merged with trunk r657726

git-svn-id: https://svn.apache.org/repos/asf/poi/tags/REL_3_1_BETA2@657731 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Yegor Kozlov 2008-05-19 06:35:30 +00:00
parent 28b6f4e2a3
commit 294932abb8
85 changed files with 3142 additions and 2822 deletions

View File

@ -55,10 +55,10 @@ public class HSSFCellUtil
*/
public static HSSFRow getRow( int rowCounter, HSSFSheet sheet )
{
HSSFRow row = sheet.getRow( (short) rowCounter );
HSSFRow row = sheet.getRow( rowCounter );
if ( row == null )
{
row = sheet.createRow( (short) rowCounter );
row = sheet.createRow( rowCounter );
}
return row;
@ -66,7 +66,8 @@ public class HSSFCellUtil
/**
* Get a specific cell from a row. If the cell doesn't exist, then create it.
* Get a specific cell from a row. If the cell doesn't exist,
* then create it.
*
*@param row The row that the cell is part of
*@param column The column index that the cell is in.
@ -74,11 +75,11 @@ public class HSSFCellUtil
*/
public static HSSFCell getCell( HSSFRow row, int column )
{
HSSFCell cell = row.getCell( (short) column );
HSSFCell cell = row.getCell( column );
if ( cell == null )
{
cell = row.createCell( (short) column );
cell = row.createCell( (short)column );
}
return cell;
}
@ -98,7 +99,7 @@ public class HSSFCellUtil
{
HSSFCell cell = getCell( row, column );
cell.setCellValue( value );
cell.setCellValue(new HSSFRichTextString(value));
if ( style != null )
{
cell.setCellStyle( style );
@ -222,7 +223,7 @@ public class HSSFCellUtil
public static HSSFCell translateUnicodeValues( HSSFCell cell )
{
String s = cell.getStringCellValue();
String s = cell.getRichStringCellValue().getString();
boolean foundUnicode = false;
for ( Iterator i = unicodeMappings.entrySet().iterator(); i.hasNext(); )

View File

@ -37,6 +37,17 @@
<!-- Don't forget to update status.xml too! -->
<release version="3.1-beta2" date="2008-05-??">
<action dev="POI-DEVELOPERS" type="fix">44306 - fixed reading/writing of AttrPtg(type=choose) and method toFormulaString() for CHOOSE formulas</action>
<action dev="POI-DEVELOPERS" type="fix">24207 - added HSSFName.isDeleted() to check if the name points to cell that no longer exists</action>
<action dev="POI-DEVELOPERS" type="fix">40414 - fixed selected/active sheet after removing sheet from workbook</action>
<action dev="POI-DEVELOPERS" type="fix">44523 - fixed workbook sheet selection and focus</action>
<action dev="POI-DEVELOPERS" type="fix">45000 - Fixed NPE in ListLevel when numberText is null</action>
<action dev="POI-DEVELOPERS" type="fix">44985 - Properly update TextSpecInfoAtom when the parent text is changed</action>
<action dev="POI-DEVELOPERS" type="fix">41187 - fixed HSSFSheet to properly read xls files without ROW records</action>
<action dev="POI-DEVELOPERS" type="fix">44950 - fixed HSSFFormulaEvaluator.evaluateInCell() and Area3DEval.getValue() also added validation for number of elements in AreaEvals</action>
<action dev="POI-DEVELOPERS" type="fix">42570 - fixed LabelRecord to use empty string instead of null when the length is zero.</action>
<action dev="POI-DEVELOPERS" type="fix">42564 - fixed ArrayPtg to use ConstantValueParser. Fixed a few other ArrayPtg encoding issues.</action>
<action dev="POI-DEVELOPERS" type="fix">Follow-on from 28754 - StringPtg.toFormulaString() should escape double quotes</action>
<action dev="POI-DEVELOPERS" type="fix">44929 - Improved error handling in HSSFWorkbook when attempting to read a BIFF5 file</action>
<action dev="POI-DEVELOPERS" type="fix">44675 - Parameter operand classes (function metadata) required to encode SUM() etc properly. Added parse validation for number of parameters</action>
<action dev="POI-DEVELOPERS" type="fix">44921 - allow Ptg.writeBytes() to be called on relative ref Ptgs (RefN* and AreaN*)</action>

View File

@ -1225,7 +1225,19 @@ Examples:
// Do something with this corner cell
}
}
</source>
</source>
<p>
Note, when a cell is deleted, Excel does not delete the attached named range.
As result, workbook can contain named ranges that point to cells that no longer exist.
You should check the validity of a reference before constructing AreaReference
</p>
<source>
if(hssfName.isDeleted()){
//named range points to a deleted cell.
} else {
AreaReference ref = new AreaReference(hssfName.getReference());
}
</source>
</section>
<anchor id="CellComments"/>
<section><title>Cell Comments</title>

View File

@ -34,6 +34,17 @@
<!-- Don't forget to update changes.xml too! -->
<changes>
<release version="3.1-beta2" date="2008-05-??">
<action dev="POI-DEVELOPERS" type="fix">44306 - fixed reading/writing of AttrPtg(type=choose) and method toFormulaString() for CHOOSE formulas</action>
<action dev="POI-DEVELOPERS" type="fix">24207 - added HSSFName.isDeleted() to check if the name points to cell that no longer exists</action>
<action dev="POI-DEVELOPERS" type="fix">40414 - fixed selected/active sheet after removing sheet from workbook</action>
<action dev="POI-DEVELOPERS" type="fix">44523 - fixed workbook sheet selection and focus</action>
<action dev="POI-DEVELOPERS" type="fix">45000 - Fixed NPE in ListLevel when numberText is null</action>
<action dev="POI-DEVELOPERS" type="fix">44985 - Properly update TextSpecInfoAtom when the parent text is changed</action>
<action dev="POI-DEVELOPERS" type="fix">41187 - fixed HSSFSheet to properly read xls files without ROW records</action>
<action dev="POI-DEVELOPERS" type="fix">44950 - fixed HSSFFormulaEvaluator.evaluateInCell() and Area3DEval.getValue() also added validation for number of elements in AreaEvals</action>
<action dev="POI-DEVELOPERS" type="fix">42570 - fixed LabelRecord to use empty string instead of null when the length is zero.</action>
<action dev="POI-DEVELOPERS" type="fix">42564 - fixed ArrayPtg to use ConstantValueParser. Fixed a few other ArrayPtg encoding issues.</action>
<action dev="POI-DEVELOPERS" type="fix">Follow-on from 28754 - StringPtg.toFormulaString() should escape double quotes</action>
<action dev="POI-DEVELOPERS" type="fix">44929 - Improved error handling in HSSFWorkbook when attempting to read a BIFF5 file</action>
<action dev="POI-DEVELOPERS" type="fix">44675 - Parameter operand classes (function metadata) required to encode SUM() etc properly. Added parse validation for number of parameters</action>
<action dev="POI-DEVELOPERS" type="fix">44921 - allow Ptg.writeBytes() to be called on relative ref Ptgs (RefN* and AreaN*)</action>

View File

@ -37,14 +37,14 @@ where $TAG is the release tag, for example, REL_3_1_BETA1
3. Checkout the tagged version
{code}
cd tags
svn checkout https://svn.apache.org/repos/asf/poi/tags/TAG
svn checkout https://svn.apache.org/repos/asf/poi/tags/$TAG
{code}
4. Merge (if required)
{code}
cd $TAG
$ svn merge https://svn.apache.org/repos/asf/poi/tags/TAG \
$ svn merge https://svn.apache.org/repos/asf/poi/tags/$TAG \
https://svn.apache.org/repos/asf/poi/trunk
{code}

View File

@ -15,22 +15,20 @@
limitations under the License.
==================================================================== */
/*
* BiffViewer.java
*
* Created on November 13, 2001, 9:23 AM
*/
package org.apache.poi.hssf.dev;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.ArrayList;
import org.apache.poi.hssf.record.*;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.util.HexDump;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
/**
* Utillity for reading in BIFF8 records and displaying data from them.
*
@ -38,38 +36,26 @@ import java.util.ArrayList;
*@author Glen Stampoultzis (glens at apache.org)
*@see #main
*/
public class BiffViewer {
String filename;
public final class BiffViewer {
private final File _inputFile;
private boolean dump;
private final PrintStream _ps;
/**
* Creates new BiffViewer
*
*@param args
*/
public BiffViewer(String[] args) {
if (args.length > 0) {
filename = args[0];
} else {
System.out.println("BIFFVIEWER REQUIRES A FILENAME***");
}
public BiffViewer(File inFile, PrintStream ps) {
_inputFile = inFile;
_ps = ps;
}
/**
* Method run starts up BiffViewer...
*/
public void run() {
try {
POIFSFileSystem fs =
new POIFSFileSystem(new FileInputStream(filename));
InputStream stream =
fs.createDocumentInputStream("Workbook");
createRecords(stream, dump);
POIFSFileSystem fs = new POIFSFileSystem(new FileInputStream(_inputFile));
InputStream stream = fs.createDocumentInputStream("Workbook");
createRecords(stream, dump, _ps);
} catch (Exception e) {
e.printStackTrace();
}
@ -86,451 +72,306 @@ public class BiffViewer {
* InputStream
*@exception RecordFormatException on error processing the InputStream
*/
public static Record[] createRecords(InputStream in, boolean dump)
public static Record[] createRecords(InputStream in, boolean dump, PrintStream ps)
throws RecordFormatException {
ArrayList records = new ArrayList();
RecordDetails activeRecord = null;
try {
BiffviewRecordInputStream recStream = new BiffviewRecordInputStream(in);
while (recStream.hasNextRecord()) {
BiffviewRecordInputStream recStream = new BiffviewRecordInputStream(in);
while (recStream.hasNextRecord()) {
recStream.nextRecord();
if (recStream.getSid() != 0) {
Record record = createRecord (recStream);
Record record = createRecord (recStream);
if (record.getSid() != ContinueRecord.sid)
{
records.add(record);
if (activeRecord != null)
activeRecord.dump();
activeRecord = new RecordDetails(recStream.getSid(), recStream.getLength(), (int)recStream.getPos(), record);
activeRecord.dump(ps);
activeRecord = new RecordDetails(recStream.getSid(), recStream.getLength(), (int)recStream.getPos(), record);
}
if (dump) {
recStream.dumpBytes();
}
recStream.dumpBytes(ps);
}
}
activeRecord.dump();
} catch (IOException e) {
throw new RecordFormatException("Error reading bytes", e);
}
}
if (activeRecord != null) {
activeRecord.dump(ps);
}
Record[] retval = new Record[records.size()];
retval = (Record[]) records.toArray(retval);
records.toArray(retval);
return retval;
}
private static void dumpNormal(Record record, int startloc, short rectype, short recsize)
{
//System.out.println("Offset 0x" + Integer.toHexString(startloc) + " (" + startloc + ")");
System.out.println( "recordid = 0x" + Integer.toHexString( rectype ) + ", size = " + recsize );
System.out.println( record.toString() );
}
/**
* Essentially a duplicate of RecordFactory. Kept seperate as not to screw
* Essentially a duplicate of RecordFactory. Kept separate as not to screw
* up non-debug operations.
*
*/
private static Record createRecord( RecordInputStream in )
{
Record retval = null;
switch ( in.getSid() )
{
case ChartRecord.sid:
retval = new ChartRecord( in );
break;
return new ChartRecord( in );
case ChartFormatRecord.sid:
retval = new ChartFormatRecord( in );
break;
return new ChartFormatRecord( in );
case SeriesRecord.sid:
retval = new SeriesRecord( in );
break;
return new SeriesRecord( in );
case BeginRecord.sid:
retval = new BeginRecord( in );
break;
return new BeginRecord( in );
case EndRecord.sid:
retval = new EndRecord( in );
break;
return new EndRecord( in );
case BOFRecord.sid:
retval = new BOFRecord( in );
break;
return new BOFRecord( in );
case InterfaceHdrRecord.sid:
retval = new InterfaceHdrRecord( in );
break;
return new InterfaceHdrRecord( in );
case MMSRecord.sid:
retval = new MMSRecord( in );
break;
return new MMSRecord( in );
case InterfaceEndRecord.sid:
retval = new InterfaceEndRecord( in );
break;
return new InterfaceEndRecord( in );
case WriteAccessRecord.sid:
retval = new WriteAccessRecord( in );
break;
return new WriteAccessRecord( in );
case CodepageRecord.sid:
retval = new CodepageRecord( in );
break;
return new CodepageRecord( in );
case DSFRecord.sid:
retval = new DSFRecord( in );
break;
return new DSFRecord( in );
case TabIdRecord.sid:
retval = new TabIdRecord( in );
break;
return new TabIdRecord( in );
case FnGroupCountRecord.sid:
retval = new FnGroupCountRecord( in );
break;
return new FnGroupCountRecord( in );
case WindowProtectRecord.sid:
retval = new WindowProtectRecord( in );
break;
return new WindowProtectRecord( in );
case ProtectRecord.sid:
retval = new ProtectRecord( in );
break;
return new ProtectRecord( in );
case PasswordRecord.sid:
retval = new PasswordRecord( in );
break;
return new PasswordRecord( in );
case ProtectionRev4Record.sid:
retval = new ProtectionRev4Record( in );
break;
return new ProtectionRev4Record( in );
case PasswordRev4Record.sid:
retval = new PasswordRev4Record( in );
break;
return new PasswordRev4Record( in );
case WindowOneRecord.sid:
retval = new WindowOneRecord( in );
break;
return new WindowOneRecord( in );
case BackupRecord.sid:
retval = new BackupRecord( in );
break;
return new BackupRecord( in );
case HideObjRecord.sid:
retval = new HideObjRecord( in );
break;
return new HideObjRecord( in );
case DateWindow1904Record.sid:
retval = new DateWindow1904Record( in );
break;
return new DateWindow1904Record( in );
case PrecisionRecord.sid:
retval = new PrecisionRecord( in );
break;
return new PrecisionRecord( in );
case RefreshAllRecord.sid:
retval = new RefreshAllRecord( in );
break;
return new RefreshAllRecord( in );
case BookBoolRecord.sid:
retval = new BookBoolRecord( in );
break;
return new BookBoolRecord( in );
case FontRecord.sid:
retval = new FontRecord( in );
break;
return new FontRecord( in );
case FormatRecord.sid:
retval = new FormatRecord( in );
break;
return new FormatRecord( in );
case ExtendedFormatRecord.sid:
retval = new ExtendedFormatRecord( in );
break;
return new ExtendedFormatRecord( in );
case StyleRecord.sid:
retval = new StyleRecord( in );
break;
return new StyleRecord( in );
case UseSelFSRecord.sid:
retval = new UseSelFSRecord( in );
break;
return new UseSelFSRecord( in );
case BoundSheetRecord.sid:
retval = new BoundSheetRecord( in );
break;
return new BoundSheetRecord( in );
case CountryRecord.sid:
retval = new CountryRecord( in );
break;
return new CountryRecord( in );
case SSTRecord.sid:
retval = new SSTRecord( in );
break;
return new SSTRecord( in );
case ExtSSTRecord.sid:
retval = new ExtSSTRecord( in );
break;
return new ExtSSTRecord( in );
case EOFRecord.sid:
retval = new EOFRecord( in );
break;
return new EOFRecord( in );
case IndexRecord.sid:
retval = new IndexRecord( in );
break;
return new IndexRecord( in );
case CalcModeRecord.sid:
retval = new CalcModeRecord( in );
break;
return new CalcModeRecord( in );
case CalcCountRecord.sid:
retval = new CalcCountRecord( in );
break;
return new CalcCountRecord( in );
case RefModeRecord.sid:
retval = new RefModeRecord( in );
break;
return new RefModeRecord( in );
case IterationRecord.sid:
retval = new IterationRecord( in );
break;
return new IterationRecord( in );
case DeltaRecord.sid:
retval = new DeltaRecord( in );
break;
return new DeltaRecord( in );
case SaveRecalcRecord.sid:
retval = new SaveRecalcRecord( in );
break;
return new SaveRecalcRecord( in );
case PrintHeadersRecord.sid:
retval = new PrintHeadersRecord( in );
break;
return new PrintHeadersRecord( in );
case PrintGridlinesRecord.sid:
retval = new PrintGridlinesRecord( in );
break;
return new PrintGridlinesRecord( in );
case GridsetRecord.sid:
retval = new GridsetRecord( in );
break;
return new GridsetRecord( in );
case DrawingGroupRecord.sid:
retval = new DrawingGroupRecord( in );
break;
return new DrawingGroupRecord( in );
case DrawingRecordForBiffViewer.sid:
retval = new DrawingRecordForBiffViewer( in );
break;
return new DrawingRecordForBiffViewer( in );
case DrawingSelectionRecord.sid:
retval = new DrawingSelectionRecord( in );
break;
return new DrawingSelectionRecord( in );
case GutsRecord.sid:
retval = new GutsRecord( in );
break;
return new GutsRecord( in );
case DefaultRowHeightRecord.sid:
retval = new DefaultRowHeightRecord( in );
break;
return new DefaultRowHeightRecord( in );
case WSBoolRecord.sid:
retval = new WSBoolRecord( in );
break;
return new WSBoolRecord( in );
case HeaderRecord.sid:
retval = new HeaderRecord( in );
break;
return new HeaderRecord( in );
case FooterRecord.sid:
retval = new FooterRecord( in );
break;
return new FooterRecord( in );
case HCenterRecord.sid:
retval = new HCenterRecord( in );
break;
return new HCenterRecord( in );
case VCenterRecord.sid:
retval = new VCenterRecord( in );
break;
return new VCenterRecord( in );
case PrintSetupRecord.sid:
retval = new PrintSetupRecord( in );
break;
return new PrintSetupRecord( in );
case DefaultColWidthRecord.sid:
retval = new DefaultColWidthRecord( in );
break;
return new DefaultColWidthRecord( in );
case DimensionsRecord.sid:
retval = new DimensionsRecord( in );
break;
return new DimensionsRecord( in );
case RowRecord.sid:
retval = new RowRecord( in );
break;
return new RowRecord( in );
case LabelSSTRecord.sid:
retval = new LabelSSTRecord( in );
break;
return new LabelSSTRecord( in );
case RKRecord.sid:
retval = new RKRecord( in );
break;
return new RKRecord( in );
case NumberRecord.sid:
retval = new NumberRecord( in );
break;
return new NumberRecord( in );
case DBCellRecord.sid:
retval = new DBCellRecord( in );
break;
return new DBCellRecord( in );
case WindowTwoRecord.sid:
retval = new WindowTwoRecord( in );
break;
return new WindowTwoRecord( in );
case SelectionRecord.sid:
retval = new SelectionRecord( in );
break;
return new SelectionRecord( in );
case ContinueRecord.sid:
retval = new ContinueRecord( in );
break;
return new ContinueRecord( in );
case LabelRecord.sid:
retval = new LabelRecord( in );
break;
return new LabelRecord( in );
case MulRKRecord.sid:
retval = new MulRKRecord( in );
break;
return new MulRKRecord( in );
case MulBlankRecord.sid:
retval = new MulBlankRecord( in );
break;
return new MulBlankRecord( in );
case BlankRecord.sid:
retval = new BlankRecord( in );
break;
return new BlankRecord( in );
case BoolErrRecord.sid:
retval = new BoolErrRecord( in );
break;
return new BoolErrRecord( in );
case ColumnInfoRecord.sid:
retval = new ColumnInfoRecord( in );
break;
return new ColumnInfoRecord( in );
case MergeCellsRecord.sid:
retval = new MergeCellsRecord( in );
break;
return new MergeCellsRecord( in );
case AreaRecord.sid:
retval = new AreaRecord( in );
break;
return new AreaRecord( in );
case DataFormatRecord.sid:
retval = new DataFormatRecord( in );
break;
return new DataFormatRecord( in );
case BarRecord.sid:
retval = new BarRecord( in );
break;
return new BarRecord( in );
case DatRecord.sid:
retval = new DatRecord( in );
break;
return new DatRecord( in );
case PlotGrowthRecord.sid:
retval = new PlotGrowthRecord( in );
break;
return new PlotGrowthRecord( in );
case UnitsRecord.sid:
retval = new UnitsRecord( in );
break;
return new UnitsRecord( in );
case FrameRecord.sid:
retval = new FrameRecord( in );
break;
return new FrameRecord( in );
case ValueRangeRecord.sid:
retval = new ValueRangeRecord( in );
break;
return new ValueRangeRecord( in );
case SeriesListRecord.sid:
retval = new SeriesListRecord( in );
break;
return new SeriesListRecord( in );
case FontBasisRecord.sid:
retval = new FontBasisRecord( in );
break;
return new FontBasisRecord( in );
case FontIndexRecord.sid:
retval = new FontIndexRecord( in );
break;
return new FontIndexRecord( in );
case LineFormatRecord.sid:
retval = new LineFormatRecord( in );
break;
return new LineFormatRecord( in );
case AreaFormatRecord.sid:
retval = new AreaFormatRecord( in );
break;
return new AreaFormatRecord( in );
case LinkedDataRecord.sid:
retval = new LinkedDataRecord( in );
break;
return new LinkedDataRecord( in );
case FormulaRecord.sid:
retval = new FormulaRecord( in );
break;
return new FormulaRecord( in );
case SheetPropertiesRecord.sid:
retval = new SheetPropertiesRecord( in );
break;
return new SheetPropertiesRecord( in );
case DefaultDataLabelTextPropertiesRecord.sid:
retval = new DefaultDataLabelTextPropertiesRecord( in );
break;
return new DefaultDataLabelTextPropertiesRecord( in );
case TextRecord.sid:
retval = new TextRecord( in );
break;
return new TextRecord( in );
case AxisParentRecord.sid:
retval = new AxisParentRecord( in );
break;
return new AxisParentRecord( in );
case AxisLineFormatRecord.sid:
retval = new AxisLineFormatRecord( in );
break;
return new AxisLineFormatRecord( in );
case SupBookRecord.sid:
retval = new SupBookRecord( in );
break;
return new SupBookRecord( in );
case ExternSheetRecord.sid:
retval = new ExternSheetRecord( in );
break;
return new ExternSheetRecord( in );
case SCLRecord.sid:
retval = new SCLRecord( in );
break;
return new SCLRecord( in );
case SeriesToChartGroupRecord.sid:
retval = new SeriesToChartGroupRecord( in );
break;
return new SeriesToChartGroupRecord( in );
case AxisUsedRecord.sid:
retval = new AxisUsedRecord( in );
break;
return new AxisUsedRecord( in );
case AxisRecord.sid:
retval = new AxisRecord( in );
break;
return new AxisRecord( in );
case CategorySeriesAxisRecord.sid:
retval = new CategorySeriesAxisRecord( in );
break;
return new CategorySeriesAxisRecord( in );
case AxisOptionsRecord.sid:
retval = new AxisOptionsRecord( in );
break;
return new AxisOptionsRecord( in );
case TickRecord.sid:
retval = new TickRecord( in );
break;
return new TickRecord( in );
case SeriesTextRecord.sid:
retval = new SeriesTextRecord( in );
break;
return new SeriesTextRecord( in );
case ObjectLinkRecord.sid:
retval = new ObjectLinkRecord( in );
break;
return new ObjectLinkRecord( in );
case PlotAreaRecord.sid:
retval = new PlotAreaRecord( in );
break;
return new PlotAreaRecord( in );
case SeriesIndexRecord.sid:
retval = new SeriesIndexRecord( in );
break;
return new SeriesIndexRecord( in );
case LegendRecord.sid:
retval = new LegendRecord( in );
break;
return new LegendRecord( in );
case LeftMarginRecord.sid:
retval = new LeftMarginRecord( in );
break;
return new LeftMarginRecord( in );
case RightMarginRecord.sid:
retval = new RightMarginRecord( in );
break;
return new RightMarginRecord( in );
case TopMarginRecord.sid:
retval = new TopMarginRecord( in );
break;
return new TopMarginRecord( in );
case BottomMarginRecord.sid:
retval = new BottomMarginRecord( in );
break;
return new BottomMarginRecord( in );
case PaletteRecord.sid:
retval = new PaletteRecord( in );
break;
return new PaletteRecord( in );
case StringRecord.sid:
retval = new StringRecord( in );
break;
return new StringRecord( in );
case NameRecord.sid:
retval = new NameRecord( in );
break;
return new NameRecord( in );
case PaneRecord.sid:
retval = new PaneRecord( in );
break;
return new PaneRecord( in );
case SharedFormulaRecord.sid:
retval = new SharedFormulaRecord( in);
break;
return new SharedFormulaRecord( in);
case ObjRecord.sid:
retval = new ObjRecord( in);
break;
return new ObjRecord( in);
case TextObjectRecord.sid:
retval = new TextObjectRecord( in);
break;
return new TextObjectRecord( in);
case HorizontalPageBreakRecord.sid:
retval = new HorizontalPageBreakRecord( in);
break;
return new HorizontalPageBreakRecord( in);
case VerticalPageBreakRecord.sid:
retval = new VerticalPageBreakRecord( in);
break;
return new VerticalPageBreakRecord( in);
case WriteProtectRecord.sid:
retval = new WriteProtectRecord( in);
break;
return new WriteProtectRecord( in);
case FilePassRecord.sid:
retval = new FilePassRecord(in);
break;
return new FilePassRecord(in);
case NoteRecord.sid:
retval = new NoteRecord( in );
break;
return new NoteRecord( in );
case FileSharingRecord.sid:
retval = new FileSharingRecord( in );
break;
return new FileSharingRecord( in );
case HyperlinkRecord.sid:
retval = new HyperlinkRecord( in );
break;
default:
retval = new UnknownRecord( in );
return new HyperlinkRecord( in );
}
return retval;
return new UnknownRecord( in );
}
/**
* Method setDump - hex dump out data or not.
*
*@param dump
*/
public void setDump(boolean dump) {
this.dump = dump;
}
@ -552,33 +393,44 @@ public class BiffViewer {
*
*/
public static void main(String[] args) {
System.setProperty("poi.deserialize.escher", "true");
if (args.length == 0) {
System.out.println( "Biff viewer needs a filename" );
return;
}
try {
System.setProperty("poi.deserialize.escher", "true");
if (args.length == 0)
{
System.out.println( "Biff viewer needs a filename" );
String inFileName = args[0];
File inputFile = new File(inFileName);
if(!inputFile.exists()) {
throw new RuntimeException("specified inputFile '" + inFileName + "' does not exist");
}
else
{
BiffViewer viewer = new BiffViewer(args);
if ((args.length > 1) && args[1].equals("on")) {
viewer.setDump(true);
}
if ((args.length > 1) && args[1].equals("bfd")) {
POIFSFileSystem fs =
new POIFSFileSystem(new FileInputStream(args[0]));
InputStream stream =
fs.createDocumentInputStream("Workbook");
int size = stream.available();
byte[] data = new byte[size];
stream.read(data);
HexDump.dump(data, 0, System.out, 0);
} else {
viewer.run();
}
PrintStream ps;
if (false) { // set to true to output to file
OutputStream os = new FileOutputStream(inFileName + ".out");
ps = new PrintStream(os);
} else {
ps = System.out;
}
BiffViewer viewer = new BiffViewer(inputFile, ps);
if (args.length > 1 && args[1].equals("on")) {
viewer.setDump(true);
}
if (args.length > 1 && args[1].equals("bfd")) {
POIFSFileSystem fs = new POIFSFileSystem(new FileInputStream(inputFile));
InputStream stream = fs.createDocumentInputStream("Workbook");
int size = stream.available();
byte[] data = new byte[size];
stream.read(data);
HexDump.dump(data, 0, System.out, 0);
} else {
viewer.run();
}
ps.close();
} catch (Exception e) {
e.printStackTrace();
}
@ -587,7 +439,7 @@ public class BiffViewer {
/**
* This record supports dumping of completed continue records.
*/
static class RecordDetails
private static final class RecordDetails
{
short rectype, recsize;
int startloc;
@ -616,18 +468,19 @@ public class BiffViewer {
return record;
}
public void dump() throws IOException
{
dumpNormal(record, startloc, rectype, recsize);
public void dump(PrintStream ps) {
ps.println("Offset 0x" + Integer.toHexString(startloc) + " (" + startloc + ")");
ps.println( "recordid = 0x" + Integer.toHexString( rectype ) + ", size = " + recsize );
ps.println( record.toString() );
}
}
static class BiffviewRecordInputStream extends RecordInputStream {
private static final class BiffviewRecordInputStream extends RecordInputStream {
public BiffviewRecordInputStream(InputStream in) {
super(in);
}
public void dumpBytes() {
HexDump.dump(this.data, 0, this.currentLength);
public void dumpBytes(PrintStream ps) {
ps.println(HexDump.dump(this.data, 0, this.currentLength));
}
}

View File

@ -1000,7 +1000,7 @@ end;
if (ptg instanceof AttrPtg) {
AttrPtg attrPtg = ((AttrPtg) ptg);
if (attrPtg.isOptimizedIf()) {
if (attrPtg.isOptimizedIf() || attrPtg.isOptimizedChoose() || attrPtg.isGoto()) {
continue;
}
if (attrPtg.isSpace()) {
@ -1014,6 +1014,9 @@ end;
// similar to tAttrSpace - RPN is violated
continue;
}
if (!attrPtg.isSum()) {
throw new RuntimeException("Unexpected tAttr: " + attrPtg.toString());
}
}
final OperationPtg o = (OperationPtg) ptg;

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,3 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
@ -15,13 +14,7 @@
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
/*
* LabelRecord.java
*
* Created on November 11, 2001, 12:51 PM
*/
package org.apache.poi.hssf.record;
/**
@ -33,14 +26,10 @@ package org.apache.poi.hssf.record;
* @version 2.0-pre
* @see org.apache.poi.hssf.record.LabelSSTRecord
*/
public class LabelRecord
extends Record
implements CellValueRecordInterface
{
public final class LabelRecord extends Record implements CellValueRecordInterface {
public final static short sid = 0x204;
//private short field_1_row;
private int field_1_row;
private int field_1_row;
private short field_2_column;
private short field_3_xf_index;
private short field_4_string_len;
@ -85,35 +74,30 @@ public class LabelRecord
protected void fillFields(RecordInputStream in)
{
//field_1_row = LittleEndian.getShort(data, 0 + offset);
field_1_row = in.readUShort();
field_2_column = in.readShort();
field_3_xf_index = in.readShort();
field_4_string_len = in.readShort();
field_5_unicode_flag = in.readByte();
if (field_4_string_len > 0) {
if (isUnCompressedUnicode()) {
field_6_value = in.readUnicodeLEString(field_4_string_len);
} else {
field_6_value = in.readCompressedUnicode(field_4_string_len);
if (isUnCompressedUnicode()) {
field_6_value = in.readUnicodeLEString(field_4_string_len);
} else {
field_6_value = in.readCompressedUnicode(field_4_string_len);
}
} else {
field_6_value = "";
}
} else field_6_value = null;
}
/* READ ONLY ACCESS... THIS IS FOR COMPATIBILITY ONLY...USE LABELSST!
public void setRow(short row) {
field_1_row = row;
}
public void setColumn(short col) {
field_2_column = col;
}
public void setXFIndex(short index) {
field_3_xf_index = index;
}
*/
//public short getRow()
/*
* READ ONLY ACCESS... THIS IS FOR COMPATIBILITY ONLY...USE LABELSST! public
* void setRow(short row) { field_1_row = row; }
*
* public void setColumn(short col) { field_2_column = col; }
*
* public void setXFIndex(short index) { field_3_xf_index = index; }
*/
public int getRow()
{
return field_1_row;

View File

@ -1,4 +1,3 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
@ -15,13 +14,12 @@
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hssf.record;
import org.apache.poi.util.*;
import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndian;
/**
* Describes the frozen and unfozen panes.
@ -30,9 +28,7 @@ import org.apache.poi.util.*;
* @author Glen Stampoultzis (glens at apache.org)
*/
public class PaneRecord
extends Record
{
public final class PaneRecord extends Record {
public final static short sid = 0x41;
private short field_1_x;
private short field_2_y;
@ -42,7 +38,10 @@ public class PaneRecord
public final static short ACTIVE_PANE_LOWER_RIGHT = 0;
public final static short ACTIVE_PANE_UPPER_RIGHT = 1;
public final static short ACTIVE_PANE_LOWER_LEFT = 2;
// TODO - remove obsolete field (it was deprecated May-2008 v3.1)
/** @deprecated use ACTIVE_PANE_UPPER_LEFT */
public final static short ACTIVE_PANE_UPER_LEFT = 3;
public final static short ACTIVE_PANE_UPPER_LEFT = 3;
public PaneRecord()
@ -82,7 +81,6 @@ public class PaneRecord
field_3_topRow = in.readShort();
field_4_leftColumn = in.readShort();
field_5_activePane = in.readShort();
}
public String toString()
@ -229,7 +227,7 @@ public class PaneRecord
* ACTIVE_PANE_LOWER_RIGHT
* ACTIVE_PANE_UPPER_RIGHT
* ACTIVE_PANE_LOWER_LEFT
* ACTIVE_PANE_UPER_LEFT
* ACTIVE_PANE_UPPER_LEFT
*/
public short getActivePane()
{
@ -244,16 +242,10 @@ public class PaneRecord
* ACTIVE_PANE_LOWER_RIGHT
* ACTIVE_PANE_UPPER_RIGHT
* ACTIVE_PANE_LOWER_LEFT
* ACTIVE_PANE_UPER_LEFT
* ACTIVE_PANE_UPPER_LEFT
*/
public void setActivePane(short field_5_activePane)
{
this.field_5_activePane = field_5_activePane;
}
} // END OF CLASS
}

View File

@ -1,4 +1,3 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
@ -15,7 +14,6 @@
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hssf.record;
@ -31,20 +29,18 @@ import org.apache.poi.util.LittleEndian;
* @author Jason Height (jheight at chariot dot net dot au)
* @version 2.0-pre
*/
public class RowRecord
extends Record
implements Comparable
{
public final static short sid = 0x208;
public final class RowRecord extends Record implements Comparable {
public final static short sid = 0x208;
/** The maximum row number that excel can handle (zero bazed) ie 65536 rows is
private static final int OPTION_BITS_ALWAYS_SET = 0x0100;
private static final int DEFAULT_HEIGHT_BIT = 0x8000;
/** The maximum row number that excel can handle (zero based) ie 65536 rows is
* max number of rows.
*/
public final static int MAX_ROW_NUMBER = 65535;
//private short field_1_row_number;
private int field_1_row_number;
private int field_1_row_number;
private short field_2_first_col;
private short field_3_last_col; // plus 1
private short field_4_height;
@ -52,7 +48,8 @@ public class RowRecord
// for generated sheets.
private short field_6_reserved;
private short field_7_option_flags;
/** 16 bit options flags */
private int field_7_option_flags;
private static final BitField outlineLevel = BitFieldFactory.getInstance(0x07);
// bit 3 reserved
@ -62,8 +59,17 @@ public class RowRecord
private static final BitField formatted = BitFieldFactory.getInstance(0x80);
private short field_8_xf_index; // only if isFormatted
public RowRecord()
{
public RowRecord(int rowNumber) {
field_1_row_number = rowNumber;
field_2_first_col = -1;
field_3_last_col = -1;
field_4_height = (short)DEFAULT_HEIGHT_BIT;
field_4_height = (short)DEFAULT_HEIGHT_BIT;
field_5_optimize = ( short ) 0;
field_6_reserved = ( short ) 0;
field_7_option_flags = OPTION_BITS_ALWAYS_SET; // seems necessary for outlining
field_8_xf_index = ( short ) 0xf;
}
/**
@ -86,7 +92,6 @@ public class RowRecord
protected void fillFields(RecordInputStream in)
{
//field_1_row_number = LittleEndian.getShort(data, 0 + offset);
field_1_row_number = in.readUShort();
field_2_first_col = in.readShort();
field_3_last_col = in.readShort();
@ -156,7 +161,7 @@ public class RowRecord
public void setOptionFlags(short options)
{
field_7_option_flags = options;
field_7_option_flags = options | OPTION_BITS_ALWAYS_SET;
}
// option bitfields
@ -169,20 +174,18 @@ public class RowRecord
public void setOutlineLevel(short ol)
{
field_7_option_flags =
outlineLevel.setShortValue(field_7_option_flags, ol);
field_7_option_flags = outlineLevel.setValue(field_7_option_flags, ol);
}
/**
* set whether or not to colapse this row
* @param c - colapse or not
* set whether or not to collapse this row
* @param c - collapse or not
* @see #setOptionFlags(short)
*/
public void setColapsed(boolean c)
{
field_7_option_flags = colapsed.setShortBoolean(field_7_option_flags,
c);
field_7_option_flags = colapsed.setBoolean(field_7_option_flags, c);
}
/**
@ -193,8 +196,7 @@ public class RowRecord
public void setZeroHeight(boolean z)
{
field_7_option_flags =
zeroHeight.setShortBoolean(field_7_option_flags, z);
field_7_option_flags = zeroHeight.setBoolean(field_7_option_flags, z);
}
/**
@ -205,8 +207,7 @@ public class RowRecord
public void setBadFontHeight(boolean f)
{
field_7_option_flags =
badFontHeight.setShortBoolean(field_7_option_flags, f);
field_7_option_flags = badFontHeight.setBoolean(field_7_option_flags, f);
}
/**
@ -217,8 +218,7 @@ public class RowRecord
public void setFormatted(boolean f)
{
field_7_option_flags = formatted.setShortBoolean(field_7_option_flags,
f);
field_7_option_flags = formatted.setBoolean(field_7_option_flags, f);
}
// end bitfields
@ -293,7 +293,7 @@ public class RowRecord
public short getOptionFlags()
{
return field_7_option_flags;
return (short)field_7_option_flags;
}
// option bitfields
@ -306,7 +306,7 @@ public class RowRecord
public short getOutlineLevel()
{
return outlineLevel.getShortValue(field_7_option_flags);
return (short)outlineLevel.getValue(field_7_option_flags);
}
/**
@ -410,7 +410,6 @@ public class RowRecord
{
LittleEndian.putShort(data, 0 + offset, sid);
LittleEndian.putShort(data, 2 + offset, ( short ) 16);
//LittleEndian.putShort(data, 4 + offset, getRowNumber());
LittleEndian.putShort(data, 4 + offset, ( short ) getRowNumber());
LittleEndian.putShort(data, 6 + offset, getFirstCol() == -1 ? (short)0 : getFirstCol());
LittleEndian.putShort(data, 8 + offset, getLastCol() == -1 ? (short)0 : getLastCol());
@ -419,7 +418,6 @@ public class RowRecord
LittleEndian.putShort(data, 14 + offset, field_6_reserved);
LittleEndian.putShort(data, 16 + offset, getOptionFlags());
// LittleEndian.putShort(data,18,getOutlineLevel());
LittleEndian.putShort(data, 18 + offset, getXFIndex());
return getRecordSize();
}
@ -469,8 +467,7 @@ public class RowRecord
}
public Object clone() {
RowRecord rec = new RowRecord();
rec.field_1_row_number = field_1_row_number;
RowRecord rec = new RowRecord(field_1_row_number);
rec.field_2_first_col = field_2_first_col;
rec.field_3_last_col = field_3_last_col;
rec.field_4_height = field_4_height;

View File

@ -57,8 +57,8 @@ public class WindowOneRecord
BitFieldFactory.getInstance(0x20); // display tabs at the bottom
// all the rest are "reserved"
private short field_6_selected_tab;
private short field_7_displayed_tab;
private int field_6_active_sheet;
private int field_7_first_visible_tab;
private short field_8_num_selected_tabs;
private short field_9_tab_width_ratio;
@ -91,8 +91,8 @@ public class WindowOneRecord
field_3_width = in.readShort();
field_4_height = in.readShort();
field_5_options = in.readShort();
field_6_selected_tab = in.readShort();
field_7_displayed_tab = in.readShort();
field_6_active_sheet = in.readShort();
field_7_first_visible_tab = in.readShort();
field_8_num_selected_tabs = in.readShort();
field_9_tab_width_ratio = in.readShort();
}
@ -202,24 +202,33 @@ public class WindowOneRecord
// end bitfields
public void setActiveSheetIndex(int index) {
field_6_active_sheet = index;
}
/**
* set the selected tab number
* @param s tab number
* deprecated May 2008
* @deprecated - Misleading name - use setActiveSheetIndex()
*/
public void setSelectedTab(short s)
{
field_6_selected_tab = s;
setActiveSheetIndex(s);
}
/**
* set the displayed tab number
* @param t tab number
* Sets the first visible sheet in the worksheet tab-bar. This method does <b>not</b>
* hide, select or focus sheets. It just sets the scroll position in the tab-bar.
* @param t the sheet index of the tab that will become the first in the tab-bar
*/
public void setFirstVisibleTab(int t) {
field_7_first_visible_tab = t;
}
public void setDisplayedTab(short t)
{
field_7_displayed_tab = t;
/**
* deprecated May 2008
* @deprecated - Misleading name - use setFirstVisibleTab()
*/
public void setDisplayedTab(short t) {
setFirstVisibleTab(t);
}
/**
@ -347,24 +356,36 @@ public class WindowOneRecord
// end options bitfields
/**
* get the selected tab number
* @return Tab number
* @return the index of the currently displayed sheet
*/
public int getActiveSheetIndex() {
return field_6_active_sheet;
}
/**
* deprecated May 2008
* @deprecated - Misleading name - use getActiveSheetIndex()
*/
public short getSelectedTab()
{
return field_6_selected_tab;
return (short) getActiveSheetIndex();
}
/**
* get the displayed tab number
* @return Tab number
* @return the first visible sheet in the worksheet tab-bar.
* I.E. the scroll position of the tab-bar.
*/
public int getFirstVisibleTab() {
return field_7_first_visible_tab;
}
/**
* deprecated May 2008
* @deprecated - Misleading name - use getFirstVisibleTab()
*/
public short getDisplayedTab()
{
return field_7_displayed_tab;
return (short) getFirstVisibleTab();
}
/**
@ -412,10 +433,10 @@ public class WindowOneRecord
.append(getDisplayVerticalScrollbar()).append("\n");
buffer.append(" .tabs = ").append(getDisplayTabs())
.append("\n");
buffer.append(" .selectedtab = ")
.append(Integer.toHexString(getSelectedTab())).append("\n");
buffer.append(" .displayedtab = ")
.append(Integer.toHexString(getDisplayedTab())).append("\n");
buffer.append(" .activeSheet = ")
.append(Integer.toHexString(getActiveSheetIndex())).append("\n");
buffer.append(" .firstVisibleTab = ")
.append(Integer.toHexString(getFirstVisibleTab())).append("\n");
buffer.append(" .numselectedtabs = ")
.append(Integer.toHexString(getNumSelectedTabs())).append("\n");
buffer.append(" .tabwidthratio = ")
@ -434,8 +455,8 @@ public class WindowOneRecord
LittleEndian.putShort(data, 8 + offset, getWidth());
LittleEndian.putShort(data, 10 + offset, getHeight());
LittleEndian.putShort(data, 12 + offset, getOptions());
LittleEndian.putShort(data, 14 + offset, getSelectedTab());
LittleEndian.putShort(data, 16 + offset, getDisplayedTab());
LittleEndian.putUShort(data, 14 + offset, getActiveSheetIndex());
LittleEndian.putUShort(data, 16 + offset, getFirstVisibleTab());
LittleEndian.putShort(data, 18 + offset, getNumSelectedTabs());
LittleEndian.putShort(data, 20 + offset, getTabWidthRatio());
return getRecordSize();

View File

@ -54,7 +54,7 @@ public class WindowTwoRecord
private BitField displayGuts = BitFieldFactory.getInstance(0x80);
private BitField freezePanesNoSplit = BitFieldFactory.getInstance(0x100);
private BitField selected = BitFieldFactory.getInstance(0x200);
private BitField paged = BitFieldFactory.getInstance(0x400);
private BitField active = BitFieldFactory.getInstance(0x400);
private BitField savedInPageBreakPreview = BitFieldFactory.getInstance(0x800);
// 4-7 reserved
@ -222,12 +222,16 @@ public class WindowTwoRecord
* is the sheet currently displayed in the window
* @param p displayed or not
*/
public void setPaged(boolean p)
{
field_1_options = paged.setShortBoolean(field_1_options, p);
public void setActive(boolean p) {
field_1_options = active.setShortBoolean(field_1_options, p);
}
/**
* deprecated May 2008
* @deprecated use setActive()
*/
public void setPaged(boolean p) {
setActive(p);
}
/**
* was the sheet saved in page break view
* @param p pagebreaksaved or not
@ -416,9 +420,15 @@ public class WindowTwoRecord
* @return displayed or not
*/
public boolean getPaged()
{
return paged.isSet(field_1_options);
public boolean isActive() {
return active.isSet(field_1_options);
}
/**
* deprecated May 2008
* @deprecated use isActive()
*/
public boolean getPaged() {
return isActive();
}
/**
@ -520,7 +530,7 @@ public class WindowTwoRecord
.append(getFreezePanesNoSplit()).append("\n");
buffer.append(" .selected = ").append(getSelected())
.append("\n");
buffer.append(" .paged = ").append(getPaged())
buffer.append(" .active = ").append(isActive())
.append("\n");
buffer.append(" .svdinpgbrkpv= ")
.append(getSavedInPageBreakPreview()).append("\n");

View File

@ -35,19 +35,17 @@ import java.util.TreeMap;
* @author Jason Height (jheight at chariot dot net dot au)
*/
public class RowRecordsAggregate
extends Record
{
int firstrow = -1;
int lastrow = -1;
Map records = null;
int size = 0;
public final class RowRecordsAggregate extends Record {
private int firstrow = -1;
private int lastrow = -1;
private Map records = null; // TODO - use a proper key in this map
private int size = 0;
/** Creates a new instance of ValueRecordsAggregate */
public RowRecordsAggregate()
{
records = new TreeMap();
records = new TreeMap();
}
public void insertRow(RowRecord row)
@ -74,15 +72,13 @@ public class RowRecordsAggregate
records.remove(row);
}
public RowRecord getRow(int rownum)
{
// Row must be between 0 and 65535
if(rownum < 0 || rownum > 65535) {
throw new IllegalArgumentException("The row number must be between 0 and 65535");
}
public RowRecord getRow(int rownum) {
// Row must be between 0 and 65535
if(rownum < 0 || rownum > 65535) {
throw new IllegalArgumentException("The row number must be between 0 and 65535");
}
RowRecord row = new RowRecord();
row.setRowNumber(rownum);
RowRecord row = new RowRecord(rownum);
return ( RowRecord ) records.get(row);
}
@ -333,7 +329,7 @@ public class RowRecordsAggregate
// Find the start of the group.
int startRow = findStartOfRowOutlineGroup( rowNumber );
RowRecord rowRecord = (RowRecord) getRow( startRow );
RowRecord rowRecord = getRow( startRow );
// Hide all the columns until the end of the group
int lastRow = writeHidden( rowRecord, startRow, true );
@ -358,17 +354,8 @@ public class RowRecordsAggregate
* @return RowRecord created for the passed in row number
* @see org.apache.poi.hssf.record.RowRecord
*/
public static RowRecord createRow(int row)
{
RowRecord rowrec = new RowRecord();
//rowrec.setRowNumber(( short ) row);
rowrec.setRowNumber(row);
rowrec.setHeight(( short ) 0xff);
rowrec.setOptimize(( short ) 0x0);
rowrec.setOptionFlags(( short ) 0x100); // seems necessary for outlining
rowrec.setXFIndex(( short ) 0xf);
return rowrec;
public static RowRecord createRow(int rowNumber) {
return new RowRecord(rowNumber);
}
public boolean isRowGroupCollapsed( int row )
@ -399,12 +386,12 @@ public class RowRecordsAggregate
int endIdx = findEndOfRowOutlineGroup( idx );
// expand:
// colapsed bit must be unset
// collapsed bit must be unset
// hidden bit gets unset _if_ surrounding groups are expanded you can determine
// this by looking at the hidden bit of the enclosing group. You will have
// to look at the start and the end of the current group to determine which
// is the enclosing group
// hidden bit only is altered for this outline level. ie. don't uncollapse contained groups
// hidden bit only is altered for this outline level. ie. don't un-collapse contained groups
if ( !isRowGroupHiddenByParent( idx ) )
{
for ( int i = startIdx; i <= endIdx; i++ )

View File

@ -24,9 +24,8 @@ import org.apache.poi.util.LittleEndian;
/**
* To support Constant Values (2.5.7) as required by the CRN record.
* This class should probably also be used for two dimensional arrays which are encoded by
* This class is also used for two dimensional arrays which are encoded by
* EXTERNALNAME (5.39) records and Array tokens.<p/>
* TODO - code in ArrayPtg should be merged with this code. It currently supports only 2 of the constant types
*
* @author Josh Micich
*/

View File

@ -47,18 +47,31 @@ public class ErrorConstant {
public int getErrorCode() {
return _errorCode;
}
public String getText() {
if(HSSFErrorConstants.isValidCode(_errorCode)) {
return HSSFErrorConstants.getText(_errorCode);
}
return "unknown error code (" + _errorCode + ")";
}
public static ErrorConstant valueOf(int errorCode) {
switch (errorCode) {
case HSSFErrorConstants.ERROR_NULL: return NULL;
case HSSFErrorConstants.ERROR_DIV_0: return DIV_0;
case HSSFErrorConstants.ERROR_VALUE: return VALUE;
case HSSFErrorConstants.ERROR_REF: return REF;
case HSSFErrorConstants.ERROR_NAME: return NAME;
case HSSFErrorConstants.ERROR_NUM: return NUM;
case HSSFErrorConstants.ERROR_NA: return NA;
case HSSFErrorConstants.ERROR_NULL: return NULL;
case HSSFErrorConstants.ERROR_DIV_0: return DIV_0;
case HSSFErrorConstants.ERROR_VALUE: return VALUE;
case HSSFErrorConstants.ERROR_REF: return REF;
case HSSFErrorConstants.ERROR_NAME: return NAME;
case HSSFErrorConstants.ERROR_NUM: return NUM;
case HSSFErrorConstants.ERROR_NA: return NA;
}
System.err.println("Warning - unexpected error code (" + errorCode + ")");
return new ErrorConstant(errorCode);
}
public String toString() {
StringBuffer sb = new StringBuffer(64);
sb.append(getClass().getName()).append(" [");
sb.append(getText());
sb.append("]");
return sb.toString();
}
}

View File

@ -17,22 +17,17 @@
package org.apache.poi.hssf.record.formula;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.BitField;
import org.apache.poi.util.BitFieldFactory;
import org.apache.poi.util.StringUtil;
import org.apache.poi.hssf.util.CellReference;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.record.RecordFormatException;
import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.hssf.record.SSTRecord;
import org.apache.poi.hssf.record.UnicodeString;
import org.apache.poi.hssf.record.constant.ConstantValueParser;
import org.apache.poi.hssf.record.constant.ErrorConstant;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.util.LittleEndian;
/**
* ArrayPtg - handles arrays
*
* The ArrayPtg is a little wierd, the size of the Ptg when parsing initially only
* The ArrayPtg is a little weird, the size of the Ptg when parsing initially only
* includes the Ptg sid and the reserved bytes. The next Ptg in the expression then follows.
* It is only after the "size" of all the Ptgs is met, that the ArrayPtg data is actually
* held after this. So Ptg.createParsedExpression keeps track of the number of
@ -40,209 +35,160 @@ import org.apache.poi.hssf.record.UnicodeString;
*
* @author Jason Height (jheight at chariot dot net dot au)
*/
public class ArrayPtg extends Ptg {
public static final byte sid = 0x20;
public class ArrayPtg extends Ptg
{
public final static byte sid = 0x20;
protected byte field_1_reserved;
protected byte field_2_reserved;
protected byte field_3_reserved;
protected byte field_4_reserved;
protected byte field_5_reserved;
protected byte field_6_reserved;
protected byte field_7_reserved;
protected short token_1_columns;
protected short token_2_rows;
protected Object[][] token_3_arrayValues;
private static final int RESERVED_FIELD_LEN = 7;
// TODO - fix up field visibility and subclasses
protected byte[] field_1_reserved;
// data from these fields comes after the Ptg data of all tokens in current formula
protected short token_1_columns;
protected short token_2_rows;
protected Object[] token_3_arrayValues;
protected ArrayPtg() {
//Required for clone methods
}
protected ArrayPtg() {
//Required for clone methods
}
public ArrayPtg(RecordInputStream in)
{
field_1_reserved = in.readByte();
field_2_reserved = in.readByte();
field_3_reserved = in.readByte();
field_4_reserved = in.readByte();
field_5_reserved = in.readByte();
field_6_reserved = in.readByte();
field_7_reserved = in.readByte();
}
/**
* Read in the actual token (array) values. This occurs
* AFTER the last Ptg in the expression.
* See page 304-305 of Excel97-2007BinaryFileFormat(xls)Specification.pdf
*/
public void readTokenValues(RecordInputStream in) {
token_1_columns = (short)(0x00ff & in.readByte());
token_2_rows = in.readShort();
//The token_1_columns and token_2_rows do not follow the documentation.
//The number of physical rows and columns is actually +1 of these values.
//Which is not explicitly documented.
token_1_columns++;
token_2_rows++;
token_3_arrayValues = new Object[token_1_columns][token_2_rows];
for (int x=0;x<token_1_columns;x++) {
for (int y=0;y<token_2_rows;y++) {
byte grbit = in.readByte();
if (grbit == 0x01) {
token_3_arrayValues[x][y] = new Double(in.readDouble());
} else if (grbit == 0x02) {
//Ignore the doco, it is actually a unicode string with all the
//trimmings ie 16 bit size, option byte etc
token_3_arrayValues[x][y] = in.readUnicodeString();
} else throw new RecordFormatException("Unknown grbit '"+grbit+"' at " + x + "," + y + " with " + in.remaining() + " bytes left");
public ArrayPtg(RecordInputStream in)
{
field_1_reserved = new byte[RESERVED_FIELD_LEN];
// TODO - add readFully method to RecordInputStream
for(int i=0; i< RESERVED_FIELD_LEN; i++) {
field_1_reserved[i] = in.readByte();
}
}
/**
* Read in the actual token (array) values. This occurs
* AFTER the last Ptg in the expression.
* See page 304-305 of Excel97-2007BinaryFileFormat(xls)Specification.pdf
*/
public void readTokenValues(RecordInputStream in) {
short nColumns = in.readUByte();
short nRows = in.readShort();
//The token_1_columns and token_2_rows do not follow the documentation.
//The number of physical rows and columns is actually +1 of these values.
//Which is not explicitly documented.
nColumns++;
nRows++;
token_1_columns = nColumns;
token_2_rows = nRows;
int totalCount = nRows * nColumns;
token_3_arrayValues = ConstantValueParser.parse(in, totalCount);
}
public String toString()
{
StringBuffer buffer = new StringBuffer("[ArrayPtg]\n");
buffer.append("columns = ").append(getColumnCount()).append("\n");
buffer.append("rows = ").append(getRowCount()).append("\n");
for (int x=0;x<getColumnCount();x++) {
for (int y=0;y<getRowCount();y++) {
Object o = token_3_arrayValues[getValueIndex(x, y)];
buffer.append("[").append(x).append("][").append(y).append("] = ").append(o).append("\n");
}
}
}
}
return buffer.toString();
}
public String toString()
{
StringBuffer buffer = new StringBuffer("[ArrayPtg]\n");
/* package */ int getValueIndex(int colIx, int rowIx) {
if(colIx < 0 || colIx >= token_1_columns) {
throw new IllegalArgumentException("Specified colIx (" + colIx
+ ") is outside the allowed range (0.." + (token_1_columns-1) + ")");
}
if(rowIx < 0 || rowIx >= token_2_rows) {
throw new IllegalArgumentException("Specified rowIx (" + rowIx
+ ") is outside the allowed range (0.." + (token_2_rows-1) + ")");
}
return rowIx * token_1_columns + colIx;
}
buffer.append("columns = ").append(getColumnCount()).append("\n");
buffer.append("rows = ").append(getRowCount()).append("\n");
for (int x=0;x<getColumnCount();x++) {
for (int y=0;y<getRowCount();y++) {
Object o = token_3_arrayValues[x][y];
buffer.append("[").append(x).append("][").append(y).append("] = ").append(o).append("\n");
}
}
return buffer.toString();
}
public void writeBytes(byte[] data, int offset) {
LittleEndian.putByte(data, offset + 0, sid + ptgClass);
System.arraycopy(field_1_reserved, 0, data, offset+1, RESERVED_FIELD_LEN);
}
public void writeBytes(byte [] array, int offset)
{
array[offset++] = (byte) (sid + ptgClass);
array[offset++] = field_1_reserved;
array[offset++] = field_2_reserved;
array[offset++] = field_3_reserved;
array[offset++] = field_4_reserved;
array[offset++] = field_5_reserved;
array[offset++] = field_6_reserved;
array[offset++] = field_7_reserved;
}
public int writeTokenValueBytes(byte [] array, int offset) {
int pos = 0;
array[pos + offset] = (byte)(token_1_columns-1);
pos++;
LittleEndian.putShort(array, pos+offset, (short)(token_2_rows-1));
pos += 2;
for (int x=0;x<getColumnCount();x++) {
for (int y=0;y<getRowCount();y++) {
Object o = token_3_arrayValues[x][y];
if (o instanceof Double) {
array[pos+offset] = 0x01;
pos++;
LittleEndian.putDouble(array, pos+offset, ((Double)o).doubleValue());
pos+=8;
} else if (o instanceof UnicodeString) {
array[pos+offset] = 0x02;
pos++;
UnicodeString s = (UnicodeString)o;
//JMH TBD Handle string continuation. Id do it now but its 4am.
UnicodeString.UnicodeRecordStats stats = new UnicodeString.UnicodeRecordStats();
s.serialize(stats, pos + offset, array);
pos += stats.recordSize;
} else throw new RuntimeException("Coding error");
}
}
return pos;
}
public int writeTokenValueBytes(byte[] data, int offset) {
public void setRowCount(short row)
{
token_2_rows = row;
}
LittleEndian.putByte(data, offset + 0, token_1_columns-1);
LittleEndian.putShort(data, offset + 1, (short)(token_2_rows-1));
ConstantValueParser.encode(data, offset + 3, token_3_arrayValues);
return 3 + ConstantValueParser.getEncodedSize(token_3_arrayValues);
}
public short getRowCount()
{
return token_2_rows;
}
public short getRowCount() {
return token_2_rows;
}
public void setColumnCount(short col)
{
token_1_columns = (byte)col;
}
public short getColumnCount() {
return token_1_columns;
}
public short getColumnCount()
{
return token_1_columns;
}
/** This size includes the size of the array Ptg plus the Array Ptg Token value size*/
public int getSize()
{
int size = 1+7+1+2;
size += ConstantValueParser.getEncodedSize(token_3_arrayValues);
return size;
}
/** This size includes the size of the array Ptg plus the Array Ptg Token value size*/
public int getSize()
{
int size = 1+7+1+2;
for (int x=0;x<getColumnCount();x++) {
for (int y=0;y<getRowCount();y++) {
Object o = token_3_arrayValues[x][y];
if (o instanceof UnicodeString) {
size++;
UnicodeString.UnicodeRecordStats rs = new UnicodeString.UnicodeRecordStats();
((UnicodeString)o).getRecordSize(rs);
size += rs.recordSize;
} else if (o instanceof Double) {
size += 9;
}
}
}
return size;
}
public String toFormulaString(HSSFWorkbook book)
{
StringBuffer b = new StringBuffer();
b.append("{");
for (int x=0;x<getColumnCount();x++) {
if (x > 0) {
b.append(";");
}
for (int y=0;y<getRowCount();y++) {
if (y > 0) {
b.append(",");
}
Object o = token_3_arrayValues[getValueIndex(x, y)];
b.append(getConstantText(o));
}
}
b.append("}");
return b.toString();
}
private static String getConstantText(Object o) {
public String toFormulaString(HSSFWorkbook book)
{
StringBuffer b = new StringBuffer();
b.append("{");
for (int x=0;x<getColumnCount();x++) {
for (int y=0;y<getRowCount();y++) {
Object o = token_3_arrayValues[x][y];
if (o instanceof String) {
b.append((String)o);
} else if (o instanceof Double) {
b.append(((Double)o).doubleValue());
}
if (y != getRowCount())
b.append(",");
}
if (x != getColumnCount())
b.append(";");
}
b.append("}");
return b.toString();
}
public byte getDefaultOperandClass() {
return Ptg.CLASS_ARRAY;
}
public Object clone() {
ArrayPtg ptg = new ArrayPtg();
ptg.field_1_reserved = field_1_reserved;
ptg.field_2_reserved = field_2_reserved;
ptg.field_3_reserved = field_3_reserved;
ptg.field_4_reserved = field_4_reserved;
ptg.field_5_reserved = field_5_reserved;
ptg.field_6_reserved = field_6_reserved;
ptg.field_7_reserved = field_7_reserved;
ptg.token_1_columns = token_1_columns;
ptg.token_2_rows = token_2_rows;
ptg.token_3_arrayValues = new Object[getColumnCount()][getRowCount()];
for (int x=0;x<getColumnCount();x++) {
for (int y=0;y<getRowCount();y++) {
ptg.token_3_arrayValues[x][y] = token_3_arrayValues[x][y];
}
}
ptg.setClass(ptgClass);
return ptg;
}
if (o == null) {
return ""; // TODO - how is 'empty value' represented in formulas?
}
if (o instanceof UnicodeString) {
return "\"" + ((UnicodeString)o).getString() + "\"";
}
if (o instanceof Double) {
return ((Double)o).toString();
}
if (o instanceof Boolean) {
((Boolean)o).toString();
}
if (o instanceof ErrorConstant) {
return ((ErrorConstant)o).getText();
}
throw new IllegalArgumentException("Unexpected constant class (" + o.getClass().getName() + ")");
}
public byte getDefaultOperandClass() {
return Ptg.CLASS_ARRAY;
}
public Object clone() {
ArrayPtg ptg = new ArrayPtg();
ptg.field_1_reserved = (byte[]) field_1_reserved.clone();
ptg.token_1_columns = token_1_columns;
ptg.token_2_rows = token_2_rows;
ptg.token_3_arrayValues = (Object[]) token_3_arrayValues.clone();
ptg.setClass(ptgClass);
return ptg;
}
}

View File

@ -17,56 +17,31 @@
package org.apache.poi.hssf.record.formula;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.BitField;
import org.apache.poi.util.BitFieldFactory;
import org.apache.poi.util.StringUtil;
import org.apache.poi.hssf.util.CellReference;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.record.RecordFormatException;
import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.hssf.record.SSTRecord;
import org.apache.poi.hssf.record.UnicodeString;
/**
* ArrayPtgA - handles arrays
*
* @author Jason Height (jheight at chariot dot net dot au)
*/
public class ArrayPtgA extends ArrayPtg
{
public final class ArrayPtgA extends ArrayPtg {
public final static byte sid = 0x60;
protected ArrayPtgA() {
super();
private ArrayPtgA() {
//Required for clone methods
}
public ArrayPtgA(RecordInputStream in)
{
public ArrayPtgA(RecordInputStream in) {
super(in);
}
public Object clone() {
ArrayPtgA ptg = new ArrayPtgA();
ptg.field_1_reserved = field_1_reserved;
ptg.field_2_reserved = field_2_reserved;
ptg.field_3_reserved = field_3_reserved;
ptg.field_4_reserved = field_4_reserved;
ptg.field_5_reserved = field_5_reserved;
ptg.field_6_reserved = field_6_reserved;
ptg.field_7_reserved = field_7_reserved;
ptg.field_1_reserved = (byte[]) field_1_reserved.clone();
ptg.token_1_columns = token_1_columns;
ptg.token_2_rows = token_2_rows;
ptg.token_3_arrayValues = new Object[getColumnCount()][getRowCount()];
for (int x=0;x<getColumnCount();x++) {
for (int y=0;y<getRowCount();y++) {
ptg.token_3_arrayValues[x][y] = token_3_arrayValues[x][y];
}
}
ptg.token_3_arrayValues = (Object[]) token_3_arrayValues.clone();
ptg.setClass(ptgClass);
return ptg;
}

View File

@ -17,22 +17,12 @@
package org.apache.poi.hssf.record.formula;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.BitField;
import org.apache.poi.util.BitFieldFactory;
import org.apache.poi.util.StringUtil;
import org.apache.poi.hssf.util.CellReference;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.record.RecordFormatException;
import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.hssf.record.SSTRecord;
import org.apache.poi.hssf.record.UnicodeString;
/**
* ArrayPtg - handles arrays
*
* The ArrayPtg is a little wierd, the size of the Ptg when parsing initially only
* The ArrayPtg is a little weird, the size of the Ptg when parsing initially only
* includes the Ptg sid and the reserved bytes. The next Ptg in the expression then follows.
* It is only after the "size" of all the Ptgs is met, that the ArrayPtg data is actually
* held after this. So Ptg.createParsedExpression keeps track of the number of
@ -40,38 +30,24 @@ import org.apache.poi.hssf.record.UnicodeString;
*
* @author Jason Height (jheight at chariot dot net dot au)
*/
public class ArrayPtgV extends ArrayPtg
{
public final class ArrayPtgV extends ArrayPtg {
public final static byte sid = 0x40;
protected ArrayPtgV() {
private ArrayPtgV() {
//Required for clone methods
}
public ArrayPtgV(RecordInputStream in)
{
public ArrayPtgV(RecordInputStream in) {
super(in);
}
public Object clone() {
ArrayPtgV ptg = new ArrayPtgV();
ptg.field_1_reserved = field_1_reserved;
ptg.field_2_reserved = field_2_reserved;
ptg.field_3_reserved = field_3_reserved;
ptg.field_4_reserved = field_4_reserved;
ptg.field_5_reserved = field_5_reserved;
ptg.field_6_reserved = field_6_reserved;
ptg.field_7_reserved = field_7_reserved;
ptg.field_1_reserved = (byte[]) field_1_reserved.clone();
ptg.token_1_columns = token_1_columns;
ptg.token_2_rows = token_2_rows;
ptg.token_3_arrayValues = new Object[getColumnCount()][getRowCount()];
for (int x=0;x<getColumnCount();x++) {
for (int y=0;y<getRowCount();y++) {
ptg.token_3_arrayValues[x][y] = token_3_arrayValues[x][y];
}
}
ptg.token_3_arrayValues = (Object[]) token_3_arrayValues.clone();
ptg.setClass(ptgClass);
return ptg;
}

View File

@ -39,6 +39,11 @@ public final class AttrPtg extends OperationPtg {
private byte field_1_options;
private short field_2_data;
/** only used for tAttrChoose: table of offsets to starts of args */
private final int[] _jumpTable;
/** only used for tAttrChoose: offset to the tFuncVar for CHOOSE() */
private final int _chooseFuncOffset;
// flags 'volatile' and 'space', can be combined.
// OOO spec says other combinations are theoretically possible but not likely to occur.
private static final BitField semiVolatile = BitFieldFactory.getInstance(0x01);
@ -63,7 +68,7 @@ public final class AttrPtg extends OperationPtg {
/** 03H = Carriage returns before opening parenthesis (only allowed before tParen token) */
public static final int CR_BEFORE_OPEN_PAREN = 0x03;
/** 04H = Spaces before closing parenthesis (only allowed before tParen, tFunc, and tFuncVar tokens) */
public static final int SPACE_BEFORE_CLOSE_PAERN = 0x04;
public static final int SPACE_BEFORE_CLOSE_PAREN = 0x04;
/** 05H = Carriage returns before closing parenthesis (only allowed before tParen, tFunc, and tFuncVar tokens) */
public static final int CR_BEFORE_CLOSE_PAREN = 0x05;
/** 06H = Spaces following the equality sign (only in macro sheets) */
@ -71,16 +76,33 @@ public final class AttrPtg extends OperationPtg {
}
public AttrPtg() {
_jumpTable = null;
_chooseFuncOffset = -1;
}
public AttrPtg(RecordInputStream in)
{
field_1_options = in.readByte();
field_2_data = in.readShort();
if (isOptimizedChoose()) {
int nCases = field_2_data;
int[] jumpTable = new int[nCases];
for (int i = 0; i < jumpTable.length; i++) {
jumpTable[i] = in.readUShort();
}
_jumpTable = jumpTable;
_chooseFuncOffset = in.readUShort();
} else {
_jumpTable = null;
_chooseFuncOffset = -1;
}
}
private AttrPtg(int options, int data) {
private AttrPtg(int options, int data, int[] jt, int chooseFuncOffset) {
field_1_options = (byte) options;
field_2_data = (short) data;
_jumpTable = jt;
_chooseFuncOffset = chooseFuncOffset;
}
/**
@ -89,7 +111,7 @@ public final class AttrPtg extends OperationPtg {
*/
public static AttrPtg createSpace(int type, int count) {
int data = type & 0x00FF | (count << 8) & 0x00FFFF;
return new AttrPtg(space.set(0), data);
return new AttrPtg(space.set(0), data, null, -1);
}
public void setOptions(byte options)
@ -136,14 +158,14 @@ public final class AttrPtg extends OperationPtg {
field_1_options=optiIf.setByteBoolean(field_1_options,bif);
}
/**
* Flags this ptg as a goto/jump
* @param isGoto
*/
public void setGoto(boolean isGoto) {
field_1_options=optGoto.setByteBoolean(field_1_options, isGoto);
}
/**
* Flags this ptg as a goto/jump
* @param isGoto
*/
public void setGoto(boolean isGoto) {
field_1_options=optGoto.setByteBoolean(field_1_options, isGoto);
}
// lets hope no one uses this anymore
public boolean isBaxcel()
{
@ -181,7 +203,7 @@ public final class AttrPtg extends OperationPtg {
if(isOptimizedIf()) {
sb.append("if dist=").append(getData());
} else if(isOptimizedChoose()) {
sb.append("choose dist=").append(getData());
sb.append("choose nCases=").append(getData());
} else if(isGoto()) {
sb.append("skip dist=").append(getData());
} else if(isSum()) {
@ -195,13 +217,28 @@ public final class AttrPtg extends OperationPtg {
public void writeBytes(byte [] array, int offset)
{
array[offset]=sid;
array[offset+1]=field_1_options;
LittleEndian.putShort(array,offset+2,field_2_data);
LittleEndian.putByte(array, offset+0, sid);
LittleEndian.putByte(array, offset+1, field_1_options);
LittleEndian.putShort(array,offset+2, field_2_data);
int[] jt = _jumpTable;
if (jt != null) {
int joff = offset+4;
LittleEndian.putUShort(array, joff, _chooseFuncOffset);
joff+=2;
for (int i = 0; i < jt.length; i++) {
LittleEndian.putUShort(array, joff, jt[i]);
joff+=2;
}
LittleEndian.putUShort(array, joff, _chooseFuncOffset);
}
}
public int getSize()
{
if (_jumpTable != null) {
return SIZE + (_jumpTable.length + 1) * LittleEndian.SHORT_SIZE;
}
return SIZE;
}
@ -255,12 +292,17 @@ public final class AttrPtg extends OperationPtg {
public byte getDefaultOperandClass() {return Ptg.CLASS_VALUE;}
public byte getDefaultOperandClass() {
return Ptg.CLASS_VALUE;
}
public Object clone() {
AttrPtg ptg = new AttrPtg();
ptg.field_1_options = field_1_options;
ptg.field_2_data = field_2_data;
return ptg;
int[] jt;
if (_jumpTable == null) {
jt = null;
} else {
jt = (int[]) _jumpTable.clone();
}
return new AttrPtg(field_1_options, field_2_data, jt, _chooseFuncOffset);
}
}

View File

@ -32,18 +32,6 @@ public final class FuncPtg extends AbstractFunctionPtg {
public final static int SIZE = 3;
private int numParams=0;
/**
* FuncPtgs are defined to be 4 bytes but the actual FuncPtg uses only 2 bytes.
* If we have leftOvers that are read from the file we should serialize them back out.
* <p>
* If the leftovers are removed, a prompt "Warning: Data may have been lost occurs in Excel"
*/
//protected byte[] leftOvers = null;
private FuncPtg() {
//Required for clone methods
}
/**Creates new function pointer from a byte array
* usually called while reading an excel file.
*/
@ -75,11 +63,9 @@ public final class FuncPtg extends AbstractFunctionPtg {
}
public Object clone() {
FuncPtg ptg = new FuncPtg();
//ptg.field_1_num_args = field_1_num_args;
ptg.field_2_fnc_index = field_2_fnc_index;
ptg.setClass(ptgClass);
return ptg;
FuncPtg ptg = new FuncPtg(field_2_fnc_index);
ptg.setClass(ptgClass);
return ptg;
}
public int getSize() {

View File

@ -24,106 +24,123 @@ import org.apache.poi.util.StringUtil;
import org.apache.poi.hssf.record.RecordInputStream;
/**
* Number
* Stores a String value in a formula value stored in the format &lt;length 2 bytes&gt;char[]
* @author Werner Froidevaux
* String Stores a String value in a formula value stored in the format
* &lt;length 2 bytes&gt;char[]
*
* @author Werner Froidevaux
* @author Jason Height (jheight at chariot dot net dot au)
* @author Bernard Chesnoy
*/
public final class StringPtg extends Ptg {
public final static int SIZE = 9;
public final static byte sid = 0x17;
private static final BitField fHighByte = BitFieldFactory.getInstance(0x01);
/** the character (")used in formulas to delimit string literals */
private static final char FORMULA_DELIMITER = '"';
public class StringPtg
extends Ptg
{
public final static int SIZE = 9;
public final static byte sid = 0x17;
//NOTE: OO doc says 16bit lenght, but BiffViewer says 8
// Book says something totally different, so dont look there!
int field_1_length;
byte field_2_options;
BitField fHighByte = BitFieldFactory.getInstance(0x01);
private String field_3_string;
/**
* NOTE: OO doc says 16bit length, but BiffViewer says 8 Book says something
* totally different, so don't look there!
*/
private int field_1_length;
private byte field_2_options;
private String field_3_string;
private StringPtg() {
//Required for clone methods
// Required for clone methods
}
/** Create a StringPtg from a byte array read from disk */
public StringPtg(RecordInputStream in)
{
field_1_length = in.readByte() & 0xFF;
public StringPtg(RecordInputStream in) {
field_1_length = in.readUByte();
field_2_options = in.readByte();
if (fHighByte.isSet(field_2_options)) {
field_3_string= in.readUnicodeLEString(field_1_length);
}else {
field_3_string=in.readCompressedUnicode(field_1_length);
field_3_string = in.readUnicodeLEString(field_1_length);
} else {
field_3_string = in.readCompressedUnicode(field_1_length);
}
//setValue(new String(data, offset+3, data[offset+1] + 256*data[offset+2]));
// setValue(new String(data, offset+3, data[offset+1] + 256*data[offset+2]));
}
/** Create a StringPtg from a string representation of the number
* Number format is not checked, it is expected to be validated in the parser
* that calls this method.
* @param value : String representation of a floating point number
/**
* Create a StringPtg from a string representation of the number Number
* format is not checked, it is expected to be validated in the parser that
* calls this method.
*
* @param value :
* String representation of a floating point number
*/
public StringPtg(String value) {
if (value.length() >255) {
throw new IllegalArgumentException("String literals in formulas cant be bigger than 255 characters ASCII");
if (value.length() > 255) {
throw new IllegalArgumentException(
"String literals in formulas can't be bigger than 255 characters ASCII");
}
this.field_2_options=0;
field_2_options = (byte)this.fHighByte.setBoolean(field_2_options, StringUtil.hasMultibyte(value));
this.field_3_string=value;
this.field_1_length=value.length(); //for the moment, we support only ASCII strings in formulas we create
field_2_options = 0;
field_2_options = (byte) fHighByte.setBoolean(field_2_options, StringUtil
.hasMultibyte(value));
field_3_string = value;
field_1_length = value.length(); // for the moment, we support only ASCII strings in formulas we create
}
/*
public void setValue(String value)
{
field_1_value = value;
}*/
public String getValue()
{
public String getValue() {
return field_3_string;
}
public void writeBytes(byte [] array, int offset)
{
array[ offset + 0 ] = sid;
array[ offset + 1 ] = (byte)field_1_length;
array[ offset + 2 ] = field_2_options;
public void writeBytes(byte[] array, int offset) {
array[offset + 0] = sid;
array[offset + 1] = (byte) field_1_length;
array[offset + 2] = field_2_options;
if (fHighByte.isSet(field_2_options)) {
StringUtil.putUnicodeLE(getValue(),array,offset+3);
}else {
StringUtil.putCompressedUnicode(getValue(),array,offset+3);
}
}
public int getSize()
{
if (fHighByte.isSet(field_2_options)) {
return 2*field_1_length+3;
StringUtil.putUnicodeLE(getValue(), array, offset + 3);
} else {
return field_1_length+3;
StringUtil.putCompressedUnicode(getValue(), array, offset + 3);
}
}
public String toFormulaString(HSSFWorkbook book)
{
return "\""+getValue()+"\"";
public int getSize() {
if (fHighByte.isSet(field_2_options)) {
return 2 * field_1_length + 3;
} else {
return field_1_length + 3;
}
}
public String toFormulaString(HSSFWorkbook book) {
String value = field_3_string;
int len = value.length();
StringBuffer sb = new StringBuffer(len + 4);
sb.append(FORMULA_DELIMITER);
for (int i = 0; i < len; i++) {
char c = value.charAt(i);
if (c == FORMULA_DELIMITER) {
sb.append(FORMULA_DELIMITER);
}
sb.append(c);
}
sb.append(FORMULA_DELIMITER);
return sb.toString();
}
public byte getDefaultOperandClass() {
return Ptg.CLASS_VALUE;
}
return Ptg.CLASS_VALUE;
}
public Object clone() {
StringPtg ptg = new StringPtg();
ptg.field_1_length = field_1_length;
ptg.field_2_options=field_2_options;
ptg.field_3_string=field_3_string;
return ptg;
}
public Object clone() {
StringPtg ptg = new StringPtg();
ptg.field_1_length = field_1_length;
ptg.field_2_options = field_2_options;
ptg.field_3_string = field_3_string;
return ptg;
}
public String toString() {
StringBuffer sb = new StringBuffer(64);
sb.append(getClass().getName()).append(" [");
sb.append(field_3_string);
sb.append("]");
return sb.toString();
}
}

View File

@ -22,79 +22,11 @@ import org.apache.poi.hssf.record.formula.Ptg;
/**
* @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
*
*
*/
public final class Area2DEval implements AreaEval {
// TODO -refactor with Area3DEval
private final AreaPtg _delegate;
public final class Area2DEval extends AreaEvalBase {
private final ValueEval[] _values;
public Area2DEval(Ptg ptg, ValueEval[] values) {
if(ptg == null) {
throw new IllegalArgumentException("ptg must not be null");
}
if(values == null) {
throw new IllegalArgumentException("values must not be null");
}
for(int i=values.length-1; i>=0; i--) {
if(values[i] == null) {
throw new IllegalArgumentException("value array elements must not be null");
}
}
// TODO - check size of array vs size of AreaPtg
_delegate = (AreaPtg) ptg;
_values = values;
}
public int getFirstColumn() {
return _delegate.getFirstColumn();
}
public int getFirstRow() {
return _delegate.getFirstRow();
}
public int getLastColumn() {
return _delegate.getLastColumn();
}
public int getLastRow() {
return _delegate.getLastRow();
}
public ValueEval[] getValues() {
return _values;
}
public ValueEval getValueAt(int row, int col) {
ValueEval retval;
int index = ((row-getFirstRow())*(getLastColumn()-getFirstColumn()+1))+(col-getFirstColumn());
if (index <0 || index >= _values.length)
retval = ErrorEval.VALUE_INVALID;
else
retval = _values[index];
return retval;
}
public boolean contains(int row, int col) {
return (getFirstRow() <= row) && (getLastRow() >= row)
&& (getFirstColumn() <= col) && (getLastColumn() >= col);
}
public boolean containsRow(int row) {
return (getFirstRow() <= row) && (getLastRow() >= row);
}
public boolean containsColumn(short col) {
return (getFirstColumn() <= col) && (getLastColumn() >= col);
}
public boolean isColumn() {
return _delegate.getFirstColumn() == _delegate.getLastColumn();
}
public boolean isRow() {
return _delegate.getFirstRow() == _delegate.getLastRow();
}
}
public Area2DEval(Ptg ptg, ValueEval[] values) {
super((AreaPtg) ptg, values);
}
}

View File

@ -22,84 +22,18 @@ import org.apache.poi.hssf.record.formula.Ptg;
/**
* @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
*
*
*/
public final class Area3DEval implements AreaEval {
// TODO -refactor with Area3DEval
private final Area3DPtg _delegate;
public final class Area3DEval extends AreaEvalBase {
private final ValueEval[] _values;
private final int _externSheetIndex;
public Area3DEval(Ptg ptg, ValueEval[] values) {
if(ptg == null) {
throw new IllegalArgumentException("ptg must not be null");
}
if(values == null) {
throw new IllegalArgumentException("values must not be null");
}
for(int i=values.length-1; i>=0; i--) {
if(values[i] == null) {
throw new IllegalArgumentException("value array elements must not be null");
}
}
// TODO - check size of array vs size of AreaPtg
_values = values;
_delegate = (Area3DPtg) ptg;
}
public Area3DEval(Ptg ptg, ValueEval[] values) {
super((Area3DPtg) ptg, values);
_externSheetIndex = ((Area3DPtg) ptg).getExternSheetIndex();
}
public int getFirstColumn() {
return _delegate.getFirstColumn();
}
public int getFirstRow() {
return _delegate.getFirstRow();
}
public int getLastColumn() {
return (short) _delegate.getLastColumn();
}
public int getLastRow() {
return _delegate.getLastRow();
}
public ValueEval[] getValues() {
return _values;
}
public ValueEval getValueAt(int row, int col) {
ValueEval retval;
int index = (row-getFirstRow())*(col-getFirstColumn());
if (index <0 || index >= _values.length)
retval = ErrorEval.VALUE_INVALID;
else
retval = _values[index];
return retval;
}
public boolean contains(int row, int col) {
return (getFirstRow() <= row) && (getLastRow() >= row)
&& (getFirstColumn() <= col) && (getLastColumn() >= col);
}
public boolean containsRow(int row) {
return (getFirstRow() <= row) && (getLastRow() >= row);
}
public boolean containsColumn(short col) {
return (getFirstColumn() <= col) && (getLastColumn() >= col);
}
public boolean isColumn() {
return _delegate.getFirstColumn() == _delegate.getLastColumn();
}
public boolean isRow() {
return _delegate.getFirstRow() == _delegate.getLastRow();
}
public int getExternSheetIndex() {
return _delegate.getExternSheetIndex();
}
public int getExternSheetIndex() {
return _externSheetIndex;
}
}

View File

@ -0,0 +1,122 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.poi.hssf.record.formula.eval;
import org.apache.poi.hssf.record.formula.AreaI;
/**
* @author Josh Micich
*/
abstract class AreaEvalBase implements AreaEval {
private final int _firstColumn;
private final int _firstRow;
private final int _lastColumn;
private final int _lastRow;
private final ValueEval[] _values;
private final int _nColumns;
private final int _nRows;
protected AreaEvalBase(AreaI ptg, ValueEval[] values) {
if (values == null) {
throw new IllegalArgumentException("values must not be null");
}
_firstRow = ptg.getFirstRow();
_firstColumn = ptg.getFirstColumn();
_lastRow = ptg.getLastRow();
_lastColumn = ptg.getLastColumn();
_nColumns = _lastColumn - _firstColumn + 1;
_nRows = _lastRow - _firstRow + 1;
int expectedItemCount = _nRows * _nColumns;
if ((values.length != expectedItemCount)) {
// Note - this math may need alteration when POI starts to support full column or full row refs
throw new IllegalArgumentException("Array size should be (" + expectedItemCount
+ ") but was (" + values.length + ")");
}
for (int i = values.length - 1; i >= 0; i--) {
if (values[i] == null) {
throw new IllegalArgumentException("value array elements must not be null");
}
}
_values = values;
}
public final int getFirstColumn() {
return _firstColumn;
}
public final int getFirstRow() {
return _firstRow;
}
public final int getLastColumn() {
return _lastColumn;
}
public final int getLastRow() {
return _lastRow;
}
public final ValueEval[] getValues() {
// TODO - clone() - but some junits rely on not cloning at the moment
return _values;
}
public final ValueEval getValueAt(int row, int col) {
int rowOffsetIx = row - _firstRow;
int colOffsetIx = col - _firstColumn;
if(rowOffsetIx < 0 || rowOffsetIx >= _nRows) {
throw new IllegalArgumentException("Specified row index (" + row
+ ") is outside the allowed range (" + _firstRow + ".." + _lastRow + ")");
}
if(colOffsetIx < 0 || colOffsetIx >= _nColumns) {
throw new IllegalArgumentException("Specified column index (" + col
+ ") is outside the allowed range (" + _firstColumn + ".." + col + ")");
}
int index = rowOffsetIx * _nColumns + colOffsetIx;
return _values[index];
}
public final boolean contains(int row, int col) {
return _firstRow <= row && _lastRow >= row
&& _firstColumn <= col && _lastColumn >= col;
}
public final boolean containsRow(int row) {
return (_firstRow <= row) && (_lastRow >= row);
}
public final boolean containsColumn(short col) {
return (_firstColumn <= col) && (_lastColumn >= col);
}
public final boolean isColumn() {
return _firstColumn == _lastColumn;
}
public final boolean isRow() {
return _firstRow == _lastRow;
}
}

View File

@ -21,6 +21,7 @@ import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
@ -36,15 +37,14 @@ import org.apache.poi.hssf.record.formula.Ptg;
final class FunctionMetadataReader {
private static final String METADATA_FILE_NAME = "functionMetadata.txt";
/** plain ASCII text metadata file uses three dots for ellipsis */
private static final String ELLIPSIS = "...";
private static final Pattern TAB_DELIM_PATTERN = Pattern.compile("\t");
private static final Pattern SPACE_DELIM_PATTERN = Pattern.compile(" ");
private static final byte[] EMPTY_BYTE_ARRAY = { };
// special characters from the ooo document
private static final int CHAR_ELLIPSIS_8230 = 8230;
private static final int CHAR_NDASH_8211 = 8211;
private static final String[] DIGIT_ENDING_FUNCTION_NAMES = {
// Digits at the end of a function might be due to a left-over footnote marker.
// except in these cases
@ -58,7 +58,12 @@ final class FunctionMetadataReader {
throw new RuntimeException("resource '" + METADATA_FILE_NAME + "' not found");
}
BufferedReader br = new BufferedReader(new InputStreamReader(is));
BufferedReader br;
try {
br = new BufferedReader(new InputStreamReader(is,"UTF-8"));
} catch(UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
FunctionDataBuilder fdb = new FunctionDataBuilder(400);
try {
@ -123,7 +128,9 @@ final class FunctionMetadataReader {
}
String[] array = SPACE_DELIM_PATTERN.split(codes);
int nItems = array.length;
if(array[nItems-1].charAt(0) == CHAR_ELLIPSIS_8230) {
if(ELLIPSIS.equals(array[nItems-1])) {
// final ellipsis is optional, and ignored
// (all unspecified params are assumed to be the same as the last)
nItems --;
}
byte[] result = new byte[nItems];
@ -137,7 +144,6 @@ final class FunctionMetadataReader {
if(codes.length() == 1) {
switch (codes.charAt(0)) {
case '-':
case CHAR_NDASH_8211: // this is what the ooo doc has
return true;
}
}
@ -153,7 +159,7 @@ final class FunctionMetadataReader {
case 'R': return Ptg.CLASS_REF;
case 'A': return Ptg.CLASS_ARRAY;
}
throw new IllegalArgumentException("Unexpected operand type code '" + code + "'");
throw new IllegalArgumentException("Unexpected operand type code '" + code + "' (" + (int)code.charAt(0) + ")");
}
/**

View File

@ -817,8 +817,7 @@ public class HSSFCell
int row=record.getRow();
short col=record.getColumn();
short styleIndex=record.getXFIndex();
if ((cellType != CELL_TYPE_ERROR) && (cellType != CELL_TYPE_FORMULA))
{
if (cellType != CELL_TYPE_ERROR) {
setCellType(CELL_TYPE_ERROR, false, row, col, styleIndex);
}
(( BoolErrRecord ) record).setValue(value);

View File

@ -232,8 +232,7 @@ public class HSSFFormulaEvaluator {
cell.setCellValue(cv.getBooleanValue());
break;
case HSSFCell.CELL_TYPE_ERROR:
cell.setCellType(HSSFCell.CELL_TYPE_ERROR);
cell.setCellValue(cv.getErrorValue());
cell.setCellErrorValue(cv.getErrorValue());
break;
case HSSFCell.CELL_TYPE_NUMERIC:
cell.setCellType(HSSFCell.CELL_TYPE_NUMERIC);

View File

@ -139,4 +139,13 @@ public class HSSFName {
}
/**
* Tests if this name points to a cell that no longer exists
*
* @return true if the name refers to a deleted cell, false otherwise
*/
public boolean isDeleted(){
String ref = getReference();
return "#REF!".endsWith(ref);
}
}

View File

@ -21,7 +21,6 @@ import java.util.Iterator;
import java.util.NoSuchElementException;
import org.apache.poi.hssf.model.Sheet;
import org.apache.poi.hssf.model.Workbook;
import org.apache.poi.hssf.record.CellValueRecordInterface;
import org.apache.poi.hssf.record.RowRecord;
@ -37,11 +36,9 @@ public final class HSSFRow implements Comparable {
// used for collections
public final static int INITIAL_CAPACITY = 5;
//private short rowNum;
private int rowNum;
private HSSFCell[] cells=new HSSFCell[INITIAL_CAPACITY];
// private short firstcell = -1;
// private short lastcell = -1;
/**
* reference to low level representation
@ -61,7 +58,8 @@ public final class HSSFRow implements Comparable {
private Sheet sheet;
protected HSSFRow()
// TODO - ditch this constructor
HSSFRow()
{
}
@ -73,18 +71,12 @@ public final class HSSFRow implements Comparable {
* @param rowNum the row number of this row (0 based)
* @see org.apache.poi.hssf.usermodel.HSSFSheet#createRow(int)
*/
//protected HSSFRow(Workbook book, Sheet sheet, short rowNum)
protected HSSFRow(HSSFWorkbook book, Sheet sheet, int rowNum)
HSSFRow(HSSFWorkbook book, Sheet sheet, int rowNum)
{
this.rowNum = rowNum;
this.book = book;
this.sheet = sheet;
row = new RowRecord();
row.setOptionFlags( (short)0x100 ); // seems necessary for outlining to work.
row.setHeight((short) 0xff);
row.setLastCol((short) -1);
row.setFirstCol((short) -1);
row = new RowRecord(rowNum);
setRowNum(rowNum);
}
@ -98,8 +90,7 @@ public final class HSSFRow implements Comparable {
* @param record the low level api object this row should represent
* @see org.apache.poi.hssf.usermodel.HSSFSheet#createRow(int)
*/
protected HSSFRow(HSSFWorkbook book, Sheet sheet, RowRecord record)
HSSFRow(HSSFWorkbook book, Sheet sheet, RowRecord record)
{
this.book = book;
this.sheet = sheet;
@ -200,12 +191,11 @@ public final class HSSFRow implements Comparable {
* @param rowNum the row number (0-based)
* @throws IndexOutOfBoundsException if the row number is not within the range 0-65535.
*/
//public void setRowNum(short rowNum)
public void setRowNum(int rowNum)
{
if ((rowNum < 0) || (rowNum > RowRecord.MAX_ROW_NUMBER))
throw new IndexOutOfBoundsException("Row number must be between 0 and "+RowRecord.MAX_ROW_NUMBER+", was <"+rowNum+">");
public void setRowNum(int rowNum) {
if ((rowNum < 0) || (rowNum > RowRecord.MAX_ROW_NUMBER)) {
throw new IllegalArgumentException("Invalid row number (" + rowNum
+ ") outside allowable range (0.." + RowRecord.MAX_ROW_NUMBER + ")");
}
this.rowNum = rowNum;
if (row != null)
{
@ -217,8 +207,6 @@ public final class HSSFRow implements Comparable {
* get row number this row represents
* @return the row number (0 based)
*/
//public short getRowNum()
public int getRowNum()
{
return rowNum;
@ -479,8 +467,10 @@ public final class HSSFRow implements Comparable {
}
/**
* @return cell iterator of the physically defined cells. Note element 4 may
* actually be row cell depending on how many are defined!
* @return cell iterator of the physically defined cells.
* Note that the 4th element might well not be cell 4, as the iterator
* will not return un-defined (null) cells.
* Call getCellNum() on the returned cells to know which cell they are.
*/
public Iterator cellIterator()
{

View File

@ -136,6 +136,7 @@ public final class HSSFSheet {
{
int sloc = sheet.getLoc();
RowRecord row = sheet.getNextRow();
boolean rowRecordsAlreadyPresent = row!=null;
while (row != null)
{
@ -160,6 +161,18 @@ public final class HSSFSheet {
if ( ( lastrow == null ) || ( lastrow.getRowNum() != cval.getRow() ) )
{
hrow = getRow( cval.getRow() );
if (hrow == null) {
// Some tools (like Perl module Spreadsheet::WriteExcel - bug 41187) skip the RowRecords
// Excel, OpenOffice.org and GoogleDocs are all OK with this, so POI should be too.
if (rowRecordsAlreadyPresent) {
// if at least one row record is present, all should be present.
throw new RuntimeException("Unexpected missing row when some rows already present");
}
// create the row record on the fly now.
RowRecord rowRec = new RowRecord(cval.getRow());
sheet.addRow(rowRec);
hrow = createRowFromRecord(rowRec);
}
}
if ( hrow != null )
{
@ -699,6 +712,7 @@ public final class HSSFSheet {
/**
* @return an iterator of the PHYSICAL rows. Meaning the 3rd element may not
* be the third row if say for instance the second row is undefined.
* Call getRowNum() on each row if you care which one it is.
*/
public Iterator rowIterator()
{
@ -963,13 +977,34 @@ public final class HSSFSheet {
return new HSSFFooter( getSheet().getFooter() );
}
/**
* Note - this is not the same as whether the sheet is focused (isActive)
* @return <code>true</code> if this sheet is currently selected
*/
public boolean isSelected() {
return getSheet().getWindowTwo().getSelected();
}
/**
* Sets whether sheet is selected.
* @param sel Whether to select the sheet or deselect the sheet.
*/
public void setSelected( boolean sel )
{
getSheet().setSelected( sel );
getSheet().getWindowTwo().setSelected(sel);
}
/**
* @return <code>true</code> if this sheet is currently focused
*/
public boolean isActive() {
return getSheet().getWindowTwo().isActive();
}
/**
* Sets whether sheet is selected.
* @param sel Whether to select the sheet or deselect the sheet.
*/
public void setActive(boolean sel )
{
getSheet().getWindowTwo().setActive(sel);
}
/**
@ -1671,6 +1706,23 @@ public final class HSSFSheet {
* @param column the column index
*/
public void autoSizeColumn(short column) {
autoSizeColumn(column, false);
}
/**
* Adjusts the column width to fit the contents.
*
* This process can be relatively slow on large sheets, so this should
* normally only be called once per column, at the end of your
* processing.
*
* You can specify whether the content of merged cells should be considered or ignored.
* Default is to ignore merged cells.
*
* @param column the column index
* @param useMergedCells whether to use the contents of merged cells when calculating the width of the column
*/
public void autoSizeColumn(short column, boolean useMergedCells) {
AttributedString str;
TextLayout layout;
/**
@ -1679,13 +1731,13 @@ public final class HSSFSheet {
* '0' looks to be a good choice.
*/
char defaultChar = '0';
/**
* This is the multiple that the font height is scaled by when determining the
* boundary of rotated text.
*/
double fontHeightMultiple = 2.0;
FontRenderContext frc = new FontRenderContext(null, true, true);
HSSFWorkbook wb = new HSSFWorkbook(book);
@ -1697,21 +1749,27 @@ public final class HSSFSheet {
int defaultCharWidth = (int)layout.getAdvance();
double width = -1;
rows:
for (Iterator it = rowIterator(); it.hasNext();) {
HSSFRow row = (HSSFRow) it.next();
HSSFCell cell = row.getCell(column);
boolean isCellInMergedRegion = false;
for (int i = 0 ; i < getNumMergedRegions() && ! isCellInMergedRegion; i++) {
isCellInMergedRegion = getMergedRegionAt(i).contains(row.getRowNum(), column);
}
if (cell == null) continue;
if (cell == null | isCellInMergedRegion) continue;
int colspan = 1;
for (int i = 0 ; i < getNumMergedRegions(); i++) {
if (getMergedRegionAt(i).contains(row.getRowNum(), column)) {
if (!useMergedCells) {
// If we're not using merged cells, skip this one and move on to the next.
continue rows;
}
cell = row.getCell(getMergedRegionAt(i).getColumnFrom());
colspan = 1+ getMergedRegionAt(i).getColumnTo() - getMergedRegionAt(i).getColumnFrom();
}
}
HSSFCellStyle style = cell.getCellStyle();
HSSFFont font = wb.getFontAt(style.getFontIndex());
//the number of spaces to indent the text in the cell
int indention = style.getIndention();
if (cell.getCellType() == HSSFCell.CELL_TYPE_STRING) {
HSSFRichTextString rt = cell.getRichStringCellValue();
@ -1744,9 +1802,9 @@ public final class HSSFSheet {
trans.concatenate(
AffineTransform.getScaleInstance(1, fontHeightMultiple)
);
width = Math.max(width, layout.getOutline(trans).getBounds().getWidth() / defaultCharWidth + indention);
width = Math.max(width, ((layout.getOutline(trans).getBounds().getWidth() / colspan) / defaultCharWidth) + cell.getCellStyle().getIndention());
} else {
width = Math.max(width, layout.getBounds().getWidth() / defaultCharWidth + indention);
width = Math.max(width, ((layout.getBounds().getWidth() / colspan) / defaultCharWidth) + cell.getCellStyle().getIndention());
}
}
} else {
@ -1789,19 +1847,19 @@ public final class HSSFSheet {
trans.concatenate(
AffineTransform.getScaleInstance(1, fontHeightMultiple)
);
width = Math.max(width, layout.getOutline(trans).getBounds().getWidth() / defaultCharWidth + indention);
width = Math.max(width, ((layout.getOutline(trans).getBounds().getWidth() / colspan) / defaultCharWidth) + cell.getCellStyle().getIndention());
} else {
width = Math.max(width, layout.getBounds().getWidth() / defaultCharWidth + indention);
width = Math.max(width, ((layout.getBounds().getWidth() / colspan) / defaultCharWidth) + cell.getCellStyle().getIndention());
}
}
}
if (width != -1) {
if (width > Short.MAX_VALUE) { //calculated width can be greater that Short.MAX_VALUE!
width = Short.MAX_VALUE;
}
sheet.setColumnWidth(column, (short) (width * 256));
}
if (width != -1) {
if (width > Short.MAX_VALUE) { //width can be bigger that Short.MAX_VALUE!
width = Short.MAX_VALUE;
}
sheet.setColumnWidth(column, (short) (width * 256));
}
}

View File

@ -140,7 +140,7 @@ public class HSSFWorkbook extends POIDocument
protected HSSFWorkbook( Workbook book )
{
super(null, null);
super(null, null);
workbook = book;
sheets = new ArrayList( INITIAL_CAPACITY );
names = new ArrayList( INITIAL_CAPACITY );
@ -365,16 +365,66 @@ public class HSSFWorkbook extends POIDocument
workbook.setSheetOrder(sheetname, pos);
}
private void validateSheetIndex(int index) {
int lastSheetIx = sheets.size() - 1;
if (index < 0 || index > lastSheetIx) {
throw new IllegalArgumentException("Sheet index ("
+ index +") is out of range (0.." + lastSheetIx + ")");
}
}
/**
* sets the tab whose data is actually seen when the sheet is opened.
* This may be different from the "selected sheet" since excel seems to
* allow you to show the data of one sheet when another is seen "selected"
* in the tabs (at the bottom).
* @see org.apache.poi.hssf.usermodel.HSSFSheet#setSelected(boolean)
* @param index
* Selects a single sheet. This may be different to
* the 'active' sheet (which is the sheet with focus).
*/
public void setSelectedTab(int index) {
validateSheetIndex(index);
int nSheets = sheets.size();
for (int i=0; i<nSheets; i++) {
getSheetAt(i).setSelected(i == index);
}
workbook.getWindowOne().setNumSelectedTabs((short)1);
}
/**
* deprecated May 2008
* @deprecated use setSelectedTab(int)
*/
public void setSelectedTab(short index) {
workbook.getWindowOne().setSelectedTab(index);
setSelectedTab((int)index);
}
public void setSelectedTabs(int[] indexes) {
for (int i = 0; i < indexes.length; i++) {
validateSheetIndex(indexes[i]);
}
int nSheets = sheets.size();
for (int i=0; i<nSheets; i++) {
boolean bSelect = false;
for (int j = 0; j < indexes.length; j++) {
if (indexes[j] == i) {
bSelect = true;
break;
}
}
getSheetAt(i).setSelected(bSelect);
}
workbook.getWindowOne().setNumSelectedTabs((short)indexes.length);
}
/**
* Convenience method to set the active sheet. The active sheet is is the sheet
* which is currently displayed when the workbook is viewed in Excel.
* 'Selected' sheet(s) is a distinct concept.
*/
public void setActiveSheet(int index) {
validateSheetIndex(index);
int nSheets = sheets.size();
for (int i=0; i<nSheets; i++) {
getSheetAt(i).setActive(i == index);
}
workbook.getWindowOne().setActiveSheetIndex(index);
}
/**
@ -384,25 +434,46 @@ public class HSSFWorkbook extends POIDocument
* in the tabs (at the bottom).
* @see org.apache.poi.hssf.usermodel.HSSFSheet#setSelected(boolean)
*/
public int getActiveSheetIndex() {
return workbook.getWindowOne().getActiveSheetIndex();
}
/**
* deprecated May 2008
* @deprecated - Misleading name - use getActiveSheetIndex()
*/
public short getSelectedTab() {
return workbook.getWindowOne().getSelectedTab();
return (short) getActiveSheetIndex();
}
/**
* sets the first tab that is displayed in the list of tabs
* in excel.
* @param index
*/
public void setFirstVisibleTab(int index) {
workbook.getWindowOne().setFirstVisibleTab(index);
}
/**
* deprecated May 2008
* @deprecated - Misleading name - use setFirstVisibleTab()
*/
public void setDisplayedTab(short index) {
workbook.getWindowOne().setDisplayedTab(index);
setFirstVisibleTab(index);
}
/**
* sets the first tab that is displayed in the list of tabs
* in excel.
* sets the first tab that is displayed in the list of tabs in excel.
*/
public int getFirstVisibleTab() {
return workbook.getWindowOne().getFirstVisibleTab();
}
/**
* deprecated May 2008
* @deprecated - Misleading name - use getFirstVisibleTab()
*/
public short getDisplayedTab() {
return workbook.getWindowOne().getDisplayedTab();
return (short) getFirstVisibleTab();
}
/**
@ -563,17 +634,13 @@ public class HSSFWorkbook extends POIDocument
public HSSFSheet createSheet()
{
// if (getNumberOfSheets() == 3)
// throw new RuntimeException("You cannot have more than three sheets in HSSF 1.0");
HSSFSheet sheet = new HSSFSheet(this);
sheets.add(sheet);
workbook.setSheetName(sheets.size() - 1,
"Sheet" + (sheets.size() - 1));
WindowTwoRecord windowTwo = (WindowTwoRecord) sheet.getSheet().findFirstRecordBySid(WindowTwoRecord.sid);
windowTwo.setSelected(sheets.size() == 1);
windowTwo.setPaged(sheets.size() == 1);
workbook.setSheetName(sheets.size() - 1, "Sheet" + (sheets.size() - 1));
boolean isOnlySheet = sheets.size() == 1;
sheet.setSelected(isOnlySheet);
sheet.setActive(isOnlySheet);
return sheet;
}
@ -584,23 +651,24 @@ public class HSSFWorkbook extends POIDocument
*/
public HSSFSheet cloneSheet(int sheetNum) {
HSSFSheet srcSheet = (HSSFSheet)sheets.get(sheetNum);
String srcName = workbook.getSheetName(sheetNum);
if (srcSheet != null) {
validateSheetIndex(sheetNum);
HSSFSheet srcSheet = (HSSFSheet) sheets.get(sheetNum);
String srcName = workbook.getSheetName(sheetNum);
HSSFSheet clonedSheet = srcSheet.cloneSheet(this);
WindowTwoRecord windowTwo = (WindowTwoRecord) clonedSheet.getSheet().findFirstRecordBySid(WindowTwoRecord.sid);
windowTwo.setSelected(sheets.size() == 1);
windowTwo.setPaged(sheets.size() == 1);
clonedSheet.setSelected(false);
clonedSheet.setActive(false);
sheets.add(clonedSheet);
int i=1;
int i = 1;
while (true) {
//Try and find the next sheet name that is unique
// Try and find the next sheet name that is unique
String name = srcName;
String index = Integer.toString(i++);
if (name.length()+index.length()+2<31)
name = name + "("+index+")";
else name = name.substring(0, 31-index.length()-2)+"("+index+")";
if (name.length() + index.length() + 2 < 31) {
name = name + "(" + index + ")";
} else {
name = name.substring(0, 31 - index.length() - 2) + "(" + index + ")";
}
//If the sheet name is unique, then set it otherwise move on to the next number.
if (workbook.getSheetIndex(name) == -1) {
@ -609,18 +677,18 @@ public class HSSFWorkbook extends POIDocument
}
}
return clonedSheet;
}
return null;
}
/**
* create an HSSFSheet for this HSSFWorkbook, adds it to the sheets and returns
* the high level representation. Use this to create new sheets.
*
* @param sheetname sheetname to set for the sheet.
* create an HSSFSheet for this HSSFWorkbook, adds it to the sheets and
* returns the high level representation. Use this to create new sheets.
*
* @param sheetname
* sheetname to set for the sheet.
* @return HSSFSheet representing the new sheet.
* @throws IllegalArgumentException if there is already a sheet present with a case-insensitive
* match for the specified name.
* @throws IllegalArgumentException
* if there is already a sheet present with a case-insensitive
* match for the specified name.
*/
public HSSFSheet createSheet(String sheetname)
@ -632,9 +700,9 @@ public class HSSFWorkbook extends POIDocument
sheets.add(sheet);
workbook.setSheetName(sheets.size() - 1, sheetname);
WindowTwoRecord windowTwo = (WindowTwoRecord) sheet.getSheet().findFirstRecordBySid(WindowTwoRecord.sid);
windowTwo.setSelected(sheets.size() == 1);
windowTwo.setPaged(sheets.size() == 1);
boolean isOnlySheet = sheets.size() == 1;
sheet.setSelected(isOnlySheet);
sheet.setActive(isOnlySheet);
return sheet;
}
@ -686,14 +754,54 @@ public class HSSFWorkbook extends POIDocument
}
/**
* removes sheet at the given index
* Removes sheet at the given index.<p/>
*
* Care must be taken if the removed sheet is the currently active or only selected sheet in
* the workbook. There are a few situations when Excel must have a selection and/or active
* sheet. (For example when printing - see Bug 40414).<br/>
*
* This method makes sure that if the removed sheet was active, another sheet will become
* active in its place. Furthermore, if the removed sheet was the only selected sheet, another
* sheet will become selected. The newly active/selected sheet will have the same index, or
* one less if the removed sheet was the last in the workbook.
*
* @param index of the sheet (0-based)
*/
public void removeSheetAt(int index) {
validateSheetIndex(index);
boolean wasActive = getSheetAt(index).isActive();
boolean wasSelected = getSheetAt(index).isSelected();
public void removeSheetAt(int index)
{
sheets.remove(index);
workbook.removeSheet(index);
// set the remaining active/selected sheet
int nSheets = sheets.size();
if (nSheets < 1) {
// nothing more to do if there are no sheets left
return;
}
// the index of the closest remaining sheet to the one just deleted
int newSheetIndex = index;
if (newSheetIndex >= nSheets) {
newSheetIndex = nSheets-1;
}
if (wasActive) {
setActiveSheet(newSheetIndex);
}
if (wasSelected) {
boolean someOtherSheetIsStillSelected = false;
for (int i =0; i < nSheets; i++) {
if (getSheetAt(i).isSelected()) {
someOtherSheetIsStillSelected = true;
break;
}
}
if (!someOtherSheetIsStillSelected) {
setSelectedTab(newSheetIndex);
}
}
}
/**
@ -834,8 +942,7 @@ public class HSSFWorkbook extends POIDocument
HSSFPrintSetup printSetup = sheet.getPrintSetup();
printSetup.setValidSettings(false);
WindowTwoRecord w2 = (WindowTwoRecord) sheet.getSheet().findFirstRecordBySid(WindowTwoRecord.sid);
w2.setPaged(true);
sheet.setActive(true);
}
private NameRecord findExistingRowColHeaderNameRecord( int sheetIndex )

View File

@ -102,7 +102,8 @@ class BlockListImpl
catch (ArrayIndexOutOfBoundsException ignored)
{
throw new IOException("Cannot remove block[ " + index
+ " ]; out of range");
+ " ]; out of range[ 0 - " +
(_blocks.length-1) + " ]");
}
return result;
}

View File

@ -81,8 +81,9 @@ public class RawDataBlock
log.log(POILogger.ERROR,
"Unable to read entire block; " + count
+ type + " read before EOF; expected "
+ blockSize + " bytes. Your document"
+ " has probably been truncated!"
+ blockSize + " bytes. Your document "
+ "was either written by software that "
+ "ignores the spec, or has been truncated!"
);
}
else {

View File

@ -31,7 +31,7 @@
<const name="lower right" value="0"/>
<const name="upper right" value="1"/>
<const name="lower left" value="2"/>
<const name="uper left" value="3"/>
<const name="upper left" value="3"/>
</field>
</fields>
</record>

View File

@ -29,7 +29,7 @@
7 MAX 1 30 V R
8 ROW 0 1 V R
9 COLUMN 0 1 V R
10 NA 0 0 V
10 NA 0 0 V -
11 NPV 2 30 V V R
12 STDEV 1 30 V R
13 DOLLAR 1 2 V V V
@ -38,7 +38,7 @@
16 COS 1 1 V V
17 TAN 1 1 V V
18 ARCTAN 1 1 V V
19 PI 0 0 V
19 PI 0 0 V -
20 SQRT 1 1 V V
21 EXP 1 1 V V
22 LN 1 1 V V
@ -53,8 +53,8 @@
31 MID 3 3 V V V V
32 LEN 1 1 V V
33 VALUE 1 1 V V
34 TRUE 0 0 V
35 FALSE 0 0 V
34 TRUE 0 0 V -
35 FALSE 0 0 V -
36 AND 1 30 V R
37 OR 1 30 V R
38 NOT 1 1 V V
@ -80,7 +80,7 @@
60 RATE 3 6 V V V V V V V
61 MIRR 3 3 V R V V
62 IRR 1 2 V R V
63 RAND 0 0 V x
63 RAND 0 0 V - x
64 MATCH 2 3 V V R R
65 DATE 3 3 V V V V
66 TIME 3 3 V V V V
@ -91,7 +91,7 @@
71 HOUR 1 1 V V
72 MINUTE 1 1 V V
73 SECOND 1 1 V V
74 NOW 0 0 V x
74 NOW 0 0 V - x
75 AREAS 1 1 V R
76 ROWS 1 1 V R
77 COLUMNS 1 1 V R
@ -170,10 +170,10 @@
215 JIS 1 1 V V x
219 ADDRESS 2 5 V V V V V V
220 DAYS360 2 2 V V V x
221 TODAY 0 0 V x
221 TODAY 0 0 V - x
222 VDB 5 7 V V V V V V V V
227 MEDIAN 1 30 V R
228 SUMPRODUCT 1 30 V A
227 MEDIAN 1 30 V R ...
228 SUMPRODUCT 1 30 V A ...
229 SINH 1 1 V V
230 COSH 1 1 V V
231 TANH 1 1 V V
@ -188,7 +188,7 @@
247 DB 4 5 V V V V V V
252 FREQUENCY 2 2 A R R
261 ERROR.TYPE 1 1 V V
269 AVEDEV 1 30 V R
269 AVEDEV 1 30 V R ...
270 BETADIST 3 5 V V V V V V
271 GAMMALN 1 1 V V
272 BETAINV 3 5 V V V V V V
@ -237,12 +237,12 @@
315 SLOPE 2 2 V A A
316 TTEST 4 4 V A A V V
317 PROB 3 4 V A A V V
318 DEVSQ 1 30 V R
319 GEOMEAN 1 30 V R
320 HARMEAN 1 30 V R
321 SUMSQ 0 30 V R
322 KURT 1 30 V R
323 SKEW 1 30 V R
318 DEVSQ 1 30 V R ...
319 GEOMEAN 1 30 V R ...
320 HARMEAN 1 30 V R ...
321 SUMSQ 0 30 V R ...
322 KURT 1 30 V R ...
323 SKEW 1 30 V R ...
324 ZTEST 2 3 V R V V
325 LARGE 2 2 V R V
326 SMALL 2 2 V R V
@ -274,10 +274,10 @@
358 GETPIVOTDATA 2 30
359 HYPERLINK 1 2 V V V
360 PHONETIC 1 1 V R
361 AVERAGEA 1 30 V R
362 MAXA 1 30 V R
363 MINA 1 30 V R
364 STDEVPA 1 30 V R
365 VARPA 1 30 V R
366 STDEVA 1 30 V R
367 VARA 1 30 V R
361 AVERAGEA 1 30 V R ...
362 MAXA 1 30 V R ...
363 MINA 1 30 V R ...
364 STDEVPA 1 30 V R ...
365 VARPA 1 30 V R ...
366 STDEVA 1 30 V R ...
367 VARA 1 30 V R ...

View File

@ -31,7 +31,7 @@
7 MAX 1 30 V R
8 ROW 0 1 V R
9 COLUMN 0 1 V R
10 NA 0 0 V
10 NA 0 0 V -
11 NPV 2 30 V V R
12 STDEV 1 30 V R
13 DOLLAR 1 2 V V V
@ -40,7 +40,7 @@
16 COS 1 1 V V
17 TAN 1 1 V V
18 ATAN 1 1 V V
19 PI 0 0 V
19 PI 0 0 V -
20 SQRT 1 1 V V
21 EXP 1 1 V V
22 LN 1 1 V V
@ -55,8 +55,8 @@
31 MID 3 3 V V V V
32 LEN 1 1 V V
33 VALUE 1 1 V V
34 TRUE 0 0 V
35 FALSE 0 0 V
34 TRUE 0 0 V -
35 FALSE 0 0 V -
36 AND 1 30 V R
37 OR 1 30 V R
38 NOT 1 1 V V
@ -82,7 +82,7 @@
60 RATE 3 6 V V V V V V V
61 MIRR 3 3 V R V V
62 IRR 1 2 V R V
63 RAND 0 0 V x
63 RAND 0 0 V - x
64 MATCH 2 3 V V R R
65 DATE 3 3 V V V V
66 TIME 3 3 V V V V
@ -93,7 +93,7 @@
71 HOUR 1 1 V V
72 MINUTE 1 1 V V
73 SECOND 1 1 V V
74 NOW 0 0 V x
74 NOW 0 0 V - x
75 AREAS 1 1 V R
76 ROWS 1 1 V R
77 COLUMNS 1 1 V R
@ -172,10 +172,10 @@
215 JIS 1 1 V V x
219 ADDRESS 2 5 V V V V V V
220 DAYS360 2 2 V V V x
221 TODAY 0 0 V x
221 TODAY 0 0 V - x
222 VDB 5 7 V V V V V V V V
227 MEDIAN 1 30 V R
228 SUMPRODUCT 1 30 V A
227 MEDIAN 1 30 V R ...
228 SUMPRODUCT 1 30 V A ...
229 SINH 1 1 V V
230 COSH 1 1 V V
231 TANH 1 1 V V
@ -192,7 +192,7 @@
247 DB 4 5 V V V V V V
252 FREQUENCY 2 2 A R R
261 ERROR.TYPE 1 1 V V
269 AVEDEV 1 30 V R
269 AVEDEV 1 30 V R ...
270 BETADIST 3 5 V V V V V V
271 GAMMALN 1 1 V V
272 BETAINV 3 5 V V V V V V
@ -241,12 +241,12 @@
315 SLOPE 2 2 V A A
316 TTEST 4 4 V A A V V
317 PROB 3 4 V A A V V
318 DEVSQ 1 30 V R
319 GEOMEAN 1 30 V R
320 HARMEAN 1 30 V R
321 SUMSQ 0 30 V R
322 KURT 1 30 V R
323 SKEW 1 30 V R
318 DEVSQ 1 30 V R ...
319 GEOMEAN 1 30 V R ...
320 HARMEAN 1 30 V R ...
321 SUMSQ 0 30 V R ...
322 KURT 1 30 V R ...
323 SKEW 1 30 V R ...
324 ZTEST 2 3 V R V V
325 LARGE 2 2 V R V
326 SMALL 2 2 V R V
@ -278,10 +278,10 @@
358 GETPIVOTDATA 2 30
359 HYPERLINK 1 2 V V V
360 PHONETIC 1 1 V R
361 AVERAGEA 1 30 V R
362 MAXA 1 30 V R
363 MINA 1 30 V R
364 STDEVPA 1 30 V R
365 VARPA 1 30 V R
366 STDEVA 1 30 V R
367 VARA 1 30 V R
361 AVERAGEA 1 30 V R ...
362 MAXA 1 30 V R ...
363 MINA 1 30 V R ...
364 STDEVPA 1 30 V R ...
365 VARPA 1 30 V R ...
366 STDEVA 1 30 V R ...
367 VARA 1 30 V R ...

View File

@ -69,16 +69,9 @@ public class DataExtraction {
String name = ole.getInstanceName();
if ("Worksheet".equals(name)) {
//save xls on disk
FileOutputStream out = new FileOutputStream(name + "-("+(j)+").xls");
InputStream dis = data.getData();
byte[] chunk = new byte[2048];
int count;
while ((count = dis.read(chunk)) >= 0) {
out.write(chunk,0,count);
}
is.close();
out.close();
//read xls
HSSFWorkbook wb = new HSSFWorkbook(data.getData());
} else if ("Document".equals(name)) {
HWPFDocument doc = new HWPFDocument(data.getData());
//read the word document
@ -93,7 +86,15 @@ public class DataExtraction {
doc.write(out);
out.close();
} else {
System.err.println("Processing " + name);
FileOutputStream out = new FileOutputStream(ole.getProgID() + "-"+(j+1)+".dat");
InputStream dis = data.getData();
byte[] chunk = new byte[2048];
int count;
while ((count = dis.read(chunk)) >= 0) {
out.write(chunk,0,count);
}
is.close();
out.close();
}
}

View File

@ -76,6 +76,7 @@ public class ShapeFactory {
case ShapeTypes.TextBox:
shape = new TextBox(spContainer, parent);
break;
case ShapeTypes.HostControl:
case ShapeTypes.PictureFrame: {
EscherOptRecord opt = (EscherOptRecord)Shape.getEscherChild(spContainer, EscherOptRecord.RECORD_ID);
EscherProperty prop = Shape.getEscherProperty(opt, EscherProperties.BLIP__PICTUREID);

View File

@ -45,7 +45,6 @@ public class TextRun
protected TextBytesAtom _byteAtom;
protected TextCharsAtom _charAtom;
protected StyleTextPropAtom _styleAtom;
protected TextSpecInfoAtom _specAtom;
protected boolean _isUnicode;
protected RichTextRun[] _rtRuns;
private SlideShow slideShow;
@ -319,9 +318,9 @@ public class TextRun
* touch the stylings.
*/
private void storeText(String s) {
// Remove a single trailing \n, as there is an implicit one at the
// Remove a single trailing \r, as there is an implicit one at the
// end of every record
if(s.endsWith("\n")) {
if(s.endsWith("\r")) {
s = s.substring(0, s.length()-1);
}
@ -361,6 +360,18 @@ public class TextRun
_isUnicode = true;
}
}
/**
* If TextSpecInfoAtom is present, we must update the text size in it,
* otherwise the ppt will be corrupted
*/
if(_records != null) for (int i = 0; i < _records.length; i++) {
if(_records[i] instanceof TextSpecInfoAtom){
TextSpecInfoAtom specAtom = (TextSpecInfoAtom)_records[i];
if((s.length() + 1) != specAtom.getCharactersCovered()){
specAtom.reset(s.length() + 1);
}
}
}
}
/**
@ -446,7 +457,7 @@ public class TextRun
* as the the first character has.
* If you care about styling, do setText on a RichTextRun instead
*/
public synchronized void setText(String s) {
public synchronized void setRawText(String s) {
// Save the new text to the atoms
storeText(s);
RichTextRun fst = _rtRuns[0];
@ -474,20 +485,18 @@ public class TextRun
_rtRuns[0] = new RichTextRun(this,0,s.length());
}
/**
* If TextSpecInfoAtom is present, we must update the text size,
* otherwise the ppt will be corrupted
*/
if(_records != null) for (int i = 0; i < _records.length; i++) {
if(_records[i] instanceof TextSpecInfoAtom){
TextSpecInfoAtom specAtom = (TextSpecInfoAtom)_records[i];
specAtom.setTextSize(s.length());
}
}
}
/**
/**
* Changes the text.
* Converts '\r' into '\n'
*/
public synchronized void setText(String s) {
String text = normalize(s);
setRawText(text);
}
/**
* Ensure a StyleTextPropAtom is present for this run,
* by adding if required. Normally for internal TextRun use.
*/
@ -666,4 +675,12 @@ public class TextRun
return null;
}
/**
* Returns a new string with line breaks converted into internal ppt representation
*/
public String normalize(String s){
String ns = s.replaceAll("\\r?\\n", "\r");
return ns;
}
}

View File

@ -0,0 +1,95 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hslf.record;
import java.io.OutputStream;
import java.io.IOException;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.POILogger;
/**
* Container for OLE Control object. It contains:
* <p>
* 1. ExControlAtom (4091)
* 2. ExOleObjAtom (4035)
* 3. CString (4026), Instance MenuName (1) used for menus and the Links dialog box.
* 4. CString (4026), Instance ProgID (2) that stores the OLE Programmatic Identifier.
* A ProgID is a string that uniquely identifies a given object.
* 5. CString (4026), Instance ClipboardName (3) that appears in the paste special dialog.
* 6. MetaFile( 4033), optional
* </p>
*
*
* @author Yegor kozlov
*/
public class ExControl extends ExEmbed {
// Links to our more interesting children
private ExControlAtom ctrlAtom;
/**
* Set things up, and find our more interesting children
*
* @param source the source data as a byte array.
* @param start the start offset into the byte array.
* @param len the length of the slice in the byte array.
*/
protected ExControl(byte[] source, int start, int len) {
super(source, start, len);
}
/**
* Create a new ExEmbed, with blank fields
*/
public ExControl() {
super();
_children[0] = ctrlAtom = new ExControlAtom();
}
/**
* Gets the {@link ExControlAtom}.
*
* @return the {@link ExControlAtom}.
*/
public ExControlAtom getExControlAtom()
{
return ctrlAtom;
}
/**
* Returns the type (held as a little endian in bytes 3 and 4)
* that this class handles.
*
* @return the record type.
*/
public long getRecordType() {
return RecordTypes.ExControl.typeID;
}
protected RecordAtom getEmbedAtom(Record[] children){
RecordAtom atom = null;
if(_children[0] instanceof ExControlAtom) {
atom = (ExControlAtom)_children[0];
} else {
logger.log(POILogger.ERROR, "First child record wasn't a ExControlAtom, was of type " + _children[0].getRecordType());
}
return atom;
}
}

View File

@ -0,0 +1,96 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hslf.record;
import java.io.IOException;
import java.io.OutputStream;
import org.apache.poi.util.LittleEndian;
/**
* Contains a long integer, slideID, which stores the unique slide identifier of the slide
* where this control resides.
*
* @author Yegor Kozlov
*/
public class ExControlAtom extends RecordAtom {
/**
* Record header.
*/
private byte[] _header;
/**
* slideId.
*/
private int _id;
/**
* Constructs a brand new embedded object atom record.
*/
protected ExControlAtom() {
_header = new byte[8];
LittleEndian.putShort(_header, 2, (short) getRecordType());
LittleEndian.putInt(_header, 4, 4);
}
/**
* Constructs the ExControlAtom record from its source data.
*
* @param source the source data as a byte array.
* @param start the start offset into the byte array.
* @param len the length of the slice in the byte array.
*/
protected ExControlAtom(byte[] source, int start, int len) {
// Get the header.
_header = new byte[8];
System.arraycopy(source, start, _header, 0, 8);
_id = LittleEndian.getInt(source, start + 8);
}
public int getSlideId() {
return _id;
}
/**
* Gets the record type.
* @return the record type.
*/
public long getRecordType() {
return RecordTypes.ExControlAtom.typeID;
}
/**
* Write the contents of the record back, so it can be written
* to disk
*
* @param out the output stream to write to.
* @throws java.io.IOException if an error occurs.
*/
public void writeOut(OutputStream out) throws IOException {
out.write(_header);
byte[] data = new byte[4];
LittleEndian.putInt(data, _id);
out.write(data);
}
}

View File

@ -36,7 +36,7 @@ public class ExEmbed extends RecordContainer {
private byte[] _header;
// Links to our more interesting children
private ExEmbedAtom embedAtom;
private RecordAtom embedAtom;
private ExOleObjAtom oleObjAtom;
private CString menuName;
private CString progId;
@ -91,11 +91,7 @@ public class ExEmbed extends RecordContainer {
private void findInterestingChildren() {
// First child should be the ExHyperlinkAtom
if(_children[0] instanceof ExEmbedAtom) {
embedAtom = (ExEmbedAtom)_children[0];
} else {
logger.log(POILogger.ERROR, "First child record wasn't a ExEmbedAtom, was of type " + _children[0].getRecordType());
}
embedAtom = getEmbedAtom(_children);
// Second child should be the ExOleObjAtom
if (_children[1] instanceof ExOleObjAtom) {
@ -115,6 +111,16 @@ public class ExEmbed extends RecordContainer {
}
}
protected RecordAtom getEmbedAtom(Record[] children){
RecordAtom atom = null;
if(_children[0] instanceof ExEmbedAtom) {
atom = (ExEmbedAtom)_children[0];
} else {
logger.log(POILogger.ERROR, "First child record wasn't a ExEmbedAtom, was of type " + _children[0].getRecordType());
}
return atom;
}
/**
* Gets the {@link ExEmbedAtom}.
*
@ -122,7 +128,7 @@ public class ExEmbed extends RecordContainer {
*/
public ExEmbedAtom getExEmbedAtom()
{
return embedAtom;
return (ExEmbedAtom)embedAtom;
}
/**

View File

@ -17,11 +17,9 @@
package org.apache.poi.hslf.record;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.*;
import java.util.zip.InflaterInputStream;
import java.util.zip.DeflaterOutputStream;
import org.apache.poi.util.LittleEndian;
@ -92,6 +90,25 @@ public class ExOleObjStg extends RecordAtom implements PersistRecord {
return new InflaterInputStream(compressedStream);
}
/**
* Sets the embedded data.
*
* @param data the embedded data.
*/
public void setData(byte[] data) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
//first four bytes is the length of the raw data
byte[] b = new byte[4];
LittleEndian.putInt(b, data.length);
out.write(b);
DeflaterOutputStream def = new DeflaterOutputStream(out);
def.write(data, 0, data.length);
def.finish();
_data = out.toByteArray();
LittleEndian.putInt(_header, 4, _data.length);
}
/**
* Gets the record type.
*

View File

@ -119,7 +119,7 @@ public class RecordTypes {
public static final Type RecolorInfoAtom = new Type(4071,null);
public static final Type ExQuickTimeMovie = new Type(4074,null);
public static final Type ExQuickTimeMovieData = new Type(4075,null);
public static final Type ExControl = new Type(4078,null);
public static final Type ExControl = new Type(4078,ExControl.class);
public static final Type SlideListWithText = new Type(4080,SlideListWithText.class);
public static final Type InteractiveInfo = new Type(4082,InteractiveInfo.class);
public static final Type InteractiveInfoAtom = new Type(4083,InteractiveInfoAtom.class);

View File

@ -20,6 +20,7 @@ import org.apache.poi.util.LittleEndian;
import java.io.OutputStream;
import java.io.IOException;
import java.util.ArrayList;
/**
* The special info runs contained in this text.
@ -82,4 +83,118 @@ public class TextSpecInfoAtom extends RecordAtom {
public void setTextSize(int size){
LittleEndian.putInt(_data, 0, size);
}
/**
* Reset the content to one info run with the default values
* @param size the site of parent text
*/
public void reset(int size){
_data = new byte[10];
// 01 00 00 00
LittleEndian.putInt(_data, 0, size);
// 01 00 00 00
LittleEndian.putInt(_data, 4, 1); //mask
// 00 00
LittleEndian.putShort(_data, 8, (short)0); //langId
// Update the size (header bytes 5-8)
LittleEndian.putInt(_header, 4, _data.length);
}
/**
* Get the number of characters covered by this records
*
* @return the number of characters covered by this records
*/
public int getCharactersCovered(){
int covered = 0;
TextSpecInfoRun[] runs = getTextSpecInfoRuns();
for (int i = 0; i < runs.length; i++) covered += runs[i].len;
return covered;
}
public TextSpecInfoRun[] getTextSpecInfoRuns(){
ArrayList lst = new ArrayList();
int pos = 0;
int[] bits = {1, 0, 2};
while(pos < _data.length) {
TextSpecInfoRun run = new TextSpecInfoRun();
run.len = LittleEndian.getInt(_data, pos); pos += 4;
run.mask = LittleEndian.getInt(_data, pos); pos += 4;
for (int i = 0; i < bits.length; i++) {
if((run.mask & 1 << bits[i]) != 0){
switch (bits[i]){
case 0:
run.spellInfo = LittleEndian.getShort(_data, pos); pos += 2;
break;
case 1:
run.langId = LittleEndian.getShort(_data, pos); pos += 2;
break;
case 2:
run.altLangId = LittleEndian.getShort(_data, pos); pos += 2;
break;
}
}
}
lst.add(run);
}
return (TextSpecInfoRun[])lst.toArray(new TextSpecInfoRun[lst.size()]);
}
public static class TextSpecInfoRun {
//Length of special info run.
protected int len;
//Special info mask of this run;
protected int mask;
// info fields as indicated by the mask.
// -1 means the bit is not set
protected short spellInfo = -1;
protected short langId = -1;
protected short altLangId = -1;
/**
* Spelling status of this text. See Spell Info table below.
*
* <p>Spell Info Types:</p>
* <li>0 Unchecked
* <li>1 Previously incorrect, needs rechecking
* <li>2 Correct
* <li>3 Incorrect
*
* @return Spelling status of this text
*/
public short getSpellInfo(){
return spellInfo;
}
/**
* Windows LANGID for this text.
*
* @return Windows LANGID for this text.
*/
public short getLangId(){
return spellInfo;
}
/**
* Alternate Windows LANGID of this text;
* must be a valid non-East Asian LANGID if the text has an East Asian language,
* otherwise may be an East Asian LANGID or language neutral (zero).
*
* @return Alternate Windows LANGID of this text
*/
public short getAltLangId(){
return altLangId;
}
/**
* @return Length of special info run.
*/
public int length(){
return len;
}
}
}

View File

@ -17,6 +17,7 @@
package org.apache.poi.hslf.usermodel;
import java.io.InputStream;
import java.io.IOException;
import org.apache.poi.hslf.record.ExOleObjStg;
@ -49,6 +50,15 @@ public class ObjectData {
return storage.getData();
}
/**
* Sets the embedded data.
*
* @param data the embedded data.
*/
public void setData(byte[] data) throws IOException {
storage.setData(data);
}
/**
* Return the record that contains the object data.
*

View File

@ -162,10 +162,18 @@ public class RichTextRun {
* Change the text
*/
public void setText(String text) {
length = text.length();
parentRun.changeTextInRichTextRun(this,text);
String s = parentRun.normalize(text);
setRawText(s);
}
/**
* Change the text
*/
public void setRawText(String text) {
length = text.length();
parentRun.changeTextInRichTextRun(this,text);
}
/**
* Tells the RichTextRun its new position in the parent TextRun
* @param startAt

View File

@ -1,4 +1,3 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
@ -16,22 +15,20 @@
limitations under the License.
==================================================================== */
package org.apache.poi.hwpf.model;
import java.util.Arrays;
import org.apache.poi.util.BitField;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.hwpf.usermodel.CharacterProperties;
import org.apache.poi.hwpf.usermodel.ParagraphProperties;
import org.apache.poi.hwpf.sprm.ParagraphSprmCompressor;
import org.apache.poi.hwpf.sprm.CharacterSprmCompressor;
import java.util.Arrays;
public class ListLevel
/**
*
*/
public final class ListLevel
{
private static final int RGBXCH_NUMS_SIZE = 9;
private int _iStartAt;
private byte _nfc;
private byte _info;
@ -70,7 +67,7 @@ public class ListLevel
_grpprlPapx = new byte[0];
_grpprlChpx = new byte[0];
_numberText = new char[0];
_rgbxchNums = new byte[9];
_rgbxchNums = new byte[RGBXCH_NUMS_SIZE];
if (numbered)
{
@ -90,12 +87,11 @@ public class ListLevel
_nfc = buf[offset++];
_info = buf[offset++];
_rgbxchNums = new byte[9];
for (int x = 0; x < 9; x++)
{
_rgbxchNums[x] = buf[offset++];
}
_ixchFollow = buf[offset++];
_rgbxchNums = new byte[RGBXCH_NUMS_SIZE];
System.arraycopy(buf, offset, _rgbxchNums, 0, RGBXCH_NUMS_SIZE);
offset += RGBXCH_NUMS_SIZE;
_ixchFollow = buf[offset++];
_dxaSpace = LittleEndian.getInt(buf, offset);
offset += LittleEndian.INT_SIZE;
_dxaIndent = LittleEndian.getInt(buf, offset);
@ -207,8 +203,8 @@ public class ListLevel
offset += LittleEndian.INT_SIZE;
buf[offset++] = _nfc;
buf[offset++] = _info;
System.arraycopy(_rgbxchNums, 0, buf, offset, _rgbxchNums.length);
offset += _rgbxchNums.length;
System.arraycopy(_rgbxchNums, 0, buf, offset, RGBXCH_NUMS_SIZE);
offset += RGBXCH_NUMS_SIZE;
buf[offset++] = _ixchFollow;
LittleEndian.putInt(buf, offset, _dxaSpace);
offset += LittleEndian.INT_SIZE;
@ -225,23 +221,33 @@ public class ListLevel
System.arraycopy(_grpprlPapx, 0, buf, offset, _cbGrpprlPapx);
offset += _cbGrpprlPapx;
LittleEndian.putShort(buf, offset, (short)_numberText.length);
offset += LittleEndian.SHORT_SIZE;
for (int x = 0; x < _numberText.length; x++)
{
LittleEndian.putShort(buf, offset, (short)_numberText[x]);
if (_numberText == null) {
// TODO - write junit to test this flow
LittleEndian.putUShort(buf, offset, 0);
} else {
LittleEndian.putUShort(buf, offset, _numberText.length);
offset += LittleEndian.SHORT_SIZE;
for (int x = 0; x < _numberText.length; x++)
{
LittleEndian.putUShort(buf, offset, _numberText[x]);
offset += LittleEndian.SHORT_SIZE;
}
}
return buf;
}
public int getSizeInBytes()
{
if (_numberText!=null)
{
return 28 + _cbGrpprlChpx + _cbGrpprlPapx + (_numberText.length * LittleEndian.SHORT_SIZE) + 2;
} else {
return 28 + _cbGrpprlChpx + _cbGrpprlPapx + 2;
}
int result =
6 // int byte byte
+ RGBXCH_NUMS_SIZE
+ 13 // byte int int byte byte short
+ _cbGrpprlChpx
+ _cbGrpprlPapx
+ 2; // numberText length
if (_numberText != null) {
result += _numberText.length * LittleEndian.SHORT_SIZE;
}
return result;
}
}

View File

@ -0,0 +1,95 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hslf.record;
import org.apache.poi.hslf.HSLFSlideShow;
import org.apache.poi.hslf.model.textproperties.CharFlagsTextProp;
import org.apache.poi.hslf.model.textproperties.TextProp;
import org.apache.poi.hslf.model.textproperties.TextPropCollection;
import org.apache.poi.hslf.record.StyleTextPropAtom.*;
import org.apache.poi.hslf.usermodel.SlideShow;
import org.apache.poi.util.HexDump;
import junit.framework.TestCase;
import java.io.ByteArrayOutputStream;
import java.util.LinkedList;
import java.util.Arrays;
/**
* Tests TextSpecInfoAtom
*
* @author Yegor Kozlov
*/
public class TestTextSpecInfoAtom extends TestCase {
//from a real file
private byte[] data_1 = new byte[] {
0x00, 0x00, (byte)0xAA, 0x0F, 0x2C, 0x00, 0x00, 0x00,
0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x03, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
public void testRead() throws Exception {
TextSpecInfoAtom spec = new TextSpecInfoAtom(data_1, 0, data_1.length);
TextSpecInfoAtom.TextSpecInfoRun[] run = spec.getTextSpecInfoRuns();
assertEquals(5, run.length);
assertEquals(10, run[0].length());
assertEquals(1, run[1].length());
assertEquals(70, run[2].length());
assertEquals(9, run[3].length());
assertEquals(32, run[4].length());
}
public void testWrite() throws Exception {
TextSpecInfoAtom spec = new TextSpecInfoAtom(data_1, 0, data_1.length);
ByteArrayOutputStream out = new ByteArrayOutputStream();
spec.writeOut(out);
byte[] result = out.toByteArray();
assertTrue(Arrays.equals(result, data_1));
}
public void testReset() throws Exception {
TextSpecInfoAtom spec = new TextSpecInfoAtom(data_1, 0, data_1.length);
spec.reset(32); //length of the parent text
TextSpecInfoAtom.TextSpecInfoRun[] run = spec.getTextSpecInfoRuns();
assertEquals(1, run.length);
assertEquals(32, run[0].length());
//serialize and read again
ByteArrayOutputStream out = new ByteArrayOutputStream();
spec.writeOut(out);
byte[] result = out.toByteArray();
TextSpecInfoAtom spec2 = new TextSpecInfoAtom(result, 0, result.length);
TextSpecInfoAtom.TextSpecInfoRun[] run2 = spec2.getTextSpecInfoRuns();
assertEquals(1, run2.length);
assertEquals(32, run2[0].length());
}
}

View File

@ -22,9 +22,7 @@ import junit.framework.TestSuite;
import org.apache.poi.hssf.eventmodel.TestEventRecordFactory;
import org.apache.poi.hssf.eventmodel.TestModelFactory;
import org.apache.poi.hssf.model.TestDrawingManager;
import org.apache.poi.hssf.model.TestFormulaParser;
import org.apache.poi.hssf.model.TestSheet;
import org.apache.poi.hssf.model.AllModelTests;
import org.apache.poi.hssf.record.AllRecordTests;
import org.apache.poi.hssf.usermodel.AllUserModelTests;
import org.apache.poi.hssf.util.TestAreaReference;
@ -50,10 +48,10 @@ public final class HSSFTests {
TestSuite suite = new TestSuite("Tests for org.apache.poi.hssf");
// $JUnit-BEGIN$
suite.addTest(AllModelTests.suite());
suite.addTest(AllUserModelTests.suite());
suite.addTest(AllRecordTests.suite());
suite.addTest(new TestSuite(TestFormulaParser.class));
suite.addTest(new TestSuite(TestAreaReference.class));
suite.addTest(new TestSuite(TestCellReference.class));
suite.addTest(new TestSuite(TestRangeAddress.class));
@ -61,8 +59,6 @@ public final class HSSFTests {
suite.addTest(new TestSuite(TestSheetReferences.class));
suite.addTest(new TestSuite(TestEventRecordFactory.class));
suite.addTest(new TestSuite(TestModelFactory.class));
suite.addTest(new TestSuite(TestDrawingManager.class));
suite.addTest(new TestSuite(TestSheet.class));
// $JUnit-END$
return suite;
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,40 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hssf.model;
import junit.framework.Test;
import junit.framework.TestSuite;
/**
* Collects all tests for <tt>org.apache.poi.hssf.model</tt>.
*
* @author Josh Micich
*/
public final class AllModelTests {
public static Test suite() {
TestSuite result = new TestSuite(AllModelTests.class.getName());
result.addTestSuite(TestDrawingManager.class);
result.addTestSuite(TestDrawingManager2.class);
result.addTestSuite(TestFormulaParser.class);
result.addTestSuite(TestFormulaParserEval.class);
result.addTestSuite(TestSheet.class);
result.addTestSuite(TestSheetAdditional.class);
return result;
}
}

View File

@ -65,6 +65,7 @@ public final class TestFormulaParser extends TestCase {
* @return parsed token array already confirmed not <code>null</code>
*/
private static Ptg[] parseFormula(String s) {
// TODO - replace multiple copies of this code with calls to this method
FormulaParser fp = new FormulaParser(s, null);
fp.parse();
Ptg[] result = fp.getRPNPtg();
@ -86,7 +87,6 @@ public final class TestFormulaParser extends TestCase {
assertTrue("",(ptgs[0] instanceof IntPtg));
assertTrue("",(ptgs[1] instanceof IntPtg));
assertTrue("",(ptgs[2] instanceof AddPtg));
}
public void testFormulaWithSpace2() {
@ -169,8 +169,6 @@ public final class TestFormulaParser extends TestCase {
assertEquals("If FALSE offset", (short)7, ifPtg.getData());
FuncVarPtg funcPtg = (FuncVarPtg)asts[8];
}
/**
@ -190,8 +188,6 @@ public final class TestFormulaParser extends TestCase {
assertTrue("It is not an if", ifFunc.isOptimizedIf());
assertTrue("Average Function set correctly", (asts[5] instanceof FuncVarPtg));
}
public void testIfSingleCondition(){
@ -213,8 +209,6 @@ public final class TestFormulaParser extends TestCase {
assertTrue("Ptg is not a Variable Function", (asts[6] instanceof FuncVarPtg));
FuncVarPtg funcPtg = (FuncVarPtg)asts[6];
assertEquals("Arguments", 2, funcPtg.getNumberOfOperands());
}
public void testSumIf() {
@ -223,7 +217,6 @@ public final class TestFormulaParser extends TestCase {
fp.parse();
Ptg[] asts = fp.getRPNPtg();
assertEquals("4 Ptgs expected", 4, asts.length);
}
/**
@ -235,51 +228,35 @@ public final class TestFormulaParser extends TestCase {
String currencyCell = "F3";
String function="\"TOTAL[\"&"+currencyCell+"&\"]\"";
FormulaParser fp = new FormulaParser(function, null);
fp.parse();
Ptg[] asts = fp.getRPNPtg();
Ptg[] asts = parseFormula(function);
assertEquals("5 ptgs expected", 5, asts.length);
assertTrue ("Ptg[0] is a string", (asts[0] instanceof StringPtg));
StringPtg firstString = (StringPtg)asts[0];
assertEquals("TOTAL[", firstString.getValue());
//the PTG order isn't 100% correct but it still works - dmui
}
public void testSimpleLogical() {
FormulaParser fp=new FormulaParser("IF(A1<A2,B1,B2)",null);
fp.parse();
Ptg[] ptgs = fp.getRPNPtg();
assertTrue("Ptg array should not be null", ptgs !=null);
Ptg[] ptgs = parseFormula("IF(A1<A2,B1,B2)");
assertEquals("Ptg array length", 9, ptgs.length);
assertEquals("3rd Ptg is less than",LessThanPtg.class,ptgs[2].getClass());
assertEquals("3rd Ptg is less than", LessThanPtg.class, ptgs[2].getClass());
}
public void testParenIf() {
FormulaParser fp=new FormulaParser("IF((A1+A2)<=3,\"yes\",\"no\")",null);
fp.parse();
Ptg[] ptgs = fp.getRPNPtg();
assertTrue("Ptg array should not be null", ptgs !=null);
Ptg[] ptgs = parseFormula("IF((A1+A2)<=3,\"yes\",\"no\")");
assertEquals("Ptg array length", 12, ptgs.length);
assertEquals("6th Ptg is less than equal",LessEqualPtg.class,ptgs[5].getClass());
assertEquals("11th Ptg is not a goto (Attr) ptg",AttrPtg.class,ptgs[10].getClass());
}
public void testEmbeddedIf() {
FormulaParser fp=new FormulaParser("IF(3>=1,\"*\",IF(4<>1,\"first\",\"second\"))",null);
fp.parse();
Ptg[] ptgs = fp.getRPNPtg();
assertTrue("Ptg array should not be null", ptgs !=null);
Ptg[] ptgs = parseFormula("IF(3>=1,\"*\",IF(4<>1,\"first\",\"second\"))");
assertEquals("Ptg array length", 17, ptgs.length);
assertEquals("6th Ptg is not a goto (Attr) ptg",AttrPtg.class,ptgs[5].getClass());
assertEquals("9th Ptg is not a not equal ptg",NotEqualPtg.class,ptgs[8].getClass());
assertEquals("15th Ptg is not the inner IF variable function ptg",FuncVarPtg.class,ptgs[14].getClass());
}
public void testMacroFunction() {
@ -302,16 +279,15 @@ public final class TestFormulaParser extends TestCase {
Ptg[] ptg = fp.getRPNPtg();
assertTrue("first ptg is string",ptg[0] instanceof StringPtg);
assertTrue("second ptg is string",ptg[1] instanceof StringPtg);
}
public void testConcatenate(){
FormulaParser fp = new FormulaParser("CONCATENATE(\"first\",\"second\")",null);
fp.parse();
Ptg[] ptg = fp.getRPNPtg();
assertTrue("first ptg is string",ptg[0] instanceof StringPtg);
assertTrue("second ptg is string",ptg[1] instanceof StringPtg);
}
public void testConcatenate() {
FormulaParser fp = new FormulaParser("CONCATENATE(\"first\",\"second\")", null);
fp.parse();
Ptg[] ptg = fp.getRPNPtg();
assertTrue("first ptg is string", ptg[0] instanceof StringPtg);
assertTrue("second ptg is string", ptg[1] instanceof StringPtg);
}
public void testWorksheetReferences()
{
@ -395,16 +371,16 @@ public final class TestFormulaParser extends TestCase {
/** bug 33160, testcase by Amol Deshmukh*/
public void testSimpleLongFormula() {
FormulaParser fp = new FormulaParser("40000/2", null);
fp.parse();
Ptg[] ptgs = fp.getRPNPtg();
assertTrue("three tokens expected, got "+ptgs.length,ptgs.length == 3);
assertTrue("IntPtg",(ptgs[0] instanceof IntPtg));
assertTrue("IntPtg",(ptgs[1] instanceof IntPtg));
assertTrue("DividePtg",(ptgs[2] instanceof DividePtg));
FormulaParser fp = new FormulaParser("40000/2", null);
fp.parse();
Ptg[] ptgs = fp.getRPNPtg();
assertTrue("three tokens expected, got " + ptgs.length, ptgs.length == 3);
assertTrue("IntPtg", (ptgs[0] instanceof IntPtg));
assertTrue("IntPtg", (ptgs[1] instanceof IntPtg));
assertTrue("DividePtg", (ptgs[2] instanceof DividePtg));
}
/** bug 35027, underscore in sheet name*/
/** bug 35027, underscore in sheet name */
public void testUnderscore() {
HSSFWorkbook wb = new HSSFWorkbook();
@ -775,8 +751,34 @@ public final class TestFormulaParser extends TestCase {
StringPtg sp = (StringPtg) parseSingleToken(formula, StringPtg.class);
assertEquals(expectedValue, sp.getValue());
}
public void testParseStringLiterals_bug28754() {
public void testPaseStringLiterals() {
StringPtg sp;
try {
sp = (StringPtg) parseSingleToken("\"test\"\"ing\"", StringPtg.class);
} catch (RuntimeException e) {
if(e.getMessage().startsWith("Cannot Parse")) {
throw new AssertionFailedError("Identified bug 28754a");
}
throw e;
}
assertEquals("test\"ing", sp.getValue());
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet sheet = wb.createSheet();
wb.setSheetName(0, "Sheet1");
HSSFRow row = sheet.createRow(0);
HSSFCell cell = row.createCell((short)0);
cell.setCellFormula("right(\"test\"\"ing\", 3)");
String actualCellFormula = cell.getCellFormula();
if("RIGHT(\"test\"ing\",3)".equals(actualCellFormula)) {
throw new AssertionFailedError("Identified bug 28754b");
}
assertEquals("RIGHT(\"test\"\"ing\",3)", actualCellFormula);
}
public void testParseStringLiterals() {
confirmStringParse("goto considered harmful");
confirmStringParse("goto 'considered' harmful");
@ -810,10 +812,8 @@ public final class TestFormulaParser extends TestCase {
parseExpectedException("#DIV/ 0+2");
if (false) { // TODO - add functionality to detect func arg count mismatch
parseExpectedException("IF(TRUE)");
parseExpectedException("countif(A1:B5, C1, D1)");
}
parseExpectedException("IF(TRUE)");
parseExpectedException("countif(A1:B5, C1, D1)");
}
private static void parseExpectedException(String formula) {
@ -887,8 +887,16 @@ public final class TestFormulaParser extends TestCase {
assertTrue(e.getMessage().startsWith("Too few arguments suppled to operation token"));
}
}
/**
* Make sure that POI uses the right Func Ptg when encoding formulas. Functions with variable
* number of args should get FuncVarPtg, functions with fixed args should get FuncPtg.<p/>
*
* Prior to the fix for bug 44675 POI would encode FuncVarPtg for all functions. In many cases
* Excel tolerates the wrong Ptg and evaluates the formula OK (e.g. SIN), but in some cases
* (e.g. COUNTIF) Excel fails to evaluate the formula, giving '#VALUE!' instead.
*/
public void testFuncPtgSelection() {
HSSFWorkbook book = new HSSFWorkbook();
HSSFWorkbook book = new HSSFWorkbook();
Ptg[] ptgs;
ptgs = FormulaParser.parse("countif(A1:A2, 1)", book);
assertEquals(3, ptgs.length);

View File

@ -1,4 +1,3 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
@ -15,7 +14,6 @@
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hssf.model;
@ -34,8 +32,7 @@ import java.util.List;
*
* @author Glen Stampoultzis (glens at apache.org)
*/
public class TestSheet extends TestCase
{
public final class TestSheet extends TestCase {
public void testCreateSheet() throws Exception
{
// Check we're adding row and cell aggregates
@ -76,6 +73,21 @@ public class TestSheet extends TestCase
if ((regionsToAdd % 1027) != 0)
recordsExpected++;
assertTrue("The " + regionsToAdd + " merged regions should have been spread out over " + recordsExpected + " records, not " + recordsAdded, recordsAdded == recordsExpected);
// Check we can't add one with invalid date
try {
sheet.addMergedRegion(10, (short)10, 9, (short)12);
fail("Expected an exception to occur");
} catch(IllegalArgumentException e) {
// occurs during successful test
assertEquals("The 'to' row (9) must not be less than the 'from' row (10)", e.getMessage());
}
try {
sheet.addMergedRegion(10, (short)10, 12, (short)9);
fail("Expected an exception to occur");
} catch(IllegalArgumentException e) {
// occurs during successful test
assertEquals("The 'to' col (9) must not be less than the 'from' col (10)", e.getMessage());
}
}
public void testRemoveMergedRegion()
@ -113,9 +125,9 @@ public class TestSheet extends TestCase
MergeCellsRecord merged = new MergeCellsRecord();
merged.addArea(0, (short)0, 1, (short)2);
records.add(new RowRecord());
records.add(new RowRecord());
records.add(new RowRecord());
records.add(new RowRecord(0));
records.add(new RowRecord(1));
records.add(new RowRecord(2));
records.add(merged);
Sheet sheet = Sheet.createSheet(records, 0);
@ -142,20 +154,11 @@ public class TestSheet extends TestCase
*/
public void testRowAggregation() {
List records = new ArrayList();
RowRecord row = new RowRecord();
row.setRowNumber(0);
records.add(row);
row = new RowRecord();
row.setRowNumber(1);
records.add(row);
records.add(new RowRecord(0));
records.add(new RowRecord(1));
records.add(new StringRecord());
row = new RowRecord();
row.setRowNumber(2);
records.add(row);
records.add(new RowRecord(2));
Sheet sheet = Sheet.createSheet(records, 0);
assertNotNull("Row [2] was skipped", sheet.getRow(2));
@ -197,9 +200,9 @@ public class TestSheet extends TestCase
Iterator iterator = sheet.getRowBreaks();
while (iterator.hasNext()) {
PageBreakRecord.Break breakItem = (PageBreakRecord.Break)iterator.next();
int main = (int)breakItem.main;
int main = breakItem.main;
if (main != 0 && main != 10 && main != 11) fail("Invalid page break");
if (main == 0) is0 = true;
if (main == 0) is0 = true;
if (main == 10) is10= true;
if (main == 11) is11 = true;
}
@ -216,8 +219,6 @@ public class TestSheet extends TestCase
assertFalse("row should be removed", sheet.isRowBroken(10));
assertEquals("no more breaks", 0, sheet.getNumRowBreaks());
}
/**
@ -256,10 +257,10 @@ public class TestSheet extends TestCase
Iterator iterator = sheet.getColumnBreaks();
while (iterator.hasNext()) {
PageBreakRecord.Break breakItem = (PageBreakRecord.Break)iterator.next();
int main = (int)breakItem.main;
int main = breakItem.main;
if (main != 0 && main != 1 && main != 10 && main != 15) fail("Invalid page break");
if (main == 0) is0 = true;
if (main == 1) is1 = true;
if (main == 0) is0 = true;
if (main == 1) is1 = true;
if (main == 10) is10= true;
if (main == 15) is15 = true;
}
@ -286,72 +287,69 @@ public class TestSheet extends TestCase
* works as designed.
*/
public void testXFIndexForColumn() {
try{
final short TEST_IDX = 10;
final short DEFAULT_IDX = 0xF; // 15
short xfindex = Short.MIN_VALUE;
Sheet sheet = Sheet.createSheet();
// without ColumnInfoRecord
xfindex = sheet.getXFIndexForColAt((short) 0);
assertEquals(DEFAULT_IDX, xfindex);
xfindex = sheet.getXFIndexForColAt((short) 1);
assertEquals(DEFAULT_IDX, xfindex);
ColumnInfoRecord nci = ( ColumnInfoRecord ) sheet.createColInfo();
sheet.columns.insertColumn(nci);
// single column ColumnInfoRecord
nci.setFirstColumn((short) 2);
nci.setLastColumn((short) 2);
nci.setXFIndex(TEST_IDX);
xfindex = sheet.getXFIndexForColAt((short) 0);
assertEquals(DEFAULT_IDX, xfindex);
xfindex = sheet.getXFIndexForColAt((short) 1);
assertEquals(DEFAULT_IDX, xfindex);
xfindex = sheet.getXFIndexForColAt((short) 2);
assertEquals(TEST_IDX, xfindex);
xfindex = sheet.getXFIndexForColAt((short) 3);
assertEquals(DEFAULT_IDX, xfindex);
final short TEST_IDX = 10;
final short DEFAULT_IDX = 0xF; // 15
short xfindex = Short.MIN_VALUE;
Sheet sheet = Sheet.createSheet();
// without ColumnInfoRecord
xfindex = sheet.getXFIndexForColAt((short) 0);
assertEquals(DEFAULT_IDX, xfindex);
xfindex = sheet.getXFIndexForColAt((short) 1);
assertEquals(DEFAULT_IDX, xfindex);
ColumnInfoRecord nci = ( ColumnInfoRecord ) sheet.createColInfo();
sheet.columns.insertColumn(nci);
// single column ColumnInfoRecord
nci.setFirstColumn((short) 2);
nci.setLastColumn((short) 2);
nci.setXFIndex(TEST_IDX);
xfindex = sheet.getXFIndexForColAt((short) 0);
assertEquals(DEFAULT_IDX, xfindex);
xfindex = sheet.getXFIndexForColAt((short) 1);
assertEquals(DEFAULT_IDX, xfindex);
xfindex = sheet.getXFIndexForColAt((short) 2);
assertEquals(TEST_IDX, xfindex);
xfindex = sheet.getXFIndexForColAt((short) 3);
assertEquals(DEFAULT_IDX, xfindex);
// ten column ColumnInfoRecord
nci.setFirstColumn((short) 2);
nci.setLastColumn((short) 11);
nci.setXFIndex(TEST_IDX);
xfindex = sheet.getXFIndexForColAt((short) 1);
assertEquals(DEFAULT_IDX, xfindex);
xfindex = sheet.getXFIndexForColAt((short) 2);
assertEquals(TEST_IDX, xfindex);
xfindex = sheet.getXFIndexForColAt((short) 6);
assertEquals(TEST_IDX, xfindex);
xfindex = sheet.getXFIndexForColAt((short) 11);
assertEquals(TEST_IDX, xfindex);
xfindex = sheet.getXFIndexForColAt((short) 12);
assertEquals(DEFAULT_IDX, xfindex);
// ten column ColumnInfoRecord
nci.setFirstColumn((short) 2);
nci.setLastColumn((short) 11);
nci.setXFIndex(TEST_IDX);
xfindex = sheet.getXFIndexForColAt((short) 1);
assertEquals(DEFAULT_IDX, xfindex);
xfindex = sheet.getXFIndexForColAt((short) 2);
assertEquals(TEST_IDX, xfindex);
xfindex = sheet.getXFIndexForColAt((short) 6);
assertEquals(TEST_IDX, xfindex);
xfindex = sheet.getXFIndexForColAt((short) 11);
assertEquals(TEST_IDX, xfindex);
xfindex = sheet.getXFIndexForColAt((short) 12);
assertEquals(DEFAULT_IDX, xfindex);
// single column ColumnInfoRecord starting at index 0
nci.setFirstColumn((short) 0);
nci.setLastColumn((short) 0);
nci.setXFIndex(TEST_IDX);
xfindex = sheet.getXFIndexForColAt((short) 0);
assertEquals(TEST_IDX, xfindex);
xfindex = sheet.getXFIndexForColAt((short) 1);
assertEquals(DEFAULT_IDX, xfindex);
// single column ColumnInfoRecord starting at index 0
nci.setFirstColumn((short) 0);
nci.setLastColumn((short) 0);
nci.setXFIndex(TEST_IDX);
xfindex = sheet.getXFIndexForColAt((short) 0);
assertEquals(TEST_IDX, xfindex);
xfindex = sheet.getXFIndexForColAt((short) 1);
assertEquals(DEFAULT_IDX, xfindex);
// ten column ColumnInfoRecord starting at index 0
nci.setFirstColumn((short) 0);
nci.setLastColumn((short) 9);
nci.setXFIndex(TEST_IDX);
xfindex = sheet.getXFIndexForColAt((short) 0);
assertEquals(TEST_IDX, xfindex);
xfindex = sheet.getXFIndexForColAt((short) 7);
assertEquals(TEST_IDX, xfindex);
xfindex = sheet.getXFIndexForColAt((short) 9);
assertEquals(TEST_IDX, xfindex);
xfindex = sheet.getXFIndexForColAt((short) 10);
assertEquals(DEFAULT_IDX, xfindex);
}
catch(Exception e){e.printStackTrace();fail(e.getMessage());}
// ten column ColumnInfoRecord starting at index 0
nci.setFirstColumn((short) 0);
nci.setLastColumn((short) 9);
nci.setXFIndex(TEST_IDX);
xfindex = sheet.getXFIndexForColAt((short) 0);
assertEquals(TEST_IDX, xfindex);
xfindex = sheet.getXFIndexForColAt((short) 7);
assertEquals(TEST_IDX, xfindex);
xfindex = sheet.getXFIndexForColAt((short) 9);
assertEquals(TEST_IDX, xfindex);
xfindex = sheet.getXFIndexForColAt((short) 10);
assertEquals(DEFAULT_IDX, xfindex);
}
}

View File

@ -19,125 +19,18 @@ package org.apache.poi.hssf.model;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import junit.framework.TestCase;
import org.apache.poi.hssf.record.ColumnInfoRecord;
import org.apache.poi.hssf.record.MergeCellsRecord;
import org.apache.poi.hssf.record.PageBreakRecord;
import org.apache.poi.hssf.record.RowRecord;
import org.apache.poi.hssf.record.StringRecord;
/**
* @author Tony Poppleton
*/
public class TestSheetAdditional extends TestCase
{
/**
* Constructor for SheetTest.
* @param arg0
*/
public TestSheetAdditional(String arg0)
{
super(arg0);
}
public final class TestSheetAdditional extends TestCase {
public void testAddMergedRegion()
{
Sheet sheet = Sheet.createSheet();
int regionsToAdd = 4096;
int startRecords = sheet.getRecords().size();
//simple test that adds a load of regions
for (int n = 0; n < regionsToAdd; n++)
{
int index = sheet.addMergedRegion(0, (short) 0, 1, (short) 1);
assertTrue("Merged region index expected to be " + n + " got " + index, index == n);
}
//test all the regions were indeed added
assertTrue(sheet.getNumMergedRegions() == regionsToAdd);
//test that the regions were spread out over the appropriate number of records
int recordsAdded = sheet.getRecords().size() - startRecords;
int recordsExpected = regionsToAdd/1027;
if ((regionsToAdd % 1027) != 0)
recordsExpected++;
assertTrue("The " + regionsToAdd + " merged regions should have been spread out over " + recordsExpected + " records, not " + recordsAdded, recordsAdded == recordsExpected);
// Check we can't add one with invalud date
try {
sheet.addMergedRegion(10, (short)10, 9, (short)12);
fail();
} catch(IllegalArgumentException e) {}
try {
sheet.addMergedRegion(10, (short)10, 12, (short)9);
fail();
} catch(IllegalArgumentException e) {}
}
public void testRemoveMergedRegion()
{
Sheet sheet = Sheet.createSheet();
int regionsToAdd = 4096;
for (int n = 0; n < regionsToAdd; n++)
sheet.addMergedRegion(0, (short) 0, 1, (short) 1);
int records = sheet.getRecords().size();
//remove a third from the beginning
for (int n = 0; n < regionsToAdd/3; n++)
{
sheet.removeMergedRegion(0);
//assert they have been deleted
assertTrue("Num of regions should be " + (regionsToAdd - n - 1) + " not " + sheet.getNumMergedRegions(), sheet.getNumMergedRegions() == regionsToAdd - n - 1);
}
//assert any record removing was done
int recordsRemoved = (regionsToAdd/3)/1027; //doesn't work for particular values of regionsToAdd
assertTrue("Expected " + recordsRemoved + " record to be removed from the starting " + records + ". Currently there are " + sheet.getRecords().size() + " records", records - sheet.getRecords().size() == recordsRemoved);
}
/**
* Bug: 22922 (Reported by Xuemin Guan)
* <p>
* Remove mergedregion fails when a sheet loses records after an initial CreateSheet
* fills up the records.
*
*/
public void testMovingMergedRegion() {
List records = new ArrayList();
MergeCellsRecord merged = new MergeCellsRecord();
merged.addArea(0, (short)0, 1, (short)2);
records.add(new RowRecord());
records.add(new RowRecord());
records.add(new RowRecord());
records.add(merged);
Sheet sheet = Sheet.createSheet(records, 0);
sheet.records.remove(0);
//stub object to throw off list INDEX operations
sheet.removeMergedRegion(0);
assertEquals("Should be no more merged regions", 0, sheet.getNumMergedRegions());
}
public void testGetMergedRegionAt()
{
//TODO
}
public void testGetNumMergedRegions()
{
//TODO
}
public void DISBALEDtestGetCellWidth() throws Exception
{
public void testGetCellWidth() {
Sheet sheet = Sheet.createSheet();
ColumnInfoRecord nci = ( ColumnInfoRecord ) sheet.createColInfo();
@ -146,14 +39,8 @@ public class TestSheetAdditional extends TestCase
nci.setLastColumn((short)10);
nci.setColumnWidth((short)100);
Field f = null;
f = Sheet.class.getDeclaredField("columnSizes");
f.setAccessible(true);
List columnSizes = new ArrayList();
f.set(sheet,columnSizes);
columnSizes.add(nci);
sheet.records.add(1 + sheet.dimsloc, nci);
sheet.dimsloc++;
sheet.columns.insertColumn(nci);
assertEquals((short)100,sheet.getColumnWidth((short)5));
assertEquals((short)100,sheet.getColumnWidth((short)6));
@ -172,151 +59,6 @@ public class TestSheetAdditional extends TestCase
assertEquals((short)100,sheet.getColumnWidth((short)10));
}
/**
* Makes sure all rows registered for this sheet are aggregated, they were being skipped
*
*/
public void testRowAggregation() {
List records = new ArrayList();
RowRecord row = new RowRecord();
row.setRowNumber(0);
records.add(row);
row = new RowRecord();
row.setRowNumber(1);
records.add(row);
records.add(new StringRecord());
row = new RowRecord();
row.setRowNumber(2);
records.add(row);
Sheet sheet = Sheet.createSheet(records, 0);
assertNotNull("Row [2] was skipped", sheet.getRow(2));
}
/**
* Make sure page break functionality works (in memory)
*
*/
public void testRowPageBreaks(){
short colFrom = 0;
short colTo = 255;
Sheet sheet = Sheet.createSheet();
sheet.setRowBreak(0, colFrom, colTo);
assertTrue("no row break at 0", sheet.isRowBroken(0));
assertEquals("1 row break available", 1, sheet.getNumRowBreaks());
sheet.setRowBreak(0, colFrom, colTo);
sheet.setRowBreak(0, colFrom, colTo);
assertTrue("no row break at 0", sheet.isRowBroken(0));
assertEquals("1 row break available", 1, sheet.getNumRowBreaks());
sheet.setRowBreak(10, colFrom, colTo);
sheet.setRowBreak(11, colFrom, colTo);
assertTrue("no row break at 10", sheet.isRowBroken(10));
assertTrue("no row break at 11", sheet.isRowBroken(11));
assertEquals("3 row break available", 3, sheet.getNumRowBreaks());
boolean is10 = false;
boolean is0 = false;
boolean is11 = false;
Iterator iterator = sheet.getRowBreaks();
while (iterator.hasNext()) {
PageBreakRecord.Break breakItem = (PageBreakRecord.Break)iterator.next();
int main = (int)breakItem.main;
if (main != 0 && main != 10 && main != 11) fail("Invalid page break");
if (main == 0) is0 = true;
if (main == 10) is10= true;
if (main == 11) is11 = true;
}
assertTrue("one of the breaks didnt make it", is0 && is10 && is11);
sheet.removeRowBreak(11);
assertFalse("row should be removed", sheet.isRowBroken(11));
sheet.removeRowBreak(0);
assertFalse("row should be removed", sheet.isRowBroken(0));
sheet.removeRowBreak(10);
assertFalse("row should be removed", sheet.isRowBroken(10));
assertEquals("no more breaks", 0, sheet.getNumRowBreaks());
}
/**
* Make sure column pag breaks works properly (in-memory)
*
*/
public void testColPageBreaks(){
short rowFrom = 0;
short rowTo = (short)65535;
Sheet sheet = Sheet.createSheet();
sheet.setColumnBreak((short)0, rowFrom, rowTo);
assertTrue("no col break at 0", sheet.isColumnBroken((short)0));
assertEquals("1 col break available", 1, sheet.getNumColumnBreaks());
sheet.setColumnBreak((short)0, rowFrom, rowTo);
assertTrue("no col break at 0", sheet.isColumnBroken((short)0));
assertEquals("1 col break available", 1, sheet.getNumColumnBreaks());
sheet.setColumnBreak((short)1, rowFrom, rowTo);
sheet.setColumnBreak((short)10, rowFrom, rowTo);
sheet.setColumnBreak((short)15, rowFrom, rowTo);
assertTrue("no col break at 1", sheet.isColumnBroken((short)1));
assertTrue("no col break at 10", sheet.isColumnBroken((short)10));
assertTrue("no col break at 15", sheet.isColumnBroken((short)15));
assertEquals("4 col break available", 4, sheet.getNumColumnBreaks());
boolean is10 = false;
boolean is0 = false;
boolean is1 = false;
boolean is15 = false;
Iterator iterator = sheet.getColumnBreaks();
while (iterator.hasNext()) {
PageBreakRecord.Break breakItem = (PageBreakRecord.Break)iterator.next();
int main = (int)breakItem.main;
if (main != 0 && main != 1 && main != 10 && main != 15) fail("Invalid page break");
if (main == 0) is0 = true;
if (main == 1) is1 = true;
if (main == 10) is10= true;
if (main == 15) is15 = true;
}
assertTrue("one of the breaks didnt make it", is0 && is1 && is10 && is15);
sheet.removeColumnBreak((short)15);
assertFalse("column break should not be there", sheet.isColumnBroken((short)15));
sheet.removeColumnBreak((short)0);
assertFalse("column break should not be there", sheet.isColumnBroken((short)0));
sheet.removeColumnBreak((short)1);
assertFalse("column break should not be there", sheet.isColumnBroken((short)1));
sheet.removeColumnBreak((short)10);
assertFalse("column break should not be there", sheet.isColumnBroken((short)10));
assertEquals("no more breaks", 0, sheet.getNumColumnBreaks());
}
}

View File

@ -67,6 +67,7 @@ public final class AllRecordTests {
result.addTestSuite(TestFormulaRecord.class);
result.addTestSuite(TestFrameRecord.class);
result.addTestSuite(TestHyperlinkRecord.class);
result.addTestSuite(TestLabelRecord.class);
result.addTestSuite(TestLegendRecord.class);
result.addTestSuite(TestLineFormatRecord.class);
result.addTestSuite(TestLinkedDataRecord.class);

View File

@ -38,6 +38,8 @@ public final class TestExternalNameRecord extends TestCase {
// data taken from bugzilla 44774 att 21790
private static final byte[] dataPlainName = {
0, 0, 0, 0, 0, 0, 9, 0, 82, 97, 116, 101, 95, 68, 97, 116, 101, 9, 0, 58, 0, 0, 0, 0, 4, 0, 8, 0
// TODO - the last 2 bytes of formula data (8,0) seem weird. They encode to ConcatPtg, UnknownPtg
// UnknownPtg is otherwise not created by any other test cases
};
private static ExternalNameRecord createSimpleENR(byte[] data) {

View File

@ -19,17 +19,15 @@ package org.apache.poi.hssf.record;
import java.io.ByteArrayInputStream;
import org.apache.poi.hssf.record.formula.AttrPtg;
import org.apache.poi.hssf.record.formula.ConcatPtg;
import org.apache.poi.hssf.record.formula.FuncVarPtg;
import org.apache.poi.hssf.record.formula.IntPtg;
import org.apache.poi.hssf.record.formula.RangePtg;
import org.apache.poi.hssf.record.formula.ReferencePtg;
import org.apache.poi.hssf.record.formula.UnknownPtg;
import java.util.List;
import junit.framework.TestCase;
import org.apache.poi.hssf.record.formula.AttrPtg;
import org.apache.poi.hssf.record.formula.FuncVarPtg;
import org.apache.poi.hssf.record.formula.IntPtg;
import org.apache.poi.hssf.record.formula.ReferencePtg;
/**
* Tests the serialization and deserialization of the FormulaRecord
* class works correctly.
@ -57,7 +55,7 @@ public final class TestFormulaRecord extends TestCase {
*/
public void testCheckNanPreserve() {
byte[] formulaByte = new byte[29];
for (int i = 0; i < formulaByte.length; i++) formulaByte[i] = (byte)0;
formulaByte[4] = (byte)0x0F;
formulaByte[6] = (byte)0x02;
formulaByte[8] = (byte)0x07;
@ -91,8 +89,6 @@ public final class TestFormulaRecord extends TestCase {
public void testExpFormula() {
byte[] formulaByte = new byte[27];
for (int i = 0; i < formulaByte.length; i++) formulaByte[i] = (byte)0;
formulaByte[4] =(byte)0x0F;
formulaByte[14]=(byte)0x08;
formulaByte[18]=(byte)0xE0;
@ -109,15 +105,14 @@ public final class TestFormulaRecord extends TestCase {
public void testWithConcat() throws Exception {
// =CHOOSE(2,A2,A3,A4)
byte[] data = new byte[] {
byte[] data = {
6, 0, 68, 0,
1, 0, 1, 0, 15, 0, 0, 0, 0, 0, 0, 0, 57,
64, 0, 0, 12, 0, 12, -4, 46, 0,
30, 2, 0, // Int - 2
25, 4, 3, 0, // Attr
8, 0, // Concat
17, 0, // Range
26, 0, 35, 0, // Bit like an attr
8, 0, 17, 0, 26, 0, // jumpTable
35, 0, // chooseOffset
36, 1, 0, 0, -64, // Ref - A2
25, 8, 21, 0, // Attr
36, 2, 0, 0, -64, // Ref - A3
@ -126,30 +121,24 @@ public final class TestFormulaRecord extends TestCase {
25, 8, 3, 0, // Attr
66, 4, 100, 0 // CHOOSE
};
RecordInputStream inp = new RecordInputStream(
new ByteArrayInputStream(data)
);
RecordInputStream inp = new RecordInputStream( new ByteArrayInputStream(data));
inp.nextRecord();
FormulaRecord fr = new FormulaRecord(inp);
assertEquals(14, fr.getNumberOfExpressionTokens());
assertEquals(IntPtg.class, fr.getParsedExpression().get(0).getClass());
assertEquals(AttrPtg.class, fr.getParsedExpression().get(1).getClass());
assertEquals(ConcatPtg.class, fr.getParsedExpression().get(2).getClass());
assertEquals(UnknownPtg.class, fr.getParsedExpression().get(3).getClass());
assertEquals(RangePtg.class, fr.getParsedExpression().get(4).getClass());
assertEquals(UnknownPtg.class, fr.getParsedExpression().get(5).getClass());
assertEquals(AttrPtg.class, fr.getParsedExpression().get(6).getClass());
assertEquals(ReferencePtg.class, fr.getParsedExpression().get(7).getClass());
assertEquals(AttrPtg.class, fr.getParsedExpression().get(8).getClass());
assertEquals(ReferencePtg.class, fr.getParsedExpression().get(9).getClass());
assertEquals(AttrPtg.class, fr.getParsedExpression().get(10).getClass());
assertEquals(ReferencePtg.class, fr.getParsedExpression().get(11).getClass());
assertEquals(AttrPtg.class, fr.getParsedExpression().get(12).getClass());
assertEquals(FuncVarPtg.class, fr.getParsedExpression().get(13).getClass());
List ptgs = fr.getParsedExpression();
assertEquals(9, ptgs.size());
assertEquals(IntPtg.class, ptgs.get(0).getClass());
assertEquals(AttrPtg.class, ptgs.get(1).getClass());
assertEquals(ReferencePtg.class, ptgs.get(2).getClass());
assertEquals(AttrPtg.class, ptgs.get(3).getClass());
assertEquals(ReferencePtg.class, ptgs.get(4).getClass());
assertEquals(AttrPtg.class, ptgs.get(5).getClass());
assertEquals(ReferencePtg.class, ptgs.get(6).getClass());
assertEquals(AttrPtg.class, ptgs.get(7).getClass());
assertEquals(FuncVarPtg.class, ptgs.get(8).getClass());
FuncVarPtg choose = (FuncVarPtg)fr.getParsedExpression().get(13);
FuncVarPtg choose = (FuncVarPtg)ptgs.get(8);
assertEquals("CHOOSE", choose.getName());
}

View File

@ -0,0 +1,41 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hssf.record;
import org.apache.poi.hssf.HSSFTestDataSamples;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import junit.framework.AssertionFailedError;
import junit.framework.TestCase;
/**
* Tests for <tt>LabelRecord</tt>
*
* @author Josh Micich
*/
public final class TestLabelRecord extends TestCase {
public void testEmptyString() {
HSSFWorkbook wb;
try {
wb = HSSFTestDataSamples.openSampleWorkbook("ex42570-20305.xls");
} catch (NullPointerException e) {
throw new AssertionFailedError("Identified bug 42570");
}
HSSFTestDataSamples.writeOutAndReadBack(wb);
}
}

View File

@ -1,4 +1,3 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
@ -15,34 +14,28 @@
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hssf.record.aggregates;
import org.apache.poi.hssf.record.*;
import junit.framework.TestCase;
public class TestRowRecordsAggregate extends junit.framework.TestCase {
public TestRowRecordsAggregate(String name) {
super (name);
}
import org.apache.poi.hssf.record.RowRecord;
/**
*
*/
public final class TestRowRecordsAggregate extends TestCase {
public void testRowGet() {
RowRecordsAggregate rra = new RowRecordsAggregate();
RowRecord rr = new RowRecord();
rr.setRowNumber(( short ) 4);
RowRecord rr = new RowRecord(4);
rra.insertRow(rr);
RowRecord rr2 = new RowRecord(); rr2.setRowNumber((short) 1);
rra.insertRow(rr2);
rra.insertRow(new RowRecord(1));
RowRecord rr1 = rra.getRow(4);
assertTrue("Row Record should not be null", rr1!=null);
assertTrue("Row number is 1",rr1.getRowNumber() == 4);
assertNotNull(rr1);
assertEquals("Row number is 1", 4, rr1.getRowNumber());
assertTrue("Row record retrieved is identical ", rr1 == rr);
}
public static void main(String [] args) {
System.out
.println("Testing org.apache.poi.hssf.record.aggregates.RowRecordAggregate");
junit.textui.TestRunner.run(TestRowRecordsAggregate.class);
}
}

View File

@ -40,6 +40,7 @@ public final class AllFormulaTests {
result.addTestSuite(TestArea3DPtg.class);
result.addTestSuite(TestAreaErrPtg.class);
result.addTestSuite(TestAreaPtg.class);
result.addTestSuite(TestArrayPtg.class);
result.addTestSuite(TestErrPtg.class);
result.addTestSuite(TestExternalFunctionFormulas.class);
result.addTestSuite(TestFuncPtg.class);

View File

@ -0,0 +1,95 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hssf.record.formula;
import java.util.Arrays;
import org.apache.poi.hssf.record.TestcaseRecordInputStream;
import org.apache.poi.hssf.record.UnicodeString;
import junit.framework.AssertionFailedError;
import junit.framework.TestCase;
/**
* Tests for <tt>ArrayPtg</tt>
*
* @author Josh Micich
*/
public final class TestArrayPtg extends TestCase {
private static final byte[] ENCODED_PTG_DATA = {
0x40, 0x00,
0x08, 0x00,
0, 0, 0, 0, 0, 0, 0, 0,
};
private static final byte[] ENCODED_CONSTANT_DATA = {
2, // 3 columns
1, 0, // 2 rows
4, 1, 0, 0, 0, 0, 0, 0, 0, // TRUE
2, 4, 0, 0, 65, 66, 67, 68, // "ABCD"
2, 1, 0, 0, 69, // "E"
1, 0, 0, 0, 0, 0, 0, 0, 0, // 0
4, 0, 0, 0, 0, 0, 0, 0, 0, // FALSE
2, 2, 0, 0, 70, 71, // "FG"
};
/**
* Lots of problems with ArrayPtg's encoding of
*/
public void testReadWriteTokenValueBytes() {
ArrayPtg ptg = new ArrayPtgV(new TestcaseRecordInputStream(ArrayPtgV.sid, ENCODED_PTG_DATA));
ptg.readTokenValues(new TestcaseRecordInputStream(0, ENCODED_CONSTANT_DATA));
assertEquals(3, ptg.getColumnCount());
assertEquals(2, ptg.getRowCount());
Object[] values = ptg.token_3_arrayValues;
assertEquals(6, values.length);
assertEquals(Boolean.TRUE, values[0]);
assertEquals(new UnicodeString("ABCD"), values[1]);
assertEquals(new Double(0), values[3]);
assertEquals(Boolean.FALSE, values[4]);
assertEquals(new UnicodeString("FG"), values[5]);
byte[] outBuf = new byte[ENCODED_CONSTANT_DATA.length];
ptg.writeTokenValueBytes(outBuf, 0);
if(outBuf[0] == 4) {
throw new AssertionFailedError("Identified bug 42564b");
}
assertTrue(Arrays.equals(ENCODED_CONSTANT_DATA, outBuf));
}
/**
* make sure constant elements are stored row by row
*/
public void testElementOrdering() {
ArrayPtg ptg = new ArrayPtgV(new TestcaseRecordInputStream(ArrayPtgV.sid, ENCODED_PTG_DATA));
ptg.readTokenValues(new TestcaseRecordInputStream(0, ENCODED_CONSTANT_DATA));
assertEquals(3, ptg.getColumnCount());
assertEquals(2, ptg.getRowCount());
assertEquals(0, ptg.getValueIndex(0, 0));
assertEquals(1, ptg.getValueIndex(1, 0));
assertEquals(2, ptg.getValueIndex(2, 0));
assertEquals(3, ptg.getValueIndex(0, 1));
assertEquals(4, ptg.getValueIndex(1, 1));
assertEquals(5, ptg.getValueIndex(2, 1));
}
}

View File

@ -1,4 +1,3 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
@ -26,45 +25,31 @@ import org.apache.poi.hssf.record.TestcaseRecordInputStream;
*
* @author Danny Mui (dmui at apache dot org)
*/
public final class TestFuncPtg extends TestCase {
public class TestFuncPtg extends TestCase
{
public TestFuncPtg( String name )
{
super( name );
}
public static void main( java.lang.String[] args )
{
junit.textui.TestRunner.run( TestFuncPtg.class );
}
/**
* Make sure the left overs are re-serialized on excel file reads to avoid
* the "Warning: Data may have been lost" prompt in excel.
* <p/>
* This ptg represents a LEN function extracted from excel
*/
public void testLeftOvers()
{
byte[] fakeData = new byte[4];
//fakeData[0] = (byte) 0x41;
fakeData[0] = (byte) 0x20; //function index
fakeData[1] = (byte) 0;
fakeData[2] = (byte) 8;
public void testRead() {
// This ptg represents a LEN function extracted from excel
byte[] fakeData = {
0x20, //function index
0,
};
FuncPtg ptg = new FuncPtg( new TestcaseRecordInputStream((short)0, (short)fakeData.length, fakeData) );
assertEquals( "Len formula index is not 32(20H)", (int) 0x20, ptg.getFunctionIndex() );
assertEquals( "Len formula index is not 32(20H)", 0x20, ptg.getFunctionIndex() );
assertEquals( "Number of operands in the len formula", 1, ptg.getNumberOfOperands() );
assertEquals( "Function Name", "LEN", ptg.getName() );
assertEquals( "Ptg Size", 3, ptg.getSize() );
//assertEquals("first leftover byte is not 0", (byte)0, ptg.leftOvers[0]);
//assertEquals("second leftover byte is not 8", (byte)8, ptg.leftOvers[1]);
}
public void testClone() {
FuncPtg funcPtg = new FuncPtg(27); // ROUND() - takes 2 args
FuncPtg clone = (FuncPtg) funcPtg.clone();
if (clone.getNumberOfOperands() == 0) {
fail("clone() did copy field numberOfOperands");
}
assertEquals(2, clone.getNumberOfOperands());
assertEquals("ROUND", clone.getName());
}
}

View File

@ -28,7 +28,8 @@ import junit.framework.TestSuite;
public class AllFormulaEvalTests {
public static Test suite() {
TestSuite result = new TestSuite("Tests for org.apache.poi.hssf.record.formula.eval");
TestSuite result = new TestSuite(AllFormulaEvalTests.class.getName());
result.addTestSuite(TestAreaEval.class);
result.addTestSuite(TestCircularReferences.class);
result.addTestSuite(TestExternalFunction.class);
result.addTestSuite(TestFormulaBugs.class);

View File

@ -0,0 +1,62 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hssf.record.formula.eval;
import junit.framework.AssertionFailedError;
import junit.framework.TestCase;
import org.apache.poi.hssf.record.formula.Area3DPtg;
/**
* Tests for <tt>AreaEval</tt>
*
* @author Josh Micich
*/
public final class TestAreaEval extends TestCase {
public void testGetValue_bug44950() {
Area3DPtg ptg = new Area3DPtg("B2:D3", (short)0);
NumberEval one = new NumberEval(1);
ValueEval[] values = {
one,
new NumberEval(2),
new NumberEval(3),
new NumberEval(4),
new NumberEval(5),
new NumberEval(6),
};
AreaEval ae = new Area3DEval(ptg, values);
if (one == ae.getValueAt(1, 2)) {
throw new AssertionFailedError("Identified bug 44950 a");
}
confirm(1, ae, 1, 1);
confirm(2, ae, 1, 2);
confirm(3, ae, 1, 3);
confirm(4, ae, 2, 1);
confirm(5, ae, 2, 2);
confirm(6, ae, 2, 3);
}
private static void confirm(int expectedValue, AreaEval ae, int row, int col) {
NumberEval v = (NumberEval) ae.getValueAt(row, col);
assertEquals(expectedValue, v.getNumberValue(), 0.0);
}
}

View File

@ -25,6 +25,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
@ -60,7 +61,32 @@ public final class ExcelFileFormatDocFunctionExtractor {
private static final String SOURCE_DOC_FILE_NAME = "excelfileformat.odt";
/**
* For simplicity, the output file is strictly simple ASCII.
* This method detects any unexpected characters.
*/
/* package */ static boolean isSimpleAscii(char c) {
if (c>=0x21 && c<=0x7E) {
// everything from '!' to '~' (includes letters, digits, punctuation
return true;
}
// some specific whitespace chars below 0x21:
switch(c) {
case ' ':
case '\t':
case '\r':
case '\n':
return true;
}
return false;
}
private static final class FunctionData {
// special characters from the ooo document
private static final int CHAR_ELLIPSIS_8230 = 8230;
private static final int CHAR_NDASH_8211 = 8211;
private final int _index;
private final boolean _hasFootnote;
@ -78,10 +104,30 @@ public final class ExcelFileFormatDocFunctionExtractor {
_name = funcName;
_minParams = minParams;
_maxParams = maxParams;
_returnClass = returnClass;
_paramClasses = paramClasses;
_returnClass = convertSpecialChars(returnClass);
_paramClasses = convertSpecialChars(paramClasses);
_isVolatile = isVolatile;
}
private static String convertSpecialChars(String ss) {
StringBuffer sb = new StringBuffer(ss.length() + 4);
for(int i=0; i<ss.length(); i++) {
char c = ss.charAt(i);
if (isSimpleAscii(c)) {
sb.append(c);
continue;
}
switch (c) {
case CHAR_NDASH_8211:
sb.append('-');
continue;
case CHAR_ELLIPSIS_8230:
sb.append("...");
continue;
}
throw new RuntimeException("bad char (" + ((int)c) + ") in string '" + ss + "'");
}
return sb.toString();
}
public int getIndex() {
return _index;
}
@ -354,13 +400,19 @@ public final class ExcelFileFormatDocFunctionExtractor {
}
private static void extractFunctionData(FunctionDataCollector fdc, InputStream is) {
System.setProperty("org.xml.sax.driver", "org.apache.crimson.parser.XMLReaderImpl");
XMLReader xr;
try {
// First up, try the default one
xr = XMLReaderFactory.createXMLReader();
} catch (SAXException e) {
throw new RuntimeException(e);
// Try one for java 1.4
System.setProperty("org.xml.sax.driver", "org.apache.crimson.parser.XMLReaderImpl");
try {
xr = XMLReaderFactory.createXMLReader();
} catch (SAXException e2) {
throw new RuntimeException(e2);
}
}
xr.setContentHandler(new EFFDocHandler(fdc));
@ -375,6 +427,33 @@ public final class ExcelFileFormatDocFunctionExtractor {
throw new RuntimeException(e);
}
}
/**
* To be sure that no tricky unicode chars make it through to the output file.
*/
private static final class SimpleAsciiOutputStream extends OutputStream {
private final OutputStream _os;
public SimpleAsciiOutputStream(OutputStream os) {
_os = os;
}
public void write(int b) throws IOException {
checkByte(b);
_os.write(b);
}
private static void checkByte(int b) {
if (!isSimpleAscii((char)b)) {
throw new RuntimeException("Encountered char (" + b + ") which was not simple ascii as expected");
}
}
public void write(byte[] b, int off, int len) throws IOException {
for (int i = 0; i < len; i++) {
checkByte(b[i + off]);
}
_os.write(b, off, len);
}
}
private static void processFile(File effDocFile, File outFile) {
OutputStream os;
@ -383,7 +462,14 @@ public final class ExcelFileFormatDocFunctionExtractor {
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
PrintStream ps = new PrintStream(os);
os = new SimpleAsciiOutputStream(os);
PrintStream ps;
try {
ps = new PrintStream(os, true, "UTF-8");
} catch(UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
outputLicenseHeader(ps);
Class genClass = ExcelFileFormatDocFunctionExtractor.class;
ps.println("# Created by (" + genClass.getName() + ")");

View File

@ -67,7 +67,7 @@ public final class TestCountFuncs extends TestCase {
args = new Eval[] {
EvalFactory.createAreaEval("D1:F5", 3, 5), // 15
EvalFactory.createRefEval("A1"),
EvalFactory.createAreaEval("A1:F6", 7, 6), // 42
EvalFactory.createAreaEval("A1:G6", 7, 6), // 42
new NumberEval(0),
};
confirmCountA(59, args);
@ -87,7 +87,7 @@ public final class TestCountFuncs extends TestCase {
BoolEval.TRUE,
BlankEval.INSTANCE,
};
range = createAreaEval("A1:B2", values);
range = createAreaEval("A1:B3", values);
confirmCountIf(2, range, BoolEval.TRUE);
// when criteria is numeric
@ -98,9 +98,8 @@ public final class TestCountFuncs extends TestCase {
new NumberEval(2),
new NumberEval(2),
BoolEval.TRUE,
BlankEval.INSTANCE,
};
range = createAreaEval("A1:B2", values);
range = createAreaEval("A1:B3", values);
confirmCountIf(3, range, new NumberEval(2));
// note - same results when criteria is a string that parses as the number with the same value
confirmCountIf(3, range, new StringEval("2.00"));

View File

@ -14,7 +14,6 @@
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hssf.record.formula.functions;
@ -33,10 +32,6 @@ import org.apache.poi.hssf.record.formula.eval.ValueEval;
*/
public final class TestIndex extends TestCase {
public TestIndex(String testName) {
super(testName);
}
private static final double[] TEST_VALUES0 = {
1, 2,
3, 4,
@ -44,7 +39,6 @@ public final class TestIndex extends TestCase {
7, 8,
9, 10,
11, 12,
13, // excess array element. TODO - Area2DEval currently has no validation to ensure correct size of values array
};
/**

View File

@ -38,10 +38,12 @@ public class AllUserModelTests {
result.addTestSuite(TestEscherGraphics2d.class);
result.addTestSuite(TestFontDetails.class);
result.addTestSuite(TestFormulas.class);
result.addTestSuite(TestFormulaEvaluatorBugs.class);
result.addTestSuite(TestFormulaEvaluatorDocs.class);
result.addTestSuite(TestHSSFCell.class);
result.addTestSuite(TestHSSFClientAnchor.class);
result.addTestSuite(TestHSSFConditionalFormatting.class);
result.addTestSuite(TestHSSFComment.class);
result.addTestSuite(TestHSSFConditionalFormatting.class);
result.addTestSuite(TestHSSFDateUtil.class);
result.addTestSuite(TestHSSFHeaderFooter.class);
result.addTestSuite(TestHSSFHyperlink.class);
@ -54,17 +56,19 @@ public class AllUserModelTests {
result.addTestSuite(TestHSSFSheet.class);
result.addTestSuite(TestHSSFSheetOrder.class);
result.addTestSuite(TestHSSFSheetSetOrder.class);
result.addTestSuite(TestHSSFTextbox.class);
result.addTestSuite(TestHSSFWorkbook.class);
result.addTestSuite(TestNamedRange.class);
result.addTestSuite(TestOLE2Embeding.class);
result.addTestSuite(TestPOIFSProperties.class);
result.addTestSuite(TestReadWriteChart.class);
result.addTestSuite(TestSanityChecker.class);
result.addTestSuite(TestSheetHiding.class);
result.addTestSuite(TestSheetShiftRows.class);
if (false) { // deliberately avoiding this one
result.addTestSuite(TestUnfixedBugs.class);
}
result.addTestSuite(TestUnicodeWorkbook.class);
result.addTestSuite(TestUnfixedBugs.class);
}
result.addTestSuite(TestUnicodeWorkbook.class);
result.addTestSuite(TestUppercaseWorkbook.class);
result.addTestSuite(TestWorkbook.class);

View File

@ -17,17 +17,18 @@
package org.apache.poi.hssf.usermodel;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Iterator;
import junit.framework.AssertionFailedError;
import junit.framework.TestCase;
import org.apache.poi.hssf.HSSFTestDataSamples;
import org.apache.poi.hssf.record.RecordFormatException;
import org.apache.poi.hssf.util.Region;
import org.apache.poi.util.TempFile;
import java.io.*;
import java.util.Iterator;
/**
* Testcases for bugs entered in bugzilla
* the Test name contains the bugzilla bug id
@ -80,13 +81,7 @@ public final class TestBugs extends TestCase {
HSSFRow r = s.createRow(0);
HSSFCell c = r.createCell((short)0);
c.setCellValue(10);
try {
writeOutAndReadBack(wb);
} catch (RecordFormatException e) {
if (false) { // TODO (Apr-2008) this file does not read back ok. create bugzilla bug & fix.
throw new AssertionFailedError("Identified bug XXXX");
}
}
writeOutAndReadBack(wb);
}
/**Test writing a hyperlink
* Open resulting sheet in Excel and check that A1 contains a hyperlink*/
@ -732,7 +727,7 @@ public final class TestBugs extends TestCase {
* with the NameRecord, once you get past the BOFRecord
* issue.
*/
public void DISABLEDtest42564Alt() {
public void test42564Alt() {
HSSFWorkbook wb = openSample("42564-2.xls");
writeOutAndReadBack(wb);
}
@ -757,9 +752,13 @@ public final class TestBugs extends TestCase {
HSSFCell c2 = r2.getCell((short)1);
assertEquals(25, (int)c2.getNumericCellValue());
if (false) { // TODO (Apr-2008) This will blow up with IllegalStateException (stack underflow)
// excel function "CHOOSE" probably needs some special handling in FormulaParser.toFormulaString()
assertEquals("=CHOOSE(2,A2,A3,A4)", c2.getCellFormula());
try {
assertEquals("CHOOSE(2,A2,A3,A4)", c2.getCellFormula());
} catch (IllegalStateException e) {
if (e.getMessage().startsWith("Too few arguments")
&& e.getMessage().indexOf("ConcatPtg") > 0) {
throw new AssertionFailedError("identified bug 44306");
}
}
}
@ -887,13 +886,66 @@ public final class TestBugs extends TestCase {
writeOutAndReadBack(wb);
assertTrue("no errors writing sample xls", true);
}
/**
* Had a problem apparently, not sure what as it
* works just fine...
*/
public void test44891() throws Exception {
HSSFWorkbook wb = openSample("44891.xls");
HSSFWorkbook wb = openSample("44891.xls");
assertTrue("no errors reading sample xls", true);
writeOutAndReadBack(wb);
assertTrue("no errors writing sample xls", true);
}
/**
* Bug 44235: Ms Excel can't open save as excel file
*
* Works fine with poi-3.1-beta1.
*/
public void test44235() throws Exception {
HSSFWorkbook wb = openSample("44235.xls");
assertTrue("no errors reading sample xls", true);
writeOutAndReadBack(wb);
assertTrue("no errors writing sample xls", true);
}
/**
* Bug 21334: "File error: data may have been lost" with a file
* that contains macros and this formula:
* {=SUM(IF(FREQUENCY(IF(LEN(V4:V220)>0,MATCH(V4:V220,V4:V220,0),""),IF(LEN(V4:V220)>0,MATCH(V4:V220,V4:V220,0),""))>0,1))}
*/
public void test21334() {
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet sh = wb.createSheet();
HSSFCell cell = sh.createRow(0).createCell((short)0);
String formula = "SUM(IF(FREQUENCY(IF(LEN(V4:V220)>0,MATCH(V4:V220,V4:V220,0),\"\"),IF(LEN(V4:V220)>0,MATCH(V4:V220,V4:V220,0),\"\"))>0,1))";
cell.setCellFormula(formula);
HSSFWorkbook wb_sv = writeOutAndReadBack(wb);
HSSFCell cell_sv = wb_sv.getSheetAt(0).getRow(0).getCell((short)0);
assertEquals(formula, cell_sv.getCellFormula());
}
public void test36947() throws Exception {
HSSFWorkbook wb = openSample("36947.xls");
assertTrue("no errors reading sample xls", true);
writeOutAndReadBack(wb);
assertTrue("no errors writing sample xls", true);
}
/**
* Bug 42448: Can't parse SUMPRODUCT(A!C7:A!C67, B8:B68) / B69
*/
public void test42448(){
HSSFWorkbook wb = new HSSFWorkbook();
HSSFCell cell = wb.createSheet().createRow(0).createCell((short)0);
cell.setCellFormula("SUMPRODUCT(A!C7:A!C67, B8:B68) / B69");
assertTrue("no errors parsing formula", true);
}
public void test39634() throws Exception {
HSSFWorkbook wb = openSample("39634.xls");
assertTrue("no errors reading sample xls", true);
writeOutAndReadBack(wb);
assertTrue("no errors writing sample xls", true);

View File

@ -22,12 +22,14 @@ import java.io.FileOutputStream;
import java.util.Iterator;
import java.util.List;
import junit.framework.AssertionFailedError;
import junit.framework.TestCase;
import org.apache.poi.hssf.HSSFTestDataSamples;
import org.apache.poi.hssf.record.aggregates.FormulaRecordAggregate;
import org.apache.poi.hssf.record.formula.AreaPtg;
import org.apache.poi.hssf.record.formula.FuncVarPtg;
/**
*
*/
@ -51,42 +53,41 @@ public final class TestFormulaEvaluatorBugs extends TestCase {
*/
public void test44636() throws Exception {
// Open the existing file, tweak one value and
// re-calculate
// re-calculate
HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("44636.xls");
HSSFSheet sheet = wb.getSheetAt (0);
HSSFRow row = sheet.getRow (0);
HSSFSheet sheet = wb.getSheetAt(0);
HSSFRow row = sheet.getRow(0);
row.getCell((short)0).setCellValue(4.2);
row.getCell((short)2).setCellValue(25);
row.getCell((short) 0).setCellValue(4.2);
row.getCell((short) 2).setCellValue(25);
HSSFFormulaEvaluator.evaluateAllFormulaCells(wb);
assertEquals(4.2*25, row.getCell((short)3).getNumericCellValue(), 0.0001);
assertEquals(4.2 * 25, row.getCell((short) 3).getNumericCellValue(), 0.0001);
// Save
File existing = new File(tmpDirName,"44636-existing.xls");
File existing = new File(tmpDirName, "44636-existing.xls");
FileOutputStream out = new FileOutputStream(existing);
wb.write(out);
out.close();
System.err.println("Existing file for bug #44636 written to " + existing.toString());
// Now, do a new file from scratch
wb = new HSSFWorkbook();
sheet = wb.createSheet();
row = sheet.createRow(0);
row.createCell((short)0).setCellValue(1.2);
row.createCell((short)1).setCellValue(4.2);
row.createCell((short) 0).setCellValue(1.2);
row.createCell((short) 1).setCellValue(4.2);
row = sheet.createRow(1);
row.createCell((short)0).setCellFormula("SUM(A1:B1)");
row.createCell((short) 0).setCellFormula("SUM(A1:B1)");
HSSFFormulaEvaluator.evaluateAllFormulaCells(wb);
assertEquals(5.4, row.getCell((short)0).getNumericCellValue(), 0.0001);
assertEquals(5.4, row.getCell((short) 0).getNumericCellValue(), 0.0001);
// Save
File scratch = new File(tmpDirName,"44636-scratch.xls");
File scratch = new File(tmpDirName, "44636-scratch.xls");
out = new FileOutputStream(scratch);
wb.write(out);
out.close();
@ -105,62 +106,62 @@ public final class TestFormulaEvaluatorBugs extends TestCase {
HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("44297.xls");
HSSFRow row;
HSSFCell cell;
HSSFCell cell;
HSSFSheet sheet = wb.getSheetAt(0);
HSSFSheet sheet = wb.getSheetAt(0);
HSSFFormulaEvaluator eva = new HSSFFormulaEvaluator(sheet, wb);
row = sheet.getRow(0);
cell = row.getCell((short)0);
cell = row.getCell((short) 0);
assertEquals("31+46", cell.getCellFormula());
eva.setCurrentRow(row);
assertEquals(77, eva.evaluate(cell).getNumberValue(), 0);
row = sheet.getRow(1);
cell = row.getCell((short)0);
cell = row.getCell((short) 0);
assertEquals("30+53", cell.getCellFormula());
eva.setCurrentRow(row);
assertEquals(83, eva.evaluate(cell).getNumberValue(), 0);
row = sheet.getRow(2);
cell = row.getCell((short)0);
cell = row.getCell((short) 0);
assertEquals("SUM(A1:A2)", cell.getCellFormula());
eva.setCurrentRow(row);
assertEquals(160, eva.evaluate(cell).getNumberValue(), 0);
row = sheet.getRow(4);
cell = row.getCell((short)0);
cell = row.getCell((short) 0);
assertEquals("32767+32768", cell.getCellFormula());
eva.setCurrentRow(row);
assertEquals(65535, eva.evaluate(cell).getNumberValue(), 0);
row = sheet.getRow(7);
cell = row.getCell((short)0);
cell = row.getCell((short) 0);
assertEquals("32744+42333", cell.getCellFormula());
eva.setCurrentRow(row);
assertEquals(75077, eva.evaluate(cell).getNumberValue(), 0);
row = sheet.getRow(8);
cell = row.getCell((short)0);
cell = row.getCell((short) 0);
assertEquals("327680.0/32768", cell.getCellFormula());
eva.setCurrentRow(row);
assertEquals(10, eva.evaluate(cell).getNumberValue(), 0);
row = sheet.getRow(9);
cell = row.getCell((short)0);
cell = row.getCell((short) 0);
assertEquals("32767+32769", cell.getCellFormula());
eva.setCurrentRow(row);
assertEquals(65536, eva.evaluate(cell).getNumberValue(), 0);
row = sheet.getRow(10);
cell = row.getCell((short)0);
cell = row.getCell((short) 0);
assertEquals("35000+36000", cell.getCellFormula());
eva.setCurrentRow(row);
assertEquals(71000, eva.evaluate(cell).getNumberValue(), 0);
row = sheet.getRow(11);
cell = row.getCell((short)0);
cell = row.getCell((short) 0);
assertEquals("-1000000.0-3000000.0", cell.getCellFormula());
eva.setCurrentRow(row);
assertEquals(-4000000, eva.evaluate(cell).getNumberValue(), 0);
@ -176,30 +177,29 @@ public final class TestFormulaEvaluatorBugs extends TestCase {
HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("SingleLetterRanges.xls");
HSSFSheet sheet = wb.getSheetAt(0);
HSSFSheet sheet = wb.getSheetAt(0);
HSSFFormulaEvaluator eva = new HSSFFormulaEvaluator(sheet, wb);
// =index(C:C,2,1) -> 2
// =index(C:C,2,1) -> 2
HSSFRow rowIDX = sheet.getRow(3);
// =sum(C:C) -> 6
// =sum(C:C) -> 6
HSSFRow rowSUM = sheet.getRow(4);
// =sum(C:D) -> 66
// =sum(C:D) -> 66
HSSFRow rowSUM2D = sheet.getRow(5);
// Test the sum
HSSFCell cellSUM = rowSUM.getCell((short)0);
HSSFCell cellSUM = rowSUM.getCell((short) 0);
FormulaRecordAggregate frec =
(FormulaRecordAggregate)cellSUM.getCellValueRecord();
FormulaRecordAggregate frec = (FormulaRecordAggregate) cellSUM.getCellValueRecord();
List ops = frec.getFormulaRecord().getParsedExpression();
assertEquals(2, ops.size());
assertEquals(AreaPtg.class, ops.get(0).getClass());
assertEquals(FuncVarPtg.class, ops.get(1).getClass());
// Actually stored as C1 to C65536
// (last row is -1 === 65535)
AreaPtg ptg = (AreaPtg)ops.get(0);
// Actually stored as C1 to C65536
// (last row is -1 === 65535)
AreaPtg ptg = (AreaPtg) ops.get(0);
assertEquals(2, ptg.getFirstColumn());
assertEquals(2, ptg.getLastColumn());
assertEquals(0, ptg.getFirstRow());
@ -207,26 +207,25 @@ public final class TestFormulaEvaluatorBugs extends TestCase {
assertEquals("C:C", ptg.toFormulaString(wb));
// Will show as C:C, but won't know how many
// rows it covers as we don't have the sheet
// to hand when turning the Ptgs into a string
// rows it covers as we don't have the sheet
// to hand when turning the Ptgs into a string
assertEquals("SUM(C:C)", cellSUM.getCellFormula());
eva.setCurrentRow(rowSUM);
// But the evaluator knows the sheet, so it
// can do it properly
// can do it properly
assertEquals(6, eva.evaluate(cellSUM).getNumberValue(), 0);
// Test the index
// Again, the formula string will be right but
// lacking row count, evaluated will be right
HSSFCell cellIDX = rowIDX.getCell((short)0);
// lacking row count, evaluated will be right
HSSFCell cellIDX = rowIDX.getCell((short) 0);
assertEquals("INDEX(C:C,2,1)", cellIDX.getCellFormula());
eva.setCurrentRow(rowIDX);
assertEquals(2, eva.evaluate(cellIDX).getNumberValue(), 0);
// Across two colums
HSSFCell cellSUM2D = rowSUM2D.getCell((short)0);
HSSFCell cellSUM2D = rowSUM2D.getCell((short) 0);
assertEquals("SUM(C:D)", cellSUM2D.getCellFormula());
eva.setCurrentRow(rowSUM2D);
assertEquals(66, eva.evaluate(cellSUM2D).getNumberValue(), 0);
@ -240,7 +239,7 @@ public final class TestFormulaEvaluatorBugs extends TestCase {
HSSFSheet sheet = wb.createSheet();
wb.setSheetName(0, "Sheet1");
HSSFRow row = sheet.createRow(0);
HSSFCell cell = row.createCell((short)0);
HSSFCell cell = row.createCell((short) 0);
cell.setCellFormula("1=1");
@ -253,29 +252,46 @@ public final class TestFormulaEvaluatorBugs extends TestCase {
}
assertEquals(true, cell.getBooleanCellValue());
}
public void testClassCast_bug44861() throws Exception {
HSSFWorkbook wb = HSSFTestDataSamples.
openSampleWorkbook("44861.xls");
HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("44861.xls");
// Check direct
HSSFFormulaEvaluator.evaluateAllFormulaCells(wb);
// And via calls
int numSheets = wb.getNumberOfSheets();
for(int i=0; i<numSheets; i++) {
for (int i = 0; i < numSheets; i++) {
HSSFSheet s = wb.getSheetAt(i);
HSSFFormulaEvaluator eval = new HSSFFormulaEvaluator(s,wb);
for(Iterator rows = s.rowIterator(); rows.hasNext();) {
HSSFRow r = (HSSFRow)rows.next();
eval.setCurrentRow(r);
for(Iterator cells = r.cellIterator(); cells.hasNext();) {
HSSFCell c = (HSSFCell)cells.next();
eval.evaluateFormulaCell(c);
}
HSSFFormulaEvaluator eval = new HSSFFormulaEvaluator(s, wb);
for (Iterator rows = s.rowIterator(); rows.hasNext();) {
HSSFRow r = (HSSFRow) rows.next();
eval.setCurrentRow(r);
for (Iterator cells = r.cellIterator(); cells.hasNext();) {
HSSFCell c = (HSSFCell) cells.next();
eval.evaluateFormulaCell(c);
}
}
}
}
public void testEvaluateInCellWithErrorCode_bug44950() {
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet sheet = wb.createSheet("Sheet1");
HSSFRow row = sheet.createRow(1);
HSSFCell cell = row.createCell((short) 0);
cell.setCellFormula("na()"); // this formula evaluates to an Excel error code '#N/A'
HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(sheet, wb);
fe.setCurrentRow(row);
try {
fe.evaluateInCell(cell);
} catch (NumberFormatException e) {
if (e.getMessage().equals("You cannot get an error value from a non-error cell")) {
throw new AssertionFailedError("Identified bug 44950 b");
}
throw e;
}
}
}

View File

@ -17,11 +17,10 @@
package org.apache.poi.hssf.usermodel;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import junit.framework.TestCase;
import org.apache.poi.hssf.HSSFTestDataSamples;
/**
* Test HSSFRow is okay.
*
@ -32,7 +31,7 @@ public final class TestHSSFRow extends TestCase {
public void testLastAndFirstColumns() {
HSSFWorkbook workbook = new HSSFWorkbook();
HSSFSheet sheet = workbook.createSheet();
HSSFRow row = sheet.createRow((short) 0);
HSSFRow row = sheet.createRow(0);
assertEquals(-1, row.getFirstCellNum());
assertEquals(-1, row.getLastCellNum());
@ -50,7 +49,35 @@ public final class TestHSSFRow extends TestCase {
assertEquals(4, row.getLastCellNum());
}
public void testRemoveCell() throws Exception {
/**
* Make sure that there is no cross-talk between rows especially with getFirstCellNum and getLastCellNum
* This test was added in response to bug report 44987.
*/
public void testBoundsInMultipleRows() {
HSSFWorkbook workbook = new HSSFWorkbook();
HSSFSheet sheet = workbook.createSheet();
HSSFRow rowA = sheet.createRow(0);
rowA.createCell((short) 10);
rowA.createCell((short) 5);
assertEquals(5, rowA.getFirstCellNum());
assertEquals(11, rowA.getLastCellNum());
HSSFRow rowB = sheet.createRow(1);
rowB.createCell((short) 15);
rowB.createCell((short) 30);
assertEquals(15, rowB.getFirstCellNum());
assertEquals(31, rowB.getLastCellNum());
assertEquals(5, rowA.getFirstCellNum());
assertEquals(11, rowA.getLastCellNum());
rowA.createCell((short) 50);
assertEquals(51, rowA.getLastCellNum());
assertEquals(31, rowB.getLastCellNum());
}
public void testRemoveCell() {
HSSFWorkbook workbook = new HSSFWorkbook();
HSSFSheet sheet = workbook.createSheet();
HSSFRow row = sheet.createRow((short) 0);
@ -76,16 +103,11 @@ public final class TestHSSFRow extends TestCase {
assertEquals(0, data[6]);
assertEquals(0, data[8]);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
workbook.write(baos);
baos.close();
ByteArrayInputStream inputStream = new ByteArrayInputStream(baos.toByteArray());
workbook = new HSSFWorkbook(inputStream);
workbook = HSSFTestDataSamples.writeOutAndReadBack(workbook);
sheet = workbook.getSheetAt(0);
inputStream.close();
assertEquals(-1, sheet.getRow((short) 0).getLastCellNum());
assertEquals(-1, sheet.getRow((short) 0).getFirstCellNum());
assertEquals(-1, sheet.getRow(0).getLastCellNum());
assertEquals(-1, sheet.getRow(0).getFirstCellNum());
}
public void testMoveCell() {
@ -143,8 +165,9 @@ public final class TestHSSFRow extends TestCase {
try {
sheet.createRow(-1);
fail("IndexOutOfBoundsException should have been thrown");
} catch (IndexOutOfBoundsException ex) {
} catch (IllegalArgumentException e) {
// expected during successful test
assertEquals("Invalid row number (-1) outside allowable range (0..65535)", e.getMessage());
}
//Test high row bound
@ -153,8 +176,9 @@ public final class TestHSSFRow extends TestCase {
try {
sheet.createRow(65536);
fail("IndexOutOfBoundsException should have been thrown");
} catch (IndexOutOfBoundsException ex) {
} catch (IllegalArgumentException e) {
// expected during successful test
assertEquals("Invalid row number (65536) outside allowable range (0..65535)", e.getMessage());
}
}

View File

@ -23,6 +23,7 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import junit.framework.AssertionFailedError;
import junit.framework.TestCase;
import org.apache.poi.hssf.HSSFTestDataSamples;
@ -193,17 +194,29 @@ public final class TestHSSFSheet extends TestCase {
public void testCloneSheet() {
HSSFWorkbook workbook = new HSSFWorkbook();
HSSFSheet sheet = workbook.createSheet("Test Clone");
HSSFRow row = sheet.createRow((short) 0);
HSSFRow row = sheet.createRow(0);
HSSFCell cell = row.createCell((short) 0);
cell.setCellValue("clone_test");
HSSFSheet cloned = workbook.cloneSheet(0);
HSSFCell cell2 = row.createCell((short) 1);
cell.setCellValue(new HSSFRichTextString("clone_test"));
cell2.setCellFormula("sin(1)");
HSSFSheet clonedSheet = workbook.cloneSheet(0);
HSSFRow clonedRow = clonedSheet.getRow(0);
//Check for a good clone
assertEquals(cloned.getRow((short)0).getCell((short)0).getStringCellValue(), "clone_test");
assertEquals(clonedRow.getCell(0).getRichStringCellValue().getString(), "clone_test");
//Check that the cells are not somehow linked
cell.setCellValue("Difference Check");
assertEquals(cloned.getRow((short)0).getCell((short)0).getStringCellValue(), "clone_test");
cell.setCellValue(new HSSFRichTextString("Difference Check"));
cell2.setCellFormula("cos(2)");
if ("Difference Check".equals(clonedRow.getCell(0).getRichStringCellValue().getString())) {
fail("string cell not properly cloned");
}
if ("COS(2)".equals(clonedRow.getCell(1).getCellFormula())) {
fail("formula cell not properly cloned");
}
assertEquals(clonedRow.getCell(0).getRichStringCellValue().getString(), "clone_test");
assertEquals(clonedRow.getCell(1).getCellFormula(), "SIN(1)");
}
/** tests that the sheet name for multiple clones of the same sheet is unique
@ -214,7 +227,7 @@ public final class TestHSSFSheet extends TestCase {
HSSFSheet sheet = workbook.createSheet("Test Clone");
HSSFRow row = sheet.createRow((short) 0);
HSSFCell cell = row.createCell((short) 0);
cell.setCellValue("clone_test");
cell.setCellValue(new HSSFRichTextString("clone_test"));
//Clone the sheet multiple times
workbook.cloneSheet(0);
workbook.cloneSheet(0);
@ -517,11 +530,11 @@ public final class TestHSSFSheet extends TestCase {
HSSFSheet sheet = wb.createSheet();
HSSFRow row = sheet.createRow(0);
HSSFCell cell = row.createCell((short)0);
cell.setCellValue("first row, first cell");
cell.setCellValue(new HSSFRichTextString("first row, first cell"));
row = sheet.createRow(1);
cell = row.createCell((short)1);
cell.setCellValue("second row, second cell");
cell.setCellValue(new HSSFRichTextString("second row, second cell"));
Region region = new Region(1, (short)0, 1, (short)1);
sheet.addMergedRegion(region);
@ -643,28 +656,28 @@ public final class TestHSSFSheet extends TestCase {
/** cell with formula becomes null on cloning a sheet*/
public void test35084() {
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet s =wb.createSheet("Sheet1");
HSSFRow r = s.createRow(0);
r.createCell((short)0).setCellValue(1);
r.createCell((short)1).setCellFormula("A1*2");
HSSFSheet s1 = wb.cloneSheet(0);
r=s1.getRow(0);
assertEquals("double" ,r.getCell((short)0).getNumericCellValue(),(double)1,0); //sanity check
assertNotNull(r.getCell((short)1));
assertEquals("formula", r.getCell((short)1).getCellFormula(), "A1*2");
}
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet s = wb.createSheet("Sheet1");
HSSFRow r = s.createRow(0);
r.createCell((short) 0).setCellValue(1);
r.createCell((short) 1).setCellFormula("A1*2");
HSSFSheet s1 = wb.cloneSheet(0);
r = s1.getRow(0);
assertEquals("double", r.getCell((short) 0).getNumericCellValue(), 1, 0); // sanity check
assertNotNull(r.getCell((short) 1));
assertEquals("formula", r.getCell((short) 1).getCellFormula(), "A1*2");
}
/** test that new default column styles get applied */
public void testDefaultColumnStyle() {
HSSFWorkbook wb = new HSSFWorkbook();
HSSFCellStyle style = wb.createCellStyle();
HSSFSheet s = wb.createSheet();
s.setDefaultColumnStyle((short)0, style);
HSSFRow r = s.createRow(0);
HSSFCell c = r.createCell((short)0);
assertEquals("style should match", style.getIndex(), c.getCellStyle().getIndex());
HSSFWorkbook wb = new HSSFWorkbook();
HSSFCellStyle style = wb.createCellStyle();
HSSFSheet s = wb.createSheet();
s.setDefaultColumnStyle((short) 0, style);
HSSFRow r = s.createRow(0);
HSSFCell c = r.createCell((short) 0);
assertEquals("style should match", style.getIndex(), c.getCellStyle().getIndex());
}
@ -814,11 +827,6 @@ public final class TestHSSFSheet extends TestCase {
assertTrue(wb3.getSheetAt(3).getForceFormulaRecalculation());
}
public static void main(java.lang.String[] args) {
junit.textui.TestRunner.run(TestHSSFSheet.class);
}
public void testColumnWidth() throws Exception {
//check we can correctly read column widths from a reference workbook
HSSFWorkbook wb = openSample("colwidth.xls");
@ -870,11 +878,33 @@ public final class TestHSSFSheet extends TestCase {
assertEquals(256*10, sh.getColumnWidth((short)0));
assertEquals(256*10, sh.getColumnWidth((short)1));
assertEquals(256*10, sh.getColumnWidth((short)2));
//columns D-F have custom wodth
//columns D-F have custom width
for (char i = 'D'; i <= 'F'; i++) {
short w = (short)(256*12);
assertEquals(w, sh.getColumnWidth((short)i));
}
}
/**
* Some utilities write Excel files without the ROW records.
* Excel, ooo, and google docs are OK with this.
* Now POI is too.
*/
public void testMissingRowRecords_bug41187() {
HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("ex41187-19267.xls");
HSSFSheet sheet = wb.getSheetAt(0);
HSSFRow row = sheet.getRow(0);
if(row == null) {
throw new AssertionFailedError("Identified bug 41187 a");
}
if (row.getHeight() == 0) {
throw new AssertionFailedError("Identified bug 41187 b");
}
assertEquals("Hi Excel!", row.getCell(0).getRichStringCellValue().getString());
// check row height for 'default' flag
assertEquals((short)0x8000, row.getHeight());
HSSFTestDataSamples.writeOutAndReadBack(wb);
}
}

View File

@ -17,13 +17,18 @@
package org.apache.poi.hssf.usermodel;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import junit.framework.AssertionFailedError;
import junit.framework.TestCase;
import org.apache.poi.hssf.HSSFTestDataSamples;
import org.apache.poi.hssf.record.NameRecord;
import org.apache.poi.util.TempFile;
/**
*
*
*/
public final class TestHSSFWorkbook extends TestCase {
private static HSSFWorkbook openSample(String sampleFileName) {
@ -93,7 +98,7 @@ public final class TestHSSFWorkbook extends TestCase {
b.setSheetName( 3, "name2" );
b.setSheetName( 3, "name2" );
b.setSheetName( 3, "name2" );
HSSFWorkbook c = new HSSFWorkbook( );
c.createSheet("Sheet1");
c.createSheet("Sheet2");
@ -101,109 +106,274 @@ public final class TestHSSFWorkbook extends TestCase {
c.createSheet("Sheet4");
}
public void testWindowOneDefaults() {
HSSFWorkbook b = new HSSFWorkbook( );
try {
assertEquals(b.getSelectedTab(), 0);
assertEquals(b.getDisplayedTab(), 0);
assertEquals(b.getActiveSheetIndex(), 0);
assertEquals(b.getFirstVisibleTab(), 0);
} catch (NullPointerException npe) {
fail("WindowOneRecord in Workbook is probably not initialized");
}
}
public void testSheetSelection() {
HSSFWorkbook b = new HSSFWorkbook();
b.createSheet("Sheet One");
b.createSheet("Sheet Two");
b.setSelectedTab((short) 1);
b.setDisplayedTab((short) 1);
assertEquals(b.getSelectedTab(), 1);
assertEquals(b.getDisplayedTab(), 1);
b.setActiveSheet(1);
b.setSelectedTab(1);
b.setFirstVisibleTab(1);
assertEquals(1, b.getActiveSheetIndex());
assertEquals(1, b.getFirstVisibleTab());
}
public void testSheetClone() {
// First up, try a simple file
HSSFWorkbook b = new HSSFWorkbook();
assertEquals(0, b.getNumberOfSheets());
b.createSheet("Sheet One");
b.createSheet("Sheet Two");
assertEquals(2, b.getNumberOfSheets());
b.cloneSheet(0);
assertEquals(3, b.getNumberOfSheets());
// Now try a problem one with drawing records in it
b = openSample("SheetWithDrawing.xls");
assertEquals(1, b.getNumberOfSheets());
b.cloneSheet(0);
assertEquals(2, b.getNumberOfSheets());
}
public void testReadWriteWithCharts() {
HSSFWorkbook b;
HSSFSheet s;
// Single chart, two sheets
b = openSample("44010-SingleChart.xls");
assertEquals(2, b.getNumberOfSheets());
assertEquals("Graph2", b.getSheetName(1));
s = b.getSheetAt(1);
assertEquals(0, s.getFirstRowNum());
assertEquals(0, s.getLastRowNum());
assertEquals(8, s.getLastRowNum());
// Has chart on 1st sheet??
// FIXME
assertNotNull(b.getSheetAt(0).getDrawingPatriarch());
assertNull(b.getSheetAt(1).getDrawingPatriarch());
assertFalse(b.getSheetAt(0).getDrawingPatriarch().containsChart());
// We've now called getDrawingPatriarch() so
// We've now called getDrawingPatriarch() so
// everything will be all screwy
// So, start again
b = openSample("44010-SingleChart.xls");
b = writeRead(b);
assertEquals(2, b.getNumberOfSheets());
s = b.getSheetAt(1);
assertEquals(0, s.getFirstRowNum());
assertEquals(0, s.getLastRowNum());
assertEquals(8, s.getLastRowNum());
// Two charts, three sheets
b = openSample("44010-TwoCharts.xls");
assertEquals(3, b.getNumberOfSheets());
s = b.getSheetAt(1);
assertEquals(0, s.getFirstRowNum());
assertEquals(0, s.getLastRowNum());
assertEquals(8, s.getLastRowNum());
s = b.getSheetAt(2);
assertEquals(0, s.getFirstRowNum());
assertEquals(0, s.getLastRowNum());
assertEquals(8, s.getLastRowNum());
// Has chart on 1st sheet??
// FIXME
assertNotNull(b.getSheetAt(0).getDrawingPatriarch());
assertNull(b.getSheetAt(1).getDrawingPatriarch());
assertNull(b.getSheetAt(2).getDrawingPatriarch());
assertFalse(b.getSheetAt(0).getDrawingPatriarch().containsChart());
// We've now called getDrawingPatriarch() so
// We've now called getDrawingPatriarch() so
// everything will be all screwy
// So, start again
b = openSample("44010-TwoCharts.xls");
b = writeRead(b);
assertEquals(3, b.getNumberOfSheets());
s = b.getSheetAt(1);
assertEquals(0, s.getFirstRowNum());
assertEquals(0, s.getLastRowNum());
assertEquals(8, s.getLastRowNum());
s = b.getSheetAt(2);
assertEquals(0, s.getFirstRowNum());
assertEquals(0, s.getLastRowNum());
assertEquals(8, s.getLastRowNum());
}
private static HSSFWorkbook writeRead(HSSFWorkbook b) {
return HSSFTestDataSamples.writeOutAndReadBack(b);
return HSSFTestDataSamples.writeOutAndReadBack(b);
}
}
public void testSelectedSheet_bug44523() {
HSSFWorkbook wb=new HSSFWorkbook();
HSSFSheet sheet1 = wb.createSheet("Sheet1");
HSSFSheet sheet2 = wb.createSheet("Sheet2");
HSSFSheet sheet3 = wb.createSheet("Sheet3");
HSSFSheet sheet4 = wb.createSheet("Sheet4");
confirmActiveSelected(sheet1, true);
confirmActiveSelected(sheet2, false);
confirmActiveSelected(sheet3, false);
confirmActiveSelected(sheet4, false);
wb.setSelectedTab(1);
// Demonstrate bug 44525:
// Well... not quite, since isActive + isSelected were also added in the same bug fix
if (sheet1.isSelected()) {
throw new AssertionFailedError("Identified bug 44523 a");
}
wb.setActiveSheet(1);
if (sheet1.isActive()) {
throw new AssertionFailedError("Identified bug 44523 b");
}
confirmActiveSelected(sheet1, false);
confirmActiveSelected(sheet2, true);
confirmActiveSelected(sheet3, false);
confirmActiveSelected(sheet4, false);
}
public void testSelectMultiple() {
HSSFWorkbook wb=new HSSFWorkbook();
HSSFSheet sheet1 = wb.createSheet("Sheet1");
HSSFSheet sheet2 = wb.createSheet("Sheet2");
HSSFSheet sheet3 = wb.createSheet("Sheet3");
HSSFSheet sheet4 = wb.createSheet("Sheet4");
HSSFSheet sheet5 = wb.createSheet("Sheet5");
HSSFSheet sheet6 = wb.createSheet("Sheet6");
wb.setSelectedTabs(new int[] { 0, 2, 3});
assertEquals(true, sheet1.isSelected());
assertEquals(false, sheet2.isSelected());
assertEquals(true, sheet3.isSelected());
assertEquals(true, sheet4.isSelected());
assertEquals(false, sheet5.isSelected());
assertEquals(false, sheet6.isSelected());
wb.setSelectedTabs(new int[] { 1, 3, 5});
assertEquals(false, sheet1.isSelected());
assertEquals(true, sheet2.isSelected());
assertEquals(false, sheet3.isSelected());
assertEquals(true, sheet4.isSelected());
assertEquals(false, sheet5.isSelected());
assertEquals(true, sheet6.isSelected());
assertEquals(true, sheet1.isActive());
assertEquals(false, sheet2.isActive());
assertEquals(true, sheet1.isActive());
assertEquals(false, sheet3.isActive());
wb.setActiveSheet(2);
assertEquals(false, sheet1.isActive());
assertEquals(true, sheet3.isActive());
if (false) { // helpful if viewing this workbook in excel:
sheet1.createRow(0).createCell((short)0).setCellValue(new HSSFRichTextString("Sheet1"));
sheet2.createRow(0).createCell((short)0).setCellValue(new HSSFRichTextString("Sheet2"));
sheet3.createRow(0).createCell((short)0).setCellValue(new HSSFRichTextString("Sheet3"));
sheet4.createRow(0).createCell((short)0).setCellValue(new HSSFRichTextString("Sheet4"));
try {
File fOut = TempFile.createTempFile("sheetMultiSelect", ".xls");
FileOutputStream os = new FileOutputStream(fOut);
wb.write(os);
os.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
public void testActiveSheetAfterDelete_bug40414() {
HSSFWorkbook wb=new HSSFWorkbook();
HSSFSheet sheet0 = wb.createSheet("Sheet0");
HSSFSheet sheet1 = wb.createSheet("Sheet1");
HSSFSheet sheet2 = wb.createSheet("Sheet2");
HSSFSheet sheet3 = wb.createSheet("Sheet3");
HSSFSheet sheet4 = wb.createSheet("Sheet4");
// confirm default activation/selection
confirmActiveSelected(sheet0, true);
confirmActiveSelected(sheet1, false);
confirmActiveSelected(sheet2, false);
confirmActiveSelected(sheet3, false);
confirmActiveSelected(sheet4, false);
wb.setActiveSheet(3);
wb.setSelectedTab(3);
confirmActiveSelected(sheet0, false);
confirmActiveSelected(sheet1, false);
confirmActiveSelected(sheet2, false);
confirmActiveSelected(sheet3, true);
confirmActiveSelected(sheet4, false);
wb.removeSheetAt(3);
// after removing the only active/selected sheet, another should be active/selected in its place
if (!sheet4.isSelected()) {
throw new AssertionFailedError("identified bug 40414 a");
}
if (!sheet4.isActive()) {
throw new AssertionFailedError("identified bug 40414 b");
}
confirmActiveSelected(sheet0, false);
confirmActiveSelected(sheet1, false);
confirmActiveSelected(sheet2, false);
confirmActiveSelected(sheet4, true);
sheet3 = sheet4; // re-align local vars in this test case
// Some more cases of removing sheets
// Starting with a multiple selection, and different active sheet
wb.setSelectedTabs(new int[] { 1, 3, });
wb.setActiveSheet(2);
confirmActiveSelected(sheet0, false, false);
confirmActiveSelected(sheet1, false, true);
confirmActiveSelected(sheet2, true, false);
confirmActiveSelected(sheet3, false, true);
// removing a sheet that is not active, and not the only selected sheet
wb.removeSheetAt(3);
confirmActiveSelected(sheet0, false, false);
confirmActiveSelected(sheet1, false, true);
confirmActiveSelected(sheet2, true, false);
// removing the only selected sheet
wb.removeSheetAt(1);
confirmActiveSelected(sheet0, false, false);
confirmActiveSelected(sheet2, true, true);
// The last remaining sheet should always be active+selected
wb.removeSheetAt(1);
confirmActiveSelected(sheet0, true, true);
}
private static void confirmActiveSelected(HSSFSheet sheet, boolean expected) {
confirmActiveSelected(sheet, expected, expected);
}
private static void confirmActiveSelected(HSSFSheet sheet,
boolean expectedActive, boolean expectedSelected) {
assertEquals("active", expectedActive, sheet.isActive());
assertEquals("selected", expectedSelected, sheet.isSelected());
}
}

View File

@ -533,4 +533,28 @@ public final class TestNamedRange extends TestCase {
String contents = c.getStringCellValue();
assertEquals("Contents of cell retrieved by its named reference", contents, cvalue);
}
public void testDeletedReference() throws Exception {
HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("24207.xls");
assertEquals(2, wb.getNumberOfNames());
HSSFName name1 = wb.getNameAt(0);
assertEquals("a", name1.getNameName());
assertEquals("Sheet1!$A$1", name1.getReference());
AreaReference ref1 = new AreaReference(name1.getReference());
assertTrue("Successfully constructed first reference", true);
HSSFName name2 = wb.getNameAt(1);
assertEquals("b", name2.getNameName());
assertEquals("#REF!", name2.getReference());
assertTrue(name2.isDeleted());
try {
AreaReference ref2 = new AreaReference(name2.getReference());
fail("attempt to supply an invalid reference to AreaReference constructor results in exception");
} catch (Exception e){
;
}
}
}

View File

@ -17,6 +17,9 @@
package org.apache.poi.poifs.filesystem;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
@ -115,6 +118,40 @@ public final class TestPOIFSFileSystem extends TestCase {
assertTrue("input stream was not closed", testIS.isClosed()); // but still should close
}
/**
* Test for bug # 48898 - problem opening an OLE2
* file where the last block is short (i.e. not a full
* multiple of 512 bytes)
*
* As yet, this problem remains. One school of thought is
* not not issue an EOF when we discover the last block
* is short, but this seems a bit wrong.
* The other is to fix the handling of the last block in
* POIFS, since it seems to be slight wrong
*/
public void DISABLEDtestShortLastBlock() throws Exception {
String[] files = new String[] {
"ShortLastBlock.qwp", "ShortLastBlock.wps"
};
String pdirname = System.getProperty("POIFS.testdata.path");
for(int i=0; i<files.length; i++) {
File f = new File(pdirname, files[i]);
assertTrue(f.exists());
// Open the file up
POIFSFileSystem fs = new POIFSFileSystem(
new FileInputStream(f)
);
// Write it into a temp output array
ByteArrayOutputStream baos = new ByteArrayOutputStream();
fs.writeFilesystem(baos);
// Check sizes
}
}
private static InputStream openSampleStream(String sampleFileName) {
return HSSFTestDataSamples.openSampleFileStream(sampleFileName);

View File

@ -152,7 +152,7 @@ public class TestRawDataBlock
}
assertEquals(
"7 - Unable to read entire block; "+bts+" read before EOF; expected 512 bytes. Your document has probably been truncated!",
"7 - Unable to read entire block; "+bts+" read before EOF; expected 512 bytes. Your document was either written by software that ignores the spec, or has been truncated!",
(String)(logger.logged.get(0))
);
} else {