From 67412a0678b028750396c27b54c937539aa3dd5d Mon Sep 17 00:00:00 2001 From: Josh Micich Date: Sat, 25 Oct 2008 01:47:25 +0000 Subject: [PATCH] Merged revisions 703100,703197,703302,703596,703620,703645,703651,706540 via svnmerge from https://svn.apache.org/repos/asf/poi/trunk ........ r703100 | josh | 2008-10-09 01:33:54 -0700 (Thu, 09 Oct 2008) | 1 line Removed last occurrences of storing Ptg arrays in Stacks. Some related clean-up. ........ r703197 | josh | 2008-10-09 09:10:39 -0700 (Thu, 09 Oct 2008) | 1 line Should have been submitted with r703100 (changes to Ptg) ........ r703302 | josh | 2008-10-09 17:40:58 -0700 (Thu, 09 Oct 2008) | 1 line Fix for bug 45964 - support for link formulas in Text Objects ........ r703596 | josh | 2008-10-10 15:59:14 -0700 (Fri, 10 Oct 2008) | 1 line Made RecordInputStream final (major clean-up in test cases and BiffViewer) ........ r703620 | josh | 2008-10-10 18:11:05 -0700 (Fri, 10 Oct 2008) | 2 lines fix for bug 45866 - allowed for change of unicode compression across Continue records ........ r703645 | yegor | 2008-10-11 03:31:24 -0700 (Sat, 11 Oct 2008) | 1 line fixed error in eval.xml: use < instead of '<' ........ r703651 | yegor | 2008-10-11 05:01:42 -0700 (Sat, 11 Oct 2008) | 1 line set trunk version.id=3.3-alpha1 ........ r706540 | yegor | 2008-10-20 23:47:35 -0700 (Mon, 20 Oct 2008) | 1 line updated release version on the index page, started a new section in the change log ........ git-svn-id: https://svn.apache.org/repos/asf/poi/branches/ooxml@707807 13f79535-47bb-0310-9956-ffa450edef68 --- src/documentation/content/xdocs/changes.xml | 7 +- src/documentation/content/xdocs/index.xml | 8 +- src/documentation/content/xdocs/status.xml | 7 +- .../org/apache/poi/hssf/dev/BiffViewer.java | 817 +++++++++++------- .../apache/poi/hssf/model/TextboxShape.java | 14 +- .../poi/hssf/record/ContinueRecord.java | 83 +- .../apache/poi/hssf/record/CustomField.java | 52 -- .../poi/hssf/record/ExternalNameRecord.java | 8 +- .../hssf/record/LinkedDataFormulaField.java | 59 +- .../poi/hssf/record/LinkedDataRecord.java | 2 +- .../apache/poi/hssf/record/RecordFactory.java | 87 +- .../poi/hssf/record/RecordInputStream.java | 141 +-- .../poi/hssf/record/TextObjectBaseRecord.java | 427 --------- .../poi/hssf/record/TextObjectRecord.java | 664 ++++++++------ .../apache/poi/hssf/record/formula/Ptg.java | 39 +- .../poi/hssf/usermodel/HSSFComment.java | 5 +- .../hssf/usermodel/HSSFRichTextString.java | 2 +- .../apache/poi/hssf/usermodel/HSSFChart.java | 10 +- .../eventmodel/TestEventRecordFactory.java | 4 +- .../poi/hssf/record/AllRecordTests.java | 1 + .../poi/hssf/record/TestAreaFormatRecord.java | 2 +- .../poi/hssf/record/TestAreaRecord.java | 2 +- .../hssf/record/TestAxisLineFormatRecord.java | 2 +- .../hssf/record/TestAxisOptionsRecord.java | 2 +- .../poi/hssf/record/TestAxisParentRecord.java | 2 +- .../poi/hssf/record/TestAxisRecord.java | 2 +- .../poi/hssf/record/TestAxisUsedRecord.java | 2 +- .../apache/poi/hssf/record/TestBarRecord.java | 2 +- .../poi/hssf/record/TestBoundSheetRecord.java | 2 +- .../poi/hssf/record/TestCFHeaderRecord.java | 4 +- .../poi/hssf/record/TestCFRuleRecord.java | 4 +- .../record/TestCategorySeriesAxisRecord.java | 2 +- .../poi/hssf/record/TestChartRecord.java | 2 +- .../record/TestCommonObjectDataSubRecord.java | 2 +- .../apache/poi/hssf/record/TestDatRecord.java | 2 +- .../poi/hssf/record/TestDataFormatRecord.java | 2 +- ...tDefaultDataLabelTextPropertiesRecord.java | 2 +- .../TestEmbeddedObjectRefSubRecord.java | 2 +- .../poi/hssf/record/TestEndSubRecord.java | 2 +- .../hssf/record/TestExtendedFormatRecord.java | 4 +- .../hssf/record/TestExternalNameRecord.java | 2 +- .../poi/hssf/record/TestFontBasisRecord.java | 2 +- .../poi/hssf/record/TestFontIndexRecord.java | 2 +- .../poi/hssf/record/TestFontRecord.java | 8 +- .../poi/hssf/record/TestFormulaRecord.java | 4 +- .../poi/hssf/record/TestFrameRecord.java | 2 +- .../poi/hssf/record/TestHyperlinkRecord.java | 15 +- .../poi/hssf/record/TestLegendRecord.java | 99 +-- .../poi/hssf/record/TestLineFormatRecord.java | 4 +- .../poi/hssf/record/TestLinkedDataRecord.java | 12 +- .../poi/hssf/record/TestNameRecord.java | 9 +- .../poi/hssf/record/TestNoteRecord.java | 6 +- .../record/TestNoteStructureSubRecord.java | 2 +- .../record/TestNumberFormatIndexRecord.java | 2 +- .../apache/poi/hssf/record/TestObjRecord.java | 8 +- .../poi/hssf/record/TestObjectLinkRecord.java | 2 +- .../poi/hssf/record/TestPaneRecord.java | 2 +- .../poi/hssf/record/TestPlotAreaRecord.java | 2 +- .../poi/hssf/record/TestPlotGrowthRecord.java | 2 +- .../poi/hssf/record/TestRecordFactory.java | 6 +- .../hssf/record/TestRecordInputStream.java | 97 +++ .../apache/poi/hssf/record/TestSCLRecord.java | 2 +- .../poi/hssf/record/TestSSTDeserializer.java | 70 +- .../TestSeriesChartGroupIndexRecord.java | 2 +- .../hssf/record/TestSeriesIndexRecord.java | 2 +- .../hssf/record/TestSeriesLabelsRecord.java | 2 +- .../poi/hssf/record/TestSeriesListRecord.java | 2 +- .../poi/hssf/record/TestSeriesRecord.java | 2 +- .../poi/hssf/record/TestSeriesTextRecord.java | 2 +- .../record/TestSeriesToChartGroupRecord.java | 2 +- .../hssf/record/TestSharedFormulaRecord.java | 2 +- .../record/TestSheetPropertiesRecord.java | 2 +- .../poi/hssf/record/TestStringRecord.java | 4 +- .../poi/hssf/record/TestSupBookRecord.java | 6 +- .../poi/hssf/record/TestTableRecord.java | 2 +- .../hssf/record/TestTextObjectBaseRecord.java | 92 +- .../poi/hssf/record/TestTextObjectRecord.java | 129 ++- .../poi/hssf/record/TestTextRecord.java | 4 +- .../poi/hssf/record/TestTickRecord.java | 2 +- .../poi/hssf/record/TestUnicodeString.java | 32 +- .../poi/hssf/record/TestUnitsRecord.java | 2 +- .../poi/hssf/record/TestValueRangeRecord.java | 2 +- .../record/TestcaseRecordInputStream.java | 57 +- .../constant/TestConstantValueParser.java | 16 +- .../poi/hssf/record/formula/TestArrayPtg.java | 14 +- .../poi/hssf/record/formula/TestFuncPtg.java | 2 +- .../hssf/record/formula/TestReferencePtg.java | 8 +- 87 files changed, 1592 insertions(+), 1641 deletions(-) delete mode 100644 src/java/org/apache/poi/hssf/record/CustomField.java delete mode 100644 src/java/org/apache/poi/hssf/record/TextObjectBaseRecord.java create mode 100644 src/testcases/org/apache/poi/hssf/record/TestRecordInputStream.java diff --git a/src/documentation/content/xdocs/changes.xml b/src/documentation/content/xdocs/changes.xml index 7fa34db878..9dbd18ead2 100644 --- a/src/documentation/content/xdocs/changes.xml +++ b/src/documentation/content/xdocs/changes.xml @@ -66,7 +66,12 @@ Created a common interface for handling PowerPoint files, irrespective of if they are .ppt or .pptx Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx - + + YK: remove me. required to keep Forrest DTD compiler quiet + + + 45866 - allowed for change of unicode compression across Continue records + 45964 - support for link formulas in Text Objects 43354 - support for evalating formulas with missing args 45912 - fixed ArrayIndexOutOfBoundsException in EmbeddedObjectRefSubRecord 45889 - fixed ArrayIndexOutOfBoundsException when constructing HSLF Table with a single row diff --git a/src/documentation/content/xdocs/index.xml b/src/documentation/content/xdocs/index.xml index cfbcafc2db..6deed531a2 100644 --- a/src/documentation/content/xdocs/index.xml +++ b/src/documentation/content/xdocs/index.xml @@ -44,10 +44,10 @@ People interested should also follow the dev list to track progress.

-
POI 3.1-FINAL Released (2008-06-29) +
POI 3.2-FINAL Released (2008-10-19)

- The POI team is pleased to announce the release of 3.1 FINAL, the latest release of Apache POI. - There have been many important bug fixes since the 3.0.2 release and a lot of new features. + The POI team is pleased to announce the release of 3.2 FINAL, the latest release of Apache POI. + There have been many important bug fixes since the 3.1 release and a lot of new features.

A full list of changes is available in the changelog, and download @@ -56,7 +56,7 @@

The release is also available from the central Maven repository - under Group ID "org.apache.poi" and Version "3.1-FINAL". + under Group ID "org.apache.poi" and Version "3.2-FINAL".

diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml index baead2a358..ee52d97065 100644 --- a/src/documentation/content/xdocs/status.xml +++ b/src/documentation/content/xdocs/status.xml @@ -63,7 +63,12 @@ Created a common interface for handling PowerPoint files, irrespective of if they are .ppt or .pptx Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx - + + YK: remove me. required to keep Forrest DTD compiler quiet + + + 45866 - allowed for change of unicode compression across Continue records + 45964 - support for link formulas in Text Objects 43354 - support for evalating formulas with missing args 45912 - fixed ArrayIndexOutOfBoundsException in EmbeddedObjectRefSubRecord 45889 - fixed ArrayIndexOutOfBoundsException when constructing HSLF Table with a single row diff --git a/src/java/org/apache/poi/hssf/dev/BiffViewer.java b/src/java/org/apache/poi/hssf/dev/BiffViewer.java index 15177d0d95..6d2def084e 100644 --- a/src/java/org/apache/poi/hssf/dev/BiffViewer.java +++ b/src/java/org/apache/poi/hssf/dev/BiffViewer.java @@ -17,17 +17,23 @@ package org.apache.poi.hssf.dev; +import java.io.DataInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; +import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.io.OutputStreamWriter; import java.io.PrintStream; +import java.io.Writer; import java.util.ArrayList; +import java.util.List; import org.apache.poi.hssf.record.*; import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.apache.poi.util.HexDump; +import org.apache.poi.util.LittleEndian; /** * Utillity for reading in BIFF8 records and displaying data from them. @@ -37,333 +43,488 @@ import org.apache.poi.util.HexDump; *@see #main */ public final class BiffViewer { - private final File _inputFile; - private boolean dump; - private final PrintStream _ps; - - - 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(_inputFile)); - InputStream stream = fs.createDocumentInputStream("Workbook"); - createRecords(stream, dump, _ps); - } catch (Exception e) { - e.printStackTrace(); - } - } - - - /** - * Create an array of records from an input stream - * - *@param in the InputStream from which the records - * will be obtained - *@param dump - *@return an array of Records created from the - * InputStream - *@exception RecordFormatException on error processing the InputStream - */ - public static Record[] createRecords(InputStream in, boolean dump, PrintStream ps) - throws RecordFormatException { - ArrayList records = new ArrayList(); - RecordDetails activeRecord = null; - - BiffviewRecordInputStream recStream = new BiffviewRecordInputStream(in); - while (recStream.hasNextRecord()) { - recStream.nextRecord(); - if (recStream.getSid() != 0) { - Record record = createRecord (recStream); - if (record.getSid() != ContinueRecord.sid) - { - records.add(record); - if (activeRecord != null) - activeRecord.dump(ps); - int startPos = (int)(recStream.getPos()-recStream.getLength() - 4); - activeRecord = new RecordDetails(recStream.getSid(), recStream.getLength(), startPos, record); - } - if (dump) { - recStream.dumpBytes(ps); - } - } - } - if (activeRecord != null) { - activeRecord.dump(ps); - } - Record[] retval = new Record[records.size()]; - records.toArray(retval); - return retval; - } - - - /** - * Essentially a duplicate of RecordFactory. Kept separate as not to screw - * up non-debug operations. - * - */ - private static Record createRecord( RecordInputStream in ) - { - switch ( in.getSid() ) - { - case AreaFormatRecord.sid: return new AreaFormatRecord(in); - case AreaRecord.sid: return new AreaRecord(in); - case AxisLineFormatRecord.sid: return new AxisLineFormatRecord(in); - case AxisOptionsRecord.sid: return new AxisOptionsRecord(in); - case AxisParentRecord.sid: return new AxisParentRecord(in); - case AxisRecord.sid: return new AxisRecord(in); - case AxisUsedRecord.sid: return new AxisUsedRecord(in); - case BOFRecord.sid: return new BOFRecord(in); - case BackupRecord.sid: return new BackupRecord(in); - case BarRecord.sid: return new BarRecord(in); - case BeginRecord.sid: return new BeginRecord(in); - case BlankRecord.sid: return new BlankRecord(in); - case BookBoolRecord.sid: return new BookBoolRecord(in); - case BoolErrRecord.sid: return new BoolErrRecord(in); - case BottomMarginRecord.sid: return new BottomMarginRecord(in); - case BoundSheetRecord.sid: return new BoundSheetRecord(in); - case CFHeaderRecord.sid: return new CFHeaderRecord(in); - case CFRuleRecord.sid: return new CFRuleRecord(in); - case CalcCountRecord.sid: return new CalcCountRecord(in); - case CalcModeRecord.sid: return new CalcModeRecord(in); - case CategorySeriesAxisRecord.sid: return new CategorySeriesAxisRecord(in); - case ChartFormatRecord.sid: return new ChartFormatRecord(in); - case ChartRecord.sid: return new ChartRecord(in); - case CodepageRecord.sid: return new CodepageRecord(in); - case ColumnInfoRecord.sid: return new ColumnInfoRecord(in); - case ContinueRecord.sid: return new ContinueRecord(in); - case CountryRecord.sid: return new CountryRecord(in); - case DBCellRecord.sid: return new DBCellRecord(in); - case DSFRecord.sid: return new DSFRecord(in); - case DatRecord.sid: return new DatRecord(in); - case DataFormatRecord.sid: return new DataFormatRecord(in); - case DateWindow1904Record.sid: return new DateWindow1904Record(in); - case DefaultColWidthRecord.sid:return new DefaultColWidthRecord(in); - case DefaultDataLabelTextPropertiesRecord.sid: return new DefaultDataLabelTextPropertiesRecord(in); - case DefaultRowHeightRecord.sid: return new DefaultRowHeightRecord(in); - case DeltaRecord.sid: return new DeltaRecord(in); - case DimensionsRecord.sid: return new DimensionsRecord(in); - case DrawingGroupRecord.sid: return new DrawingGroupRecord(in); - case DrawingRecordForBiffViewer.sid: return new DrawingRecordForBiffViewer(in); - case DrawingSelectionRecord.sid: return new DrawingSelectionRecord(in); - case DVRecord.sid: return new DVRecord(in); - case DVALRecord.sid: return new DVALRecord(in); - case EOFRecord.sid: return new EOFRecord(in); - case EndRecord.sid: return new EndRecord(in); - case ExtSSTRecord.sid: return new ExtSSTRecord(in); - case ExtendedFormatRecord.sid: return new ExtendedFormatRecord(in); - case ExternSheetRecord.sid: return new ExternSheetRecord(in); - case FilePassRecord.sid: return new FilePassRecord(in); - case FileSharingRecord.sid: return new FileSharingRecord(in); - case FnGroupCountRecord.sid: return new FnGroupCountRecord(in); - case FontBasisRecord.sid: return new FontBasisRecord(in); - case FontIndexRecord.sid: return new FontIndexRecord(in); - case FontRecord.sid: return new FontRecord(in); - case FooterRecord.sid: return new FooterRecord(in); - case FormatRecord.sid: return new FormatRecord(in); - case FormulaRecord.sid: return new FormulaRecord(in); - case FrameRecord.sid: return new FrameRecord(in); - case GridsetRecord.sid: return new GridsetRecord(in); - case GutsRecord.sid: return new GutsRecord(in); - case HCenterRecord.sid: return new HCenterRecord(in); - case HeaderRecord.sid: return new HeaderRecord(in); - case HideObjRecord.sid: return new HideObjRecord(in); - case HorizontalPageBreakRecord.sid: return new HorizontalPageBreakRecord(in); - case HyperlinkRecord.sid: return new HyperlinkRecord(in); - case IndexRecord.sid: return new IndexRecord(in); - case InterfaceEndRecord.sid: return new InterfaceEndRecord(in); - case InterfaceHdrRecord.sid: return new InterfaceHdrRecord(in); - case IterationRecord.sid: return new IterationRecord(in); - case LabelRecord.sid: return new LabelRecord(in); - case LabelSSTRecord.sid: return new LabelSSTRecord(in); - case LeftMarginRecord.sid: return new LeftMarginRecord(in); - case LegendRecord.sid: return new LegendRecord(in); - case LineFormatRecord.sid: return new LineFormatRecord(in); - case LinkedDataRecord.sid: return new LinkedDataRecord(in); - case MMSRecord.sid: return new MMSRecord(in); - case MergeCellsRecord.sid: return new MergeCellsRecord(in); - case MulBlankRecord.sid: return new MulBlankRecord(in); - case MulRKRecord.sid: return new MulRKRecord(in); - case NameRecord.sid: return new NameRecord(in); - case NoteRecord.sid: return new NoteRecord(in); - case NumberRecord.sid: return new NumberRecord(in); - case ObjRecord.sid: return new ObjRecord(in); - case ObjectLinkRecord.sid: return new ObjectLinkRecord(in); - case PaletteRecord.sid: return new PaletteRecord(in); - case PaneRecord.sid: return new PaneRecord(in); - case PasswordRecord.sid: return new PasswordRecord(in); - case PasswordRev4Record.sid: return new PasswordRev4Record(in); - case PlotAreaRecord.sid: return new PlotAreaRecord(in); - case PlotGrowthRecord.sid: return new PlotGrowthRecord(in); - case PrecisionRecord.sid: return new PrecisionRecord(in); - case PrintGridlinesRecord.sid: return new PrintGridlinesRecord(in); - case PrintHeadersRecord.sid: return new PrintHeadersRecord(in); - case PrintSetupRecord.sid: return new PrintSetupRecord(in); - case ProtectRecord.sid: return new ProtectRecord(in); - case ProtectionRev4Record.sid: return new ProtectionRev4Record(in); - case RKRecord.sid: return new RKRecord(in); - case RefModeRecord.sid: return new RefModeRecord(in); - case RefreshAllRecord.sid: return new RefreshAllRecord(in); - case RightMarginRecord.sid: return new RightMarginRecord(in); - case RowRecord.sid: return new RowRecord(in); - case SCLRecord.sid: return new SCLRecord(in); - case SSTRecord.sid: return new SSTRecord(in); - case SaveRecalcRecord.sid: return new SaveRecalcRecord(in); - case SelectionRecord.sid: return new SelectionRecord(in); - case SeriesIndexRecord.sid: return new SeriesIndexRecord(in); - case SeriesListRecord.sid: return new SeriesListRecord(in); - case SeriesRecord.sid: return new SeriesRecord(in); - case SeriesTextRecord.sid: return new SeriesTextRecord(in); - case SeriesToChartGroupRecord.sid: return new SeriesToChartGroupRecord(in); - case SharedFormulaRecord.sid: return new SharedFormulaRecord(in); - case SheetPropertiesRecord.sid:return new SheetPropertiesRecord(in); - case StringRecord.sid: return new StringRecord(in); - case StyleRecord.sid: return new StyleRecord(in); - case SupBookRecord.sid: return new SupBookRecord(in); - case TabIdRecord.sid: return new TabIdRecord(in); - case TableRecord.sid: return new TableRecord(in); - case TextObjectRecord.sid: return new TextObjectRecord(in); - case TextRecord.sid: return new TextRecord(in); - case TickRecord.sid: return new TickRecord(in); - case TopMarginRecord.sid: return new TopMarginRecord(in); - case UnitsRecord.sid: return new UnitsRecord(in); - case UseSelFSRecord.sid: return new UseSelFSRecord(in); - case VCenterRecord.sid: return new VCenterRecord(in); - case ValueRangeRecord.sid: return new ValueRangeRecord(in); - case VerticalPageBreakRecord.sid: return new VerticalPageBreakRecord(in); - case WSBoolRecord.sid: return new WSBoolRecord(in); - case WindowOneRecord.sid: return new WindowOneRecord(in); - case WindowProtectRecord.sid: return new WindowProtectRecord(in); - case WindowTwoRecord.sid: return new WindowTwoRecord(in); - case WriteAccessRecord.sid: return new WriteAccessRecord(in); - case WriteProtectRecord.sid: return new WriteProtectRecord(in); - - } - return new UnknownRecord(in); - } - - - /** - * Method setDump - hex dump out data or not. - */ - public void setDump(boolean dump) { - this.dump = dump; - } - - - /** - * Method main with 1 argument just run straight biffview against given - * file

- * - * with 2 arguments where the second argument is "on" - run biffviewer

- * - * with hex dumps of records

- * - * with 2 arguments where the second argument is "bfd" just run a big fat - * hex dump of the file...don't worry about biffviewing it at all - *

- * Define the system property poi.deserialize.escher to turn on - * deserialization of escher records. - * - */ - 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 { - String inFileName = args[0]; - File inputFile = new File(inFileName); - if(!inputFile.exists()) { - throw new RuntimeException("specified inputFile '" + inFileName + "' does not exist"); - } - 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(); - } - } - - /** - * This record supports dumping of completed continue records. - */ - private static final class RecordDetails - { - short rectype, recsize; - int startloc; - Record record; - - public RecordDetails( short rectype, short recsize, int startloc, Record record ) - { - this.rectype = rectype; - this.recsize = recsize; - this.startloc = startloc; - this.record = record; - } - - public short getRectype() - { - return rectype; - } - - public short getRecsize() - { - return recsize; - } - - public Record getRecord() - { - return record; - } - - 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() ); - } - } - - private static final class BiffviewRecordInputStream extends RecordInputStream { - public BiffviewRecordInputStream(InputStream in) { - super(in); - } - public void dumpBytes(PrintStream ps) { - ps.println(HexDump.dump(this.data, 0, this.currentLength)); - } - } - + static final char[] NEW_LINE_CHARS = System.getProperty("line.separator").toCharArray(); + + private BiffViewer() { + // no instances of this class + } + + /** + * Create an array of records from an input stream + * + *@param in the InputStream from which the records will be obtained + *@return an array of Records created from the InputStream + *@exception RecordFormatException on error processing the InputStream + */ + public static Record[] createRecords(InputStream is, PrintStream ps, BiffRecordListener recListener, boolean dumpInterpretedRecords) + throws RecordFormatException { + ArrayList temp = new ArrayList(); + + RecordInputStream recStream = new RecordInputStream(is); + while (recStream.hasNextRecord()) { + recStream.nextRecord(); + if (recStream.getSid() == 0) { + continue; + } + Record record = createRecord (recStream); + if (record.getSid() == ContinueRecord.sid) { + continue; + } + temp.add(record); + if (dumpInterpretedRecords) { + String[] headers = recListener.getRecentHeaders(); + for (int i = 0; i < headers.length; i++) { + ps.println(headers[i]); + } + ps.print(record.toString()); + } + ps.println(); + } + Record[] result = new Record[temp.size()]; + temp.toArray(result); + return result; + } + + + /** + * Essentially a duplicate of RecordFactory. Kept separate as not to screw + * up non-debug operations. + * + */ + private static Record createRecord(RecordInputStream in) { + switch (in.getSid()) { + case AreaFormatRecord.sid: return new AreaFormatRecord(in); + case AreaRecord.sid: return new AreaRecord(in); + case ArrayRecord.sid: return new ArrayRecord(in); + case AxisLineFormatRecord.sid: return new AxisLineFormatRecord(in); + case AxisOptionsRecord.sid: return new AxisOptionsRecord(in); + case AxisParentRecord.sid: return new AxisParentRecord(in); + case AxisRecord.sid: return new AxisRecord(in); + case AxisUsedRecord.sid: return new AxisUsedRecord(in); + case BOFRecord.sid: return new BOFRecord(in); + case BackupRecord.sid: return new BackupRecord(in); + case BarRecord.sid: return new BarRecord(in); + case BeginRecord.sid: return new BeginRecord(in); + case BlankRecord.sid: return new BlankRecord(in); + case BookBoolRecord.sid: return new BookBoolRecord(in); + case BoolErrRecord.sid: return new BoolErrRecord(in); + case BottomMarginRecord.sid: return new BottomMarginRecord(in); + case BoundSheetRecord.sid: return new BoundSheetRecord(in); + case CFHeaderRecord.sid: return new CFHeaderRecord(in); + case CFRuleRecord.sid: return new CFRuleRecord(in); + case CalcCountRecord.sid: return new CalcCountRecord(in); + case CalcModeRecord.sid: return new CalcModeRecord(in); + case CategorySeriesAxisRecord.sid: return new CategorySeriesAxisRecord(in); + case ChartFormatRecord.sid: return new ChartFormatRecord(in); + case ChartRecord.sid: return new ChartRecord(in); + case CodepageRecord.sid: return new CodepageRecord(in); + case ColumnInfoRecord.sid: return new ColumnInfoRecord(in); + case ContinueRecord.sid: return new ContinueRecord(in); + case CountryRecord.sid: return new CountryRecord(in); + case DBCellRecord.sid: return new DBCellRecord(in); + case DSFRecord.sid: return new DSFRecord(in); + case DatRecord.sid: return new DatRecord(in); + case DataFormatRecord.sid: return new DataFormatRecord(in); + case DateWindow1904Record.sid: return new DateWindow1904Record(in); + case DefaultColWidthRecord.sid:return new DefaultColWidthRecord(in); + case DefaultDataLabelTextPropertiesRecord.sid: return new DefaultDataLabelTextPropertiesRecord(in); + case DefaultRowHeightRecord.sid: return new DefaultRowHeightRecord(in); + case DeltaRecord.sid: return new DeltaRecord(in); + case DimensionsRecord.sid: return new DimensionsRecord(in); + case DrawingGroupRecord.sid: return new DrawingGroupRecord(in); + case DrawingRecordForBiffViewer.sid: return new DrawingRecordForBiffViewer(in); + case DrawingSelectionRecord.sid: return new DrawingSelectionRecord(in); + case DVRecord.sid: return new DVRecord(in); + case DVALRecord.sid: return new DVALRecord(in); + case EOFRecord.sid: return new EOFRecord(in); + case EndRecord.sid: return new EndRecord(in); + case ExtSSTRecord.sid: return new ExtSSTRecord(in); + case ExtendedFormatRecord.sid: return new ExtendedFormatRecord(in); + case ExternSheetRecord.sid: return new ExternSheetRecord(in); + case FilePassRecord.sid: return new FilePassRecord(in); + case FileSharingRecord.sid: return new FileSharingRecord(in); + case FnGroupCountRecord.sid: return new FnGroupCountRecord(in); + case FontBasisRecord.sid: return new FontBasisRecord(in); + case FontIndexRecord.sid: return new FontIndexRecord(in); + case FontRecord.sid: return new FontRecord(in); + case FooterRecord.sid: return new FooterRecord(in); + case FormatRecord.sid: return new FormatRecord(in); + case FormulaRecord.sid: return new FormulaRecord(in); + case FrameRecord.sid: return new FrameRecord(in); + case GridsetRecord.sid: return new GridsetRecord(in); + case GutsRecord.sid: return new GutsRecord(in); + case HCenterRecord.sid: return new HCenterRecord(in); + case HeaderRecord.sid: return new HeaderRecord(in); + case HideObjRecord.sid: return new HideObjRecord(in); + case HorizontalPageBreakRecord.sid: return new HorizontalPageBreakRecord(in); + case HyperlinkRecord.sid: return new HyperlinkRecord(in); + case IndexRecord.sid: return new IndexRecord(in); + case InterfaceEndRecord.sid: return new InterfaceEndRecord(in); + case InterfaceHdrRecord.sid: return new InterfaceHdrRecord(in); + case IterationRecord.sid: return new IterationRecord(in); + case LabelRecord.sid: return new LabelRecord(in); + case LabelSSTRecord.sid: return new LabelSSTRecord(in); + case LeftMarginRecord.sid: return new LeftMarginRecord(in); + case LegendRecord.sid: return new LegendRecord(in); + case LineFormatRecord.sid: return new LineFormatRecord(in); + case LinkedDataRecord.sid: return new LinkedDataRecord(in); + case MMSRecord.sid: return new MMSRecord(in); + case MergeCellsRecord.sid: return new MergeCellsRecord(in); + case MulBlankRecord.sid: return new MulBlankRecord(in); + case MulRKRecord.sid: return new MulRKRecord(in); + case NameRecord.sid: return new NameRecord(in); + case NoteRecord.sid: return new NoteRecord(in); + case NumberRecord.sid: return new NumberRecord(in); + case ObjRecord.sid: return new ObjRecord(in); + case ObjectLinkRecord.sid: return new ObjectLinkRecord(in); + case PaletteRecord.sid: return new PaletteRecord(in); + case PaneRecord.sid: return new PaneRecord(in); + case PasswordRecord.sid: return new PasswordRecord(in); + case PasswordRev4Record.sid: return new PasswordRev4Record(in); + case PlotAreaRecord.sid: return new PlotAreaRecord(in); + case PlotGrowthRecord.sid: return new PlotGrowthRecord(in); + case PrecisionRecord.sid: return new PrecisionRecord(in); + case PrintGridlinesRecord.sid: return new PrintGridlinesRecord(in); + case PrintHeadersRecord.sid: return new PrintHeadersRecord(in); + case PrintSetupRecord.sid: return new PrintSetupRecord(in); + case ProtectRecord.sid: return new ProtectRecord(in); + case ProtectionRev4Record.sid: return new ProtectionRev4Record(in); + case RKRecord.sid: return new RKRecord(in); + case RefModeRecord.sid: return new RefModeRecord(in); + case RefreshAllRecord.sid: return new RefreshAllRecord(in); + case RightMarginRecord.sid: return new RightMarginRecord(in); + case RowRecord.sid: return new RowRecord(in); + case SCLRecord.sid: return new SCLRecord(in); + case SSTRecord.sid: return new SSTRecord(in); + case SaveRecalcRecord.sid: return new SaveRecalcRecord(in); + case SelectionRecord.sid: return new SelectionRecord(in); + case SeriesIndexRecord.sid: return new SeriesIndexRecord(in); + case SeriesListRecord.sid: return new SeriesListRecord(in); + case SeriesRecord.sid: return new SeriesRecord(in); + case SeriesTextRecord.sid: return new SeriesTextRecord(in); + case SeriesToChartGroupRecord.sid: return new SeriesToChartGroupRecord(in); + case SharedFormulaRecord.sid: return new SharedFormulaRecord(in); + case SheetPropertiesRecord.sid:return new SheetPropertiesRecord(in); + case StringRecord.sid: return new StringRecord(in); + case StyleRecord.sid: return new StyleRecord(in); + case SupBookRecord.sid: return new SupBookRecord(in); + case TabIdRecord.sid: return new TabIdRecord(in); + case TableRecord.sid: return new TableRecord(in); + case TextObjectRecord.sid: return new TextObjectRecord(in); + case TextRecord.sid: return new TextRecord(in); + case TickRecord.sid: return new TickRecord(in); + case TopMarginRecord.sid: return new TopMarginRecord(in); + case UnitsRecord.sid: return new UnitsRecord(in); + case UseSelFSRecord.sid: return new UseSelFSRecord(in); + case VCenterRecord.sid: return new VCenterRecord(in); + case ValueRangeRecord.sid: return new ValueRangeRecord(in); + case VerticalPageBreakRecord.sid: return new VerticalPageBreakRecord(in); + case WSBoolRecord.sid: return new WSBoolRecord(in); + case WindowOneRecord.sid: return new WindowOneRecord(in); + case WindowProtectRecord.sid: return new WindowProtectRecord(in); + case WindowTwoRecord.sid: return new WindowTwoRecord(in); + case WriteAccessRecord.sid: return new WriteAccessRecord(in); + case WriteProtectRecord.sid: return new WriteProtectRecord(in); + + } + return new UnknownRecord(in); + } + + /** + * Method main with 1 argument just run straight biffview against given + * file

+ * + * with 2 arguments where the second argument is "on" - run biffviewer

+ * + * with hex dumps of records

+ * + * with 2 arguments where the second argument is "bfd" just run a big fat + * hex dump of the file...don't worry about biffviewing it at all + *

+ * Define the system property poi.deserialize.escher to turn on + * deserialization of escher records. + * + */ + 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 { + String inFileName = args[0]; + File inputFile = new File(inFileName); + if(!inputFile.exists()) { + throw new RuntimeException("specified inputFile '" + inFileName + "' does not exist"); + } + 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; + } + + 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 { + boolean dumpInterpretedRecords = true; + boolean dumpHex = args.length > 1 && args[1].equals("on"); + + POIFSFileSystem fs = new POIFSFileSystem(new FileInputStream(inputFile)); + InputStream is = fs.createDocumentInputStream("Workbook"); + BiffRecordListener recListener = new BiffRecordListener(dumpHex ? new OutputStreamWriter(ps) : null); + is = new BiffDumpingStream(is, recListener); + createRecords(is, ps, recListener, dumpInterpretedRecords); + } + ps.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private static final class BiffRecordListener implements IBiffRecordListener { + private final Writer _hexDumpWriter; + private final List _headers; + public BiffRecordListener(Writer hexDumpWriter) { + _hexDumpWriter = hexDumpWriter; + _headers = new ArrayList(); + } + + public void processRecord(int globalOffset, int recordCounter, int sid, int dataSize, + byte[] data) { + String header = formatRecordDetails(globalOffset, sid, dataSize, recordCounter); + _headers.add(header); + Writer w = _hexDumpWriter; + if (w != null) { + try { + w.write(header); + w.write(NEW_LINE_CHARS); + hexDumpAligned(w, data, 0, dataSize+4, globalOffset); + w.flush(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } + public String[] getRecentHeaders() { + String[] result = new String[_headers.size()]; + _headers.toArray(result); + _headers.clear(); + return result; + } + private static String formatRecordDetails(int globalOffset, int sid, int size, int recordCounter) { + StringBuffer sb = new StringBuffer(64); + sb.append("Offset=").append(HexDump.intToHex(globalOffset)).append("(").append(globalOffset).append(")"); + sb.append(" recno=").append(recordCounter); + sb.append( " sid=").append(HexDump.shortToHex(sid)); + sb.append( " size=").append(HexDump.shortToHex(size)).append("(").append(size).append(")"); + return sb.toString(); + } + } + + private static interface IBiffRecordListener { + + void processRecord(int globalOffset, int recordCounter, int sid, int dataSize, byte[] data); + + } + + /** + * Wraps a plain {@link InputStream} and allows BIFF record information to be tapped off + * + */ + private static final class BiffDumpingStream extends InputStream { + private final DataInputStream _is; + private final IBiffRecordListener _listener; + private final byte[] _data; + private int _recordCounter; + private int _overallStreamPos; + private int _currentPos; + private int _currentSize; + private boolean _innerHasReachedEOF; + + public BiffDumpingStream(InputStream is, IBiffRecordListener listener) { + _is = new DataInputStream(is); + _listener = listener; + _data = new byte[RecordInputStream.MAX_RECORD_DATA_SIZE + 4]; + _recordCounter = 0; + _overallStreamPos = 0; + _currentSize = 0; + _currentPos = 0; + } + + public int read() throws IOException { + if (_currentPos >= _currentSize) { + fillNextBuffer(); + } + if (_currentPos >= _currentSize) { + return -1; + } + int result = _data[_currentPos] & 0x00FF; + _currentPos ++; + _overallStreamPos ++; + formatBufferIfAtEndOfRec(); + return result; + } + public int read(byte[] b, int off, int len) throws IOException { + if (_currentPos >= _currentSize) { + fillNextBuffer(); + } + if (_currentPos >= _currentSize) { + return -1; + } + int availSize = _currentSize - _currentPos; + int result; + if (len > availSize) { + System.err.println("Unexpected request to read past end of current biff record"); + result = availSize; + } else { + result = len; + } + System.arraycopy(_data, _currentPos, b, off, result); + _currentPos += result; + _overallStreamPos += result; + formatBufferIfAtEndOfRec(); + return result; + } + + public int available() throws IOException { + return _currentSize - _currentPos + _is.available(); + } + private void fillNextBuffer() throws IOException { + if (_innerHasReachedEOF) { + return; + } + int b0 = _is.read(); + if (b0 == -1) { + _innerHasReachedEOF = true; + return; + } + _data[0] = (byte) b0; + _is.readFully(_data, 1, 3); + int len = LittleEndian.getShort(_data, 2); + _is.readFully(_data, 4, len); + _currentPos = 0; + _currentSize = len + 4; + _recordCounter++; + } + private void formatBufferIfAtEndOfRec() { + if (_currentPos != _currentSize) { + return; + } + int dataSize = _currentSize-4; + int sid = LittleEndian.getShort(_data, 0); + int globalOffset = _overallStreamPos-_currentSize; + _listener.processRecord(globalOffset, _recordCounter, sid, dataSize, _data); + } + public void close() throws IOException { + _is.close(); + } + } + + private static final int DUMP_LINE_LEN = 16; + private static final char[] COLUMN_SEPARATOR = " | ".toCharArray(); + /** + * Hex-dumps a portion of a byte array in typical format, also preserving dump-line alignment + * @param globalOffset (somewhat arbitrary) used to calculate the addresses printed at the + * start of each line + */ + static void hexDumpAligned(Writer w, byte[] data, int baseDataOffset, int dumpLen, int globalOffset) { + // perhaps this code should be moved to HexDump + int globalStart = globalOffset + baseDataOffset; + int globalEnd = globalOffset + baseDataOffset + dumpLen; + int startDelta = globalStart % DUMP_LINE_LEN; + int endDelta = globalEnd % DUMP_LINE_LEN; + int startLineAddr = globalStart - startDelta; + int endLineAddr = globalEnd - endDelta; + + int lineDataOffset = baseDataOffset - startDelta; + int lineAddr = startLineAddr; + + // output (possibly incomplete) first line + if (startLineAddr == endLineAddr) { + hexDumpLine(w, data, lineAddr, lineDataOffset, startDelta, endDelta); + return; + } + hexDumpLine(w, data, lineAddr, lineDataOffset, startDelta, DUMP_LINE_LEN); + + // output all full lines in the middle + while (true) { + lineAddr += DUMP_LINE_LEN; + lineDataOffset += DUMP_LINE_LEN; + if (lineAddr >= endLineAddr) { + break; + } + hexDumpLine(w, data, lineAddr, lineDataOffset, 0, DUMP_LINE_LEN); + } + + + // output (possibly incomplete) last line + if (endDelta != 0) { + hexDumpLine(w, data, lineAddr, lineDataOffset, 0, endDelta); + } + } + + private static void hexDumpLine(Writer w, byte[] data, int lineStartAddress, int lineDataOffset, int startDelta, int endDelta) { + if (startDelta >= endDelta) { + throw new IllegalArgumentException("Bad start/end delta"); + } + try { + writeHex(w, lineStartAddress, 8); + w.write(COLUMN_SEPARATOR); + // raw hex data + for (int i=0; i< DUMP_LINE_LEN; i++) { + if (i>0) { + w.write(" "); + } + if (i >= startDelta && i < endDelta) { + writeHex(w, data[lineDataOffset+i], 2); + } else { + w.write(" "); + } + } + w.write(COLUMN_SEPARATOR); + + // interpreted ascii + for (int i=0; i< DUMP_LINE_LEN; i++) { + if (i >= startDelta && i < endDelta) { + w.write(getPrintableChar(data[lineDataOffset+i])); + } else { + w.write(" "); + } + } + w.write(NEW_LINE_CHARS); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private static char getPrintableChar(byte b) { + char ib = (char) (b & 0x00FF); + if (ib < 32 || ib > 126) { + return '.'; + } + return ib; + } + + private static void writeHex(Writer w, int value, int nDigits) throws IOException { + char[] buf = new char[nDigits]; + int acc = value; + for(int i=nDigits-1; i>=0; i--) { + int digit = acc & 0x0F; + buf[i] = (char) (digit < 10 ? ('0' + digit) : ('A' + digit - 10)); + acc >>= 4; + } + w.write(buf); + } } diff --git a/src/java/org/apache/poi/hssf/model/TextboxShape.java b/src/java/org/apache/poi/hssf/model/TextboxShape.java index b1d3370fbf..e74197711b 100644 --- a/src/java/org/apache/poi/hssf/model/TextboxShape.java +++ b/src/java/org/apache/poi/hssf/model/TextboxShape.java @@ -138,15 +138,11 @@ public class TextboxShape HSSFTextbox shape = hssfShape; TextObjectRecord obj = new TextObjectRecord(); - obj.setHorizontalTextAlignment( hssfShape.getHorizontalAlignment() ); - obj.setVerticalTextAlignment( hssfShape.getVerticalAlignment()); - obj.setTextLocked( true ); - obj.setTextOrientation( TextObjectRecord.TEXT_ORIENTATION_NONE ); - int frLength = ( shape.getString().numFormattingRuns() + 1 ) * 8; - obj.setFormattingRunLength( (short) frLength ); - obj.setTextLength( (short) shape.getString().length() ); - obj.setStr( shape.getString() ); - obj.setReserved7( 0 ); + obj.setHorizontalTextAlignment(hssfShape.getHorizontalAlignment()); + obj.setVerticalTextAlignment(hssfShape.getVerticalAlignment()); + obj.setTextLocked(true); + obj.setTextOrientation(TextObjectRecord.TEXT_ORIENTATION_NONE); + obj.setStr(shape.getString()); return obj; } diff --git a/src/java/org/apache/poi/hssf/record/ContinueRecord.java b/src/java/org/apache/poi/hssf/record/ContinueRecord.java index 435c454712..e20c4633c3 100644 --- a/src/java/org/apache/poi/hssf/record/ContinueRecord.java +++ b/src/java/org/apache/poi/hssf/record/ContinueRecord.java @@ -22,76 +22,44 @@ package org.apache.poi.hssf.record; import org.apache.poi.util.LittleEndian; /** - * Title: Continue Record - Helper class used primarily for SST Records

+ * Title: Continue Record(0x003C) - Helper class used primarily for SST Records

* Description: handles overflow for prior record in the input * stream; content is tailored to that prior record

* @author Marc Johnson (mjohnson at apache dot org) * @author Andrew C. Oliver (acoliver at apache dot org) * @author Csaba Nagy (ncsaba at yahoo dot com) - * @version 2.0-pre */ - -public class ContinueRecord - extends Record -{ +public final class ContinueRecord extends Record { public final static short sid = 0x003C; - private byte[] field_1_data; - - /** - * default constructor - */ + private byte[] _data; - public ContinueRecord() - { + public ContinueRecord(byte[] data) { + _data = data; } /** * USE ONLY within "processContinue" */ - public byte [] serialize() { - byte[] retval = new byte[ field_1_data.length + 4 ]; + byte[] retval = new byte[ _data.length + 4 ]; serialize(0, retval); return retval; } - public int serialize(int offset, byte [] data) - { - - LittleEndian.putShort(data, offset, sid); - LittleEndian.putShort(data, offset + 2, ( short ) field_1_data.length); - System.arraycopy(field_1_data, 0, data, offset + 4, field_1_data.length); - return field_1_data.length + 4; - // throw new RecordFormatException( - // "You're not supposed to serialize Continue records like this directly"); - } - - /* - * @param data raw data - */ - - public void setData(byte [] data) - { - field_1_data = data; + public int serialize(int offset, byte[] data) { + return write(data, offset, null, _data); } /** * get the data for continuation * @return byte array containing all of the continued data */ - public byte [] getData() { - return field_1_data; + return _data; } - /** - * Debugging toString - * - * @return string representation - */ - public String toString() { StringBuffer buffer = new StringBuffer(); @@ -113,19 +81,36 @@ public class ContinueRecord * * @param in the RecordInputstream to read the record from */ - public ContinueRecord(RecordInputStream in) { - field_1_data = in.readRemainder(); + _data = in.readRemainder(); } - /** - * Clone this record. - */ public Object clone() { - ContinueRecord clone = new ContinueRecord(); - clone.setData(field_1_data); - return clone; + return new ContinueRecord(_data); } + /** + * Writes the full encoding of a Continue record without making an instance + */ + public static int write(byte[] destBuf, int destOffset, Byte initialDataByte, byte[] srcData) { + return write(destBuf, destOffset, initialDataByte, srcData, 0, srcData.length); + } + /** + * @param initialDataByte (optional - often used for unicode flag). + * If supplied, this will be written before srcData + * @return the total number of bytes written + */ + public static int write(byte[] destBuf, int destOffset, Byte initialDataByte, byte[] srcData, int srcOffset, int len) { + int totalLen = len + (initialDataByte == null ? 0 : 1); + LittleEndian.putUShort(destBuf, destOffset, sid); + LittleEndian.putUShort(destBuf, destOffset + 2, totalLen); + int pos = destOffset + 4; + if (initialDataByte != null) { + LittleEndian.putByte(destBuf, pos, initialDataByte.byteValue()); + pos += 1; + } + System.arraycopy(srcData, srcOffset, destBuf, pos, len); + return 4 + totalLen; + } } diff --git a/src/java/org/apache/poi/hssf/record/CustomField.java b/src/java/org/apache/poi/hssf/record/CustomField.java deleted file mode 100644 index 474d3b2b4f..0000000000 --- a/src/java/org/apache/poi/hssf/record/CustomField.java +++ /dev/null @@ -1,52 +0,0 @@ -/* ==================================================================== - 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; - -public interface CustomField - extends Cloneable -{ - /** - * @return The size of this field in bytes. This operation is not valid - * until after the call to fillField() - */ - int getSize(); - - /** - * Populates this fields data from the byte array passed in. - * @param in the RecordInputstream to read the record from - */ - int fillField(RecordInputStream in); - - /** - * Appends the string representation of this field to the supplied - * StringBuffer. - * - * @param str The string buffer to append to. - */ - void toString(StringBuffer str); - - /** - * Converts this field to it's byte array form. - * @param offset The offset into the byte array to start writing to. - * @param data The data array to write to. - * @return The number of bytes written. - */ - int serializeField(int offset, byte[] data); - - -} diff --git a/src/java/org/apache/poi/hssf/record/ExternalNameRecord.java b/src/java/org/apache/poi/hssf/record/ExternalNameRecord.java index d2135c085e..4d7f312bd5 100755 --- a/src/java/org/apache/poi/hssf/record/ExternalNameRecord.java +++ b/src/java/org/apache/poi/hssf/record/ExternalNameRecord.java @@ -17,8 +17,6 @@ package org.apache.poi.hssf.record; -import java.util.Stack; - import org.apache.poi.hssf.record.formula.Ptg; import org.apache.poi.util.LittleEndian; import org.apache.poi.util.StringUtil; @@ -124,11 +122,7 @@ public final class ExternalNameRecord extends Record { } private int getNameDefinitionSize() { - int result = 0; - for (int i = 0; i < field_5_name_definition.length; i++) { - result += field_5_name_definition[i].getSize(); - } - return result; + return Ptg.getEncodedSize(field_5_name_definition); } diff --git a/src/java/org/apache/poi/hssf/record/LinkedDataFormulaField.java b/src/java/org/apache/poi/hssf/record/LinkedDataFormulaField.java index 9e82adec6e..4a607c9e37 100644 --- a/src/java/org/apache/poi/hssf/record/LinkedDataFormulaField.java +++ b/src/java/org/apache/poi/hssf/record/LinkedDataFormulaField.java @@ -20,47 +20,38 @@ package org.apache.poi.hssf.record; import org.apache.poi.hssf.record.formula.Ptg; import org.apache.poi.util.LittleEndian; -import java.util.Stack; -import java.util.Iterator; - /** * Not implemented yet. May commit it anyway just so people can see * where I'm heading. * * @author Glen Stampoultzis (glens at apache.org) */ -public final class LinkedDataFormulaField implements CustomField { - Stack formulaTokens = new Stack(); +public final class LinkedDataFormulaField { + private Ptg[] formulaTokens; public int getSize() { - int size = 0; - for ( Iterator iterator = formulaTokens.iterator(); iterator.hasNext(); ) - { - Ptg token = (Ptg) iterator.next(); - size += token.getSize(); - } - return size + 2; + return 2 + Ptg.getEncodedSize(formulaTokens); } public int fillField( RecordInputStream in ) { - short tokenSize = in.readShort(); - formulaTokens = Ptg.createParsedExpressionTokens(tokenSize, in); - + int tokenSize = in.readUShort(); + formulaTokens = Ptg.readTokens(tokenSize, in); return tokenSize + 2; } public void toString( StringBuffer buffer ) { - for ( int k = 0; k < formulaTokens.size(); k++ ) + for ( int k = 0; k < formulaTokens.length; k++ ) { + Ptg ptg = formulaTokens[k]; buffer.append( "Formula " ) .append( k ) .append( "=" ) - .append( formulaTokens.get( k ).toString() ) + .append(ptg.toString() ) .append( "\n" ) - .append( ( (Ptg) formulaTokens.get( k ) ).toDebugString() ) + .append(ptg.toDebugString() ) .append( "\n" ); } } @@ -75,34 +66,26 @@ public final class LinkedDataFormulaField implements CustomField { public int serializeField( int offset, byte[] data ) { int size = getSize(); - LittleEndian.putShort(data, offset, (short)(size - 2)); + LittleEndian.putUShort(data, offset, size - 2); int pos = offset + 2; - pos += Ptg.serializePtgStack(formulaTokens, data, pos); + pos += Ptg.serializePtgs(formulaTokens, data, pos); return size; } - public Object clone() - { - try - { - // todo: clone tokens? or are they immutable? - return super.clone(); - } - catch ( CloneNotSupportedException e ) - { - // should not happen - return null; - } - } - - public void setFormulaTokens( Stack formulaTokens ) + public void setFormulaTokens(Ptg[] ptgs) { - this.formulaTokens = (Stack) formulaTokens.clone(); + this.formulaTokens = (Ptg[])ptgs.clone(); } - public Stack getFormulaTokens() + public Ptg[] getFormulaTokens() { - return (Stack)this.formulaTokens.clone(); + return (Ptg[])this.formulaTokens.clone(); } + public LinkedDataFormulaField copy() { + LinkedDataFormulaField result = new LinkedDataFormulaField(); + + result.formulaTokens = getFormulaTokens(); + return result; + } } diff --git a/src/java/org/apache/poi/hssf/record/LinkedDataRecord.java b/src/java/org/apache/poi/hssf/record/LinkedDataRecord.java index 46610ec2bc..543418c353 100644 --- a/src/java/org/apache/poi/hssf/record/LinkedDataRecord.java +++ b/src/java/org/apache/poi/hssf/record/LinkedDataRecord.java @@ -125,7 +125,7 @@ public final class LinkedDataRecord extends Record { rec.field_2_referenceType = field_2_referenceType; rec.field_3_options = field_3_options; rec.field_4_indexNumberFmtRecord = field_4_indexNumberFmtRecord; - rec.field_5_formulaOfLink = ((LinkedDataFormulaField)field_5_formulaOfLink.clone()); + rec.field_5_formulaOfLink = field_5_formulaOfLink.copy(); return rec; } diff --git a/src/java/org/apache/poi/hssf/record/RecordFactory.java b/src/java/org/apache/poi/hssf/record/RecordFactory.java index 864065de77..7539e597da 100644 --- a/src/java/org/apache/poi/hssf/record/RecordFactory.java +++ b/src/java/org/apache/poi/hssf/record/RecordFactory.java @@ -321,51 +321,54 @@ public final class RecordFactory { Record lastRecord = null; while (recStream.hasNextRecord()) { recStream.nextRecord(); - if (recStream.getSid() != 0) { - Record[] recs = createRecord(recStream); // handle MulRK records + if (recStream.getSid() == 0) { + // After EOF, Excel seems to pad block with zeros + continue; + } + Record[] recs = createRecord(recStream); // handle MulRK records - if (recs.length > 1) { - for (int k = 0; k < recs.length; k++) { - records.add(recs[ k ]); // these will be number records - } - } else { - Record record = recs[ 0 ]; + if (recs.length > 1) { + for (int k = 0; k < recs.length; k++) { + records.add(recs[ k ]); // these will be number records + } + continue; + } + Record record = recs[ 0 ]; - if (record != null) { - if (record.getSid() == DrawingGroupRecord.sid - && lastRecord instanceof DrawingGroupRecord) { - DrawingGroupRecord lastDGRecord = (DrawingGroupRecord) lastRecord; - lastDGRecord.join((AbstractEscherHolderRecord) record); - } else if (record.getSid() == ContinueRecord.sid && - ((lastRecord instanceof ObjRecord) || (lastRecord instanceof TextObjectRecord))) { - // Drawing records have a very strange continue behaviour. - //There can actually be OBJ records mixed between the continues. - lastDrawingRecord.processContinueRecord( ((ContinueRecord)record).getData() ); - //we must remember the position of the continue record. - //in the serialization procedure the original structure of records must be preserved - records.add(record); - } else if (record.getSid() == ContinueRecord.sid && - (lastRecord instanceof DrawingGroupRecord)) { - ((DrawingGroupRecord)lastRecord).processContinueRecord(((ContinueRecord)record).getData()); - } else if (record.getSid() == ContinueRecord.sid && - (lastRecord instanceof StringRecord)) { - ((StringRecord)lastRecord).processContinueRecord(((ContinueRecord)record).getData()); - } else if (record.getSid() == ContinueRecord.sid) { - if (lastRecord instanceof UnknownRecord) { - //Gracefully handle records that we dont know about, - //that happen to be continued - records.add(record); - } else - throw new RecordFormatException("Unhandled Continue Record"); - } else { - lastRecord = record; - if (record instanceof DrawingRecord) { - lastDrawingRecord = (DrawingRecord) record; - } - records.add(record); - } - } + if (record == null) { + continue; + } + if (record.getSid() == DrawingGroupRecord.sid + && lastRecord instanceof DrawingGroupRecord) { + DrawingGroupRecord lastDGRecord = (DrawingGroupRecord) lastRecord; + lastDGRecord.join((AbstractEscherHolderRecord) record); + } else if (record.getSid() == ContinueRecord.sid) { + ContinueRecord contRec = (ContinueRecord)record; + + if (lastRecord instanceof ObjRecord || lastRecord instanceof TextObjectRecord) { + // Drawing records have a very strange continue behaviour. + //There can actually be OBJ records mixed between the continues. + lastDrawingRecord.processContinueRecord(contRec.getData() ); + //we must remember the position of the continue record. + //in the serialization procedure the original structure of records must be preserved + records.add(record); + } else if (lastRecord instanceof DrawingGroupRecord) { + ((DrawingGroupRecord)lastRecord).processContinueRecord(contRec.getData()); + } else if (lastRecord instanceof StringRecord) { + ((StringRecord)lastRecord).processContinueRecord(contRec.getData()); + } else if (lastRecord instanceof UnknownRecord) { + //Gracefully handle records that we don't know about, + //that happen to be continued + records.add(record); + } else { + throw new RecordFormatException("Unhandled Continue Record"); + } + } else { + lastRecord = record; + if (record instanceof DrawingRecord) { + lastDrawingRecord = (DrawingRecord) record; } + records.add(record); } } return records; diff --git a/src/java/org/apache/poi/hssf/record/RecordInputStream.java b/src/java/org/apache/poi/hssf/record/RecordInputStream.java index c23868c711..696f4fef7b 100755 --- a/src/java/org/apache/poi/hssf/record/RecordInputStream.java +++ b/src/java/org/apache/poi/hssf/record/RecordInputStream.java @@ -29,19 +29,19 @@ import java.io.ByteArrayOutputStream; * * @author Jason Height (jheight @ apache dot org) */ -public class RecordInputStream extends InputStream { - /** Maximum size of a single record (minus the 4 byte header) without a continue*/ - public final static short MAX_RECORD_DATA_SIZE = 8224; - private static final int INVALID_SID_VALUE = -1; +public final class RecordInputStream extends InputStream { + /** Maximum size of a single record (minus the 4 byte header) without a continue*/ + public final static short MAX_RECORD_DATA_SIZE = 8224; + private static final int INVALID_SID_VALUE = -1; - private InputStream in; - protected short currentSid; - protected short currentLength = -1; - protected short nextSid; + private InputStream in; + private short currentSid; + private short currentLength = -1; + private short nextSid; - protected byte[] data = new byte[MAX_RECORD_DATA_SIZE]; - protected short recordOffset; - protected long pos; + private final byte[] data = new byte[MAX_RECORD_DATA_SIZE]; + private short recordOffset; + private long pos; private boolean autoContinue = true; @@ -218,54 +218,81 @@ public class RecordInputStream extends InputStream { return result; } - /** - * given a byte array of 16-bit unicode characters, compress to 8-bit and - * return a string - * - * { 0x16, 0x00 } -0x16 - * - * @param length the length of the final string - * @return the converted string - * @exception IllegalArgumentException if len is too large (i.e., - * there is not enough data in string to create a String of that - * length) - */ - public String readUnicodeLEString(int length) { - if ((length < 0) || (((remaining() / 2) < length) && !isContinueNext())) { - throw new IllegalArgumentException("Illegal length - asked for " + length + " but only " + (remaining()/2) + " left!"); - } - - StringBuffer buf = new StringBuffer(length); - for (int i=0;i 0x100000) { // 16 million chars? + throw new IllegalArgumentException("Bad requested string length (" + requestedLength + ")"); + } + char[] buf = new char[requestedLength]; + boolean isCompressedEncoding = pIsCompressedEncoding; + int curLen = 0; + while(true) { + int availableChars =isCompressedEncoding ? remaining() : remaining() / LittleEndian.SHORT_SIZE; + if (requestedLength - curLen <= availableChars) { + // enough space in current record, so just read it out + while(curLen < requestedLength) { + char ch; + if (isCompressedEncoding) { + ch = (char)readUByte(); + } else { + ch = (char)readShort(); + } + buf[curLen] = ch; + curLen++; + } + return new String(buf); + } + // else string has been spilled into next continue record + // so read what's left of the current record + while(availableChars > 0) { + char ch; + if (isCompressedEncoding) { + ch = (char)readUByte(); + } else { + ch = (char)readShort(); + } + buf[curLen] = ch; + curLen++; + availableChars--; + } + if (!isContinueNext()) { + throw new RecordFormatException("Expected to find a ContinueRecord in order to read remaining " + + (requestedLength-curLen) + " of " + requestedLength + " chars"); + } + if(remaining() != 0) { + throw new RecordFormatException("Odd number of bytes(" + remaining() + ") left behind"); + } + nextRecord(); + // note - the compressed flag may change on the fly + byte compressFlag = readByte(); + isCompressedEncoding = (compressFlag == 0); + } + } /** Returns an excel style unicode string from the bytes reminaing in the record. * Note: Unicode strings differ from normal strings due to the addition of diff --git a/src/java/org/apache/poi/hssf/record/TextObjectBaseRecord.java b/src/java/org/apache/poi/hssf/record/TextObjectBaseRecord.java deleted file mode 100644 index 59e0cd2e66..0000000000 --- a/src/java/org/apache/poi/hssf/record/TextObjectBaseRecord.java +++ /dev/null @@ -1,427 +0,0 @@ - -/* ==================================================================== - 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.util.BitField; -import org.apache.poi.util.BitFieldFactory; -import org.apache.poi.util.HexDump; -import org.apache.poi.util.LittleEndian; - -/** - * The TXO record is used to define the properties of a text box. It is followed - * by two continue records unless there is no actual text. The first continue record contains - * the text data and the next continue record contains the formatting runs.

- * - * @author Glen Stampoultzis (glens at apache.org) - */ -public class TextObjectBaseRecord extends Record { - // TODO - don't instantiate superclass - public final static short sid = 0x01B6; - - private static final BitField reserved1 = BitFieldFactory.getInstance(0x0001); - private static final BitField HorizontalTextAlignment = BitFieldFactory.getInstance(0x000E); - private static final BitField VerticalTextAlignment = BitFieldFactory.getInstance(0x0070); - private static final BitField reserved2 = BitFieldFactory.getInstance(0x0180); - private static final BitField textLocked = BitFieldFactory.getInstance(0x0200); - private static final BitField reserved3 = BitFieldFactory.getInstance(0xFC00); - - private short field_1_options; - public final static short HORIZONTAL_TEXT_ALIGNMENT_LEFT_ALIGNED = 1; - public final static short HORIZONTAL_TEXT_ALIGNMENT_CENTERED = 2; - public final static short HORIZONTAL_TEXT_ALIGNMENT_RIGHT_ALIGNED = 3; - public final static short HORIZONTAL_TEXT_ALIGNMENT_JUSTIFIED = 4; - public final static short VERTICAL_TEXT_ALIGNMENT_TOP = 1; - public final static short VERTICAL_TEXT_ALIGNMENT_CENTER = 2; - public final static short VERTICAL_TEXT_ALIGNMENT_BOTTOM = 3; - public final static short VERTICAL_TEXT_ALIGNMENT_JUSTIFY = 4; - private short field_2_textOrientation; - public final static short TEXT_ORIENTATION_NONE = 0; - public final static short TEXT_ORIENTATION_TOP_TO_BOTTOM = 1; - public final static short TEXT_ORIENTATION_ROT_RIGHT = 2; - public final static short TEXT_ORIENTATION_ROT_LEFT = 3; - private short field_3_reserved4; - private short field_4_reserved5; - private short field_5_reserved6; - private short field_6_textLength; - private short field_7_formattingRunLength; - private int field_8_reserved7; - - - public TextObjectBaseRecord() - { - - } - - public TextObjectBaseRecord(RecordInputStream in) - { - field_1_options = in.readShort(); - field_2_textOrientation = in.readShort(); - field_3_reserved4 = in.readShort(); - field_4_reserved5 = in.readShort(); - field_5_reserved6 = in.readShort(); - field_6_textLength = in.readShort(); - field_7_formattingRunLength = in.readShort(); - field_8_reserved7 = in.readInt(); - - } - - public String toString() - { - StringBuffer buffer = new StringBuffer(); - - buffer.append("[TXO]\n"); - buffer.append(" .options = ") - .append("0x").append(HexDump.toHex( getOptions ())) - .append(" (").append( getOptions() ).append(" )"); - buffer.append(System.getProperty("line.separator")); - buffer.append(" .reserved1 = ").append(isReserved1()).append('\n'); - buffer.append(" .HorizontalTextAlignment = ").append(getHorizontalTextAlignment()).append('\n'); - buffer.append(" .VerticalTextAlignment = ").append(getVerticalTextAlignment()).append('\n'); - buffer.append(" .reserved2 = ").append(getReserved2()).append('\n'); - buffer.append(" .textLocked = ").append(isTextLocked()).append('\n'); - buffer.append(" .reserved3 = ").append(getReserved3()).append('\n'); - buffer.append(" .textOrientation = ") - .append("0x").append(HexDump.toHex( getTextOrientation ())) - .append(" (").append( getTextOrientation() ).append(" )"); - buffer.append(System.getProperty("line.separator")); - buffer.append(" .reserved4 = ") - .append("0x").append(HexDump.toHex( getReserved4 ())) - .append(" (").append( getReserved4() ).append(" )"); - buffer.append(System.getProperty("line.separator")); - buffer.append(" .reserved5 = ") - .append("0x").append(HexDump.toHex( getReserved5 ())) - .append(" (").append( getReserved5() ).append(" )"); - buffer.append(System.getProperty("line.separator")); - buffer.append(" .reserved6 = ") - .append("0x").append(HexDump.toHex( getReserved6 ())) - .append(" (").append( getReserved6() ).append(" )"); - buffer.append(System.getProperty("line.separator")); - buffer.append(" .textLength = ") - .append("0x").append(HexDump.toHex( getTextLength ())) - .append(" (").append( getTextLength() ).append(" )"); - buffer.append(System.getProperty("line.separator")); - buffer.append(" .formattingRunLength = ") - .append("0x").append(HexDump.toHex( getFormattingRunLength ())) - .append(" (").append( getFormattingRunLength() ).append(" )"); - buffer.append(System.getProperty("line.separator")); - buffer.append(" .reserved7 = ") - .append("0x").append(HexDump.toHex( getReserved7 ())) - .append(" (").append( getReserved7() ).append(" )"); - buffer.append(System.getProperty("line.separator")); - - buffer.append("[/TXO]\n"); - return buffer.toString(); - } - - public int serialize(int offset, byte[] data) - { - int pos = 0; - - LittleEndian.putShort(data, 0 + offset, sid); - LittleEndian.putShort(data, 2 + offset, (short)(getRecordSize() - 4)); - - LittleEndian.putShort(data, 4 + offset + pos, field_1_options); - LittleEndian.putShort(data, 6 + offset + pos, field_2_textOrientation); - LittleEndian.putShort(data, 8 + offset + pos, field_3_reserved4); - LittleEndian.putShort(data, 10 + offset + pos, field_4_reserved5); - LittleEndian.putShort(data, 12 + offset + pos, field_5_reserved6); - LittleEndian.putShort(data, 14 + offset + pos, field_6_textLength); - LittleEndian.putShort(data, 16 + offset + pos, field_7_formattingRunLength); - LittleEndian.putInt(data, 18 + offset + pos, field_8_reserved7); - - return getRecordSize(); - } - - public int getRecordSize() - { - return 4 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 4; - } - - public short getSid() - { - return sid; - } - - public Object clone() { - TextObjectBaseRecord rec = new TextObjectBaseRecord(); - - rec.field_1_options = field_1_options; - rec.field_2_textOrientation = field_2_textOrientation; - rec.field_3_reserved4 = field_3_reserved4; - rec.field_4_reserved5 = field_4_reserved5; - rec.field_5_reserved6 = field_5_reserved6; - rec.field_6_textLength = field_6_textLength; - rec.field_7_formattingRunLength = field_7_formattingRunLength; - rec.field_8_reserved7 = field_8_reserved7; - return rec; - } - - - - - /** - * Get the options field for the TextObjectBase record. - */ - public short getOptions() - { - return field_1_options; - } - - /** - * Set the options field for the TextObjectBase record. - */ - public void setOptions(short field_1_options) - { - this.field_1_options = field_1_options; - } - - /** - * Get the text orientation field for the TextObjectBase record. - * - * @return One of - * TEXT_ORIENTATION_NONE - * TEXT_ORIENTATION_TOP_TO_BOTTOM - * TEXT_ORIENTATION_ROT_RIGHT - * TEXT_ORIENTATION_ROT_LEFT - */ - public short getTextOrientation() - { - return field_2_textOrientation; - } - - /** - * Set the text orientation field for the TextObjectBase record. - * - * @param field_2_textOrientation - * One of - * TEXT_ORIENTATION_NONE - * TEXT_ORIENTATION_TOP_TO_BOTTOM - * TEXT_ORIENTATION_ROT_RIGHT - * TEXT_ORIENTATION_ROT_LEFT - */ - public void setTextOrientation(short field_2_textOrientation) - { - this.field_2_textOrientation = field_2_textOrientation; - } - - /** - * Get the reserved4 field for the TextObjectBase record. - */ - public short getReserved4() - { - return field_3_reserved4; - } - - /** - * Set the reserved4 field for the TextObjectBase record. - */ - public void setReserved4(short field_3_reserved4) - { - this.field_3_reserved4 = field_3_reserved4; - } - - /** - * Get the reserved5 field for the TextObjectBase record. - */ - public short getReserved5() - { - return field_4_reserved5; - } - - /** - * Set the reserved5 field for the TextObjectBase record. - */ - public void setReserved5(short field_4_reserved5) - { - this.field_4_reserved5 = field_4_reserved5; - } - - /** - * Get the reserved6 field for the TextObjectBase record. - */ - public short getReserved6() - { - return field_5_reserved6; - } - - /** - * Set the reserved6 field for the TextObjectBase record. - */ - public void setReserved6(short field_5_reserved6) - { - this.field_5_reserved6 = field_5_reserved6; - } - - /** - * Get the text length field for the TextObjectBase record. - */ - public short getTextLength() - { - return field_6_textLength; - } - - /** - * Set the text length field for the TextObjectBase record. - */ - public void setTextLength(short field_6_textLength) - { - this.field_6_textLength = field_6_textLength; - } - - /** - * Get the formatting run length field for the TextObjectBase record. - */ - public short getFormattingRunLength() - { - return field_7_formattingRunLength; - } - - /** - * Set the formatting run length field for the TextObjectBase record. - */ - public void setFormattingRunLength(short field_7_formattingRunLength) - { - this.field_7_formattingRunLength = field_7_formattingRunLength; - } - - /** - * Get the reserved7 field for the TextObjectBase record. - */ - public int getReserved7() - { - return field_8_reserved7; - } - - /** - * Set the reserved7 field for the TextObjectBase record. - */ - public void setReserved7(int field_8_reserved7) - { - this.field_8_reserved7 = field_8_reserved7; - } - - /** - * Sets the reserved1 field value. - * reserved field - */ - public void setReserved1(boolean value) - { - field_1_options = reserved1.setShortBoolean(field_1_options, value); - } - - /** - * reserved field - * @return the reserved1 field value. - */ - public boolean isReserved1() - { - return reserved1.isSet(field_1_options); - } - - /** - * Sets the Horizontal text alignment field value. - * - */ - public void setHorizontalTextAlignment(short value) - { - field_1_options = HorizontalTextAlignment.setShortValue(field_1_options, value); - } - - /** - * - * @return the Horizontal text alignment field value. - */ - public short getHorizontalTextAlignment() - { - return HorizontalTextAlignment.getShortValue(field_1_options); - } - - /** - * Sets the Vertical text alignment field value. - * - */ - public void setVerticalTextAlignment(short value) - { - field_1_options = VerticalTextAlignment.setShortValue(field_1_options, value); - } - - /** - * - * @return the Vertical text alignment field value. - */ - public short getVerticalTextAlignment() - { - return VerticalTextAlignment.getShortValue(field_1_options); - } - - /** - * Sets the reserved2 field value. - * - */ - public void setReserved2(short value) - { - field_1_options = reserved2.setShortValue(field_1_options, value); - } - - /** - * - * @return the reserved2 field value. - */ - public short getReserved2() - { - return reserved2.getShortValue(field_1_options); - } - - /** - * Sets the text locked field value. - * Text has been locked - */ - public void setTextLocked(boolean value) - { - field_1_options = textLocked.setShortBoolean(field_1_options, value); - } - - /** - * Text has been locked - * @return the text locked field value. - */ - public boolean isTextLocked() - { - return textLocked.isSet(field_1_options); - } - - /** - * Sets the reserved3 field value. - * - */ - public void setReserved3(short value) - { - field_1_options = reserved3.setShortValue(field_1_options, value); - } - - /** - * - * @return the reserved3 field value. - */ - public short getReserved3() - { - return reserved3.getShortValue(field_1_options); - } -} diff --git a/src/java/org/apache/poi/hssf/record/TextObjectRecord.java b/src/java/org/apache/poi/hssf/record/TextObjectRecord.java index 600aaf1542..6529dc93f8 100644 --- a/src/java/org/apache/poi/hssf/record/TextObjectRecord.java +++ b/src/java/org/apache/poi/hssf/record/TextObjectRecord.java @@ -19,253 +19,427 @@ package org.apache.poi.hssf.record; import java.io.UnsupportedEncodingException; +import org.apache.poi.hssf.record.formula.Ptg; import org.apache.poi.hssf.usermodel.HSSFRichTextString; +import org.apache.poi.util.BitField; +import org.apache.poi.util.BitFieldFactory; import org.apache.poi.util.HexDump; import org.apache.poi.util.LittleEndian; -public class TextObjectRecord - extends TextObjectBaseRecord -{ - HSSFRichTextString str; - - public TextObjectRecord() - { - } - - public TextObjectRecord( RecordInputStream in ) - { - super( in ); - - if (getTextLength() > 0) { - if (in.isContinueNext() && in.remaining() == 0) { - //1st Continue - in.nextRecord(); - processRawString(in); - } else - throw new RecordFormatException("Expected Continue record to hold string data for TextObjectRecord"); - } - if (getFormattingRunLength() > 0) { - if (in.isContinueNext() && in.remaining() == 0) { - in.nextRecord(); - processFontRuns(in); - } else throw new RecordFormatException("Expected Continue Record to hold font runs for TextObjectRecord"); - } - if (str == null) - str = new HSSFRichTextString(""); - } - - - public int getRecordSize() - { - int continue1Size = 0; - int continue2Size = 0; - if (str.length() != 0) - { - int length = str.length() * 2; - while(length > 0){ - int chunkSize = Math.min(RecordInputStream.MAX_RECORD_DATA_SIZE-2, length); - length -= chunkSize; - - continue1Size += chunkSize; - continue1Size += 1 + 4; - } - - continue2Size = (str.numFormattingRuns() + 1) * 8 + 4; - } - return super.getRecordSize() + continue1Size + continue2Size; - } - - - - public int serialize( int offset, byte[] data ) - { - // Temporarily blank out str so that record size is calculated without the continue records. - HSSFRichTextString temp = str; - str = new HSSFRichTextString(""); - int bytesWritten1 = super.serialize( offset, data ); - str = temp; - - int pos = offset + bytesWritten1; - if ( str.getString().equals( "" ) == false ) - { - ContinueRecord c2 = createContinue2(); - int bytesWritten2 = 0; - - try - { - byte[] c1Data = str.getString().getBytes( "UTF-16LE" ); - int length = c1Data.length; - - int charsWritten = 0; - int spos = pos; - while(length > 0){ - int chunkSize = Math.min(RecordInputStream.MAX_RECORD_DATA_SIZE-2 , length); - length -= chunkSize; - - //continue header - LittleEndian.putShort(data, spos, ContinueRecord.sid); - spos += LittleEndian.SHORT_SIZE; - LittleEndian.putShort(data, spos, (short)(chunkSize+1)); - spos += LittleEndian.SHORT_SIZE; - - //The first byte specifies if the text is compressed unicode or unicode. - //(regardless what was read, we always serialize double-byte unicode characters (UTF-16LE). - data[spos] = 1; - spos += LittleEndian.BYTE_SIZE; - - //copy characters data - System.arraycopy(c1Data, charsWritten, data, spos, chunkSize); - spos += chunkSize; - charsWritten += chunkSize; - } - - bytesWritten2 = (spos-pos); - } - catch ( UnsupportedEncodingException e ) - { - throw new RuntimeException( e.getMessage(), e ); - } - - pos += bytesWritten2; - int bytesWritten3 = c2.serialize( pos, data ); - pos += bytesWritten3; - - int size = bytesWritten1 + bytesWritten2 + bytesWritten3; - if ( size != getRecordSize() ) - throw new RecordFormatException(size + " bytes written but getRecordSize() reports " + getRecordSize()); - return size; - } - if ( bytesWritten1 != getRecordSize() ) - throw new RecordFormatException(bytesWritten1 + " bytes written but getRecordSize() reports " + getRecordSize()); - return bytesWritten1; - } - - private ContinueRecord createContinue2() - { - ContinueRecord c2 = new ContinueRecord(); - byte[] c2Data = new byte[str.numFormattingRuns() * 8 + 8]; - int pos = 0; - for ( int i = 0; i < str.numFormattingRuns(); i++ ) - { - LittleEndian.putShort( c2Data, pos, (short) str.getIndexOfFormattingRun( i ) ); - pos += 2; - LittleEndian.putShort( c2Data, pos, str.getFontOfFormattingRun( i ) == str.NO_FONT ? 0 : str.getFontOfFormattingRun( i ) ); - pos += 2; - pos += 4; // skip reserved - } - LittleEndian.putShort( c2Data, pos, (short) str.length() ); - pos += 2; - LittleEndian.putShort( c2Data, pos, (short) 0 ); - pos += 2; - pos += 4; // skip reserved - - c2.setData( c2Data ); - - return c2; - } - - private void processFontRuns( RecordInputStream in ) - { - while (in.remaining() > 0) - { - short index = in.readShort(); - short iFont = in.readShort(); - in.readInt(); // skip reserved. - - str.applyFont( index, str.length(), iFont ); - } - } - - private void processRawString( RecordInputStream in ) - { - String s; - byte compressByte = in.readByte(); - boolean isCompressed = compressByte == 0; - if ( isCompressed ) - { - s = in.readCompressedUnicode(getTextLength()); - } - else - { - s = in.readUnicodeLEString(getTextLength()); - } - str = new HSSFRichTextString( s ); - } - - public HSSFRichTextString getStr() - { - return str; - } - - public void setStr( HSSFRichTextString str ) - { - this.str = str; - } - - public String toString() - { - StringBuffer buffer = new StringBuffer(); - - buffer.append( "[TXO]\n" ); - buffer.append( " .options = " ) - .append( "0x" ).append( HexDump.toHex( getOptions() ) ) - .append( " (" ).append( getOptions() ).append( " )" ); - buffer.append( System.getProperty( "line.separator" ) ); - buffer.append( " .reserved1 = " ).append( isReserved1() ).append( '\n' ); - buffer.append( " .HorizontalTextAlignment = " ).append( getHorizontalTextAlignment() ).append( '\n' ); - buffer.append( " .VerticalTextAlignment = " ).append( getVerticalTextAlignment() ).append( '\n' ); - buffer.append( " .reserved2 = " ).append( getReserved2() ).append( '\n' ); - buffer.append( " .textLocked = " ).append( isTextLocked() ).append( '\n' ); - buffer.append( " .reserved3 = " ).append( getReserved3() ).append( '\n' ); - buffer.append( " .textOrientation = " ) - .append( "0x" ).append( HexDump.toHex( getTextOrientation() ) ) - .append( " (" ).append( getTextOrientation() ).append( " )" ); - buffer.append( System.getProperty( "line.separator" ) ); - buffer.append( " .reserved4 = " ) - .append( "0x" ).append( HexDump.toHex( getReserved4() ) ) - .append( " (" ).append( getReserved4() ).append( " )" ); - buffer.append( System.getProperty( "line.separator" ) ); - buffer.append( " .reserved5 = " ) - .append( "0x" ).append( HexDump.toHex( getReserved5() ) ) - .append( " (" ).append( getReserved5() ).append( " )" ); - buffer.append( System.getProperty( "line.separator" ) ); - buffer.append( " .reserved6 = " ) - .append( "0x" ).append( HexDump.toHex( getReserved6() ) ) - .append( " (" ).append( getReserved6() ).append( " )" ); - buffer.append( System.getProperty( "line.separator" ) ); - buffer.append( " .textLength = " ) - .append( "0x" ).append( HexDump.toHex( getTextLength() ) ) - .append( " (" ).append( getTextLength() ).append( " )" ); - buffer.append( System.getProperty( "line.separator" ) ); - buffer.append( " .reserved7 = " ) - .append( "0x" ).append( HexDump.toHex( getReserved7() ) ) - .append( " (" ).append( getReserved7() ).append( " )" ); - buffer.append( System.getProperty( "line.separator" ) ); - - buffer.append( " .string = " ).append(str).append('\n'); - - for (int i = 0; i < str.numFormattingRuns(); i++) { - buffer.append( " .textrun = " ).append(str.getFontOfFormattingRun(i)).append('\n'); - - } - buffer.append( "[/TXO]\n" ); - return buffer.toString(); - } - - public Object clone() { - - TextObjectRecord rec = new TextObjectRecord(); - rec.str = str; - - rec.setOptions(getOptions()); - rec.setTextOrientation(getTextOrientation()); - rec.setReserved4(getReserved4()); - rec.setReserved5(getReserved5()); - rec.setReserved6(getReserved6()); - rec.setTextLength(getTextLength()); - rec.setFormattingRunLength(getFormattingRunLength()); - rec.setReserved7(getReserved7()); - return rec; - } - +/** + * The TXO record (0x01B6) is used to define the properties of a text box. It is + * followed by two or more continue records unless there is no actual text. The + * first continue records contain the text data and the last continue record + * contains the formatting runs.

+ * + * @author Glen Stampoultzis (glens at apache.org) + */ +public final class TextObjectRecord extends Record { + public final static short sid = 0x01B6; + + private static final int FORMAT_RUN_ENCODED_SIZE = 8; // 2 shorts and 4 bytes reserved + + private static final BitField HorizontalTextAlignment = BitFieldFactory.getInstance(0x000E); + private static final BitField VerticalTextAlignment = BitFieldFactory.getInstance(0x0070); + private static final BitField textLocked = BitFieldFactory.getInstance(0x0200); + + public final static short HORIZONTAL_TEXT_ALIGNMENT_LEFT_ALIGNED = 1; + public final static short HORIZONTAL_TEXT_ALIGNMENT_CENTERED = 2; + public final static short HORIZONTAL_TEXT_ALIGNMENT_RIGHT_ALIGNED = 3; + public final static short HORIZONTAL_TEXT_ALIGNMENT_JUSTIFIED = 4; + public final static short VERTICAL_TEXT_ALIGNMENT_TOP = 1; + public final static short VERTICAL_TEXT_ALIGNMENT_CENTER = 2; + public final static short VERTICAL_TEXT_ALIGNMENT_BOTTOM = 3; + public final static short VERTICAL_TEXT_ALIGNMENT_JUSTIFY = 4; + + public final static short TEXT_ORIENTATION_NONE = 0; + public final static short TEXT_ORIENTATION_TOP_TO_BOTTOM = 1; + public final static short TEXT_ORIENTATION_ROT_RIGHT = 2; + public final static short TEXT_ORIENTATION_ROT_LEFT = 3; + + private int field_1_options; + private int field_2_textOrientation; + private int field_3_reserved4; + private int field_4_reserved5; + private int field_5_reserved6; + private int field_8_reserved7; + + private HSSFRichTextString _text; + + /* + * Note - the next three fields are very similar to those on + * EmbededObjectRefSubRecord(ftPictFmla 0x0009) + * + * some observed values for the 4 bytes preceding the formula: C0 5E 86 03 + * C0 11 AC 02 80 F1 8A 03 D4 F0 8A 03 + */ + private int _unknownPreFormulaInt; + /** expect tRef, tRef3D, tArea, tArea3D or tName */ + private Ptg _linkRefPtg; + /** + * Not clear if needed . Excel seems to be OK if this byte is not present. + * Value is often the same as the earlier firstColumn byte. */ + private Byte _unknownPostFormulaByte; + + public TextObjectRecord() { + } + + public TextObjectRecord(RecordInputStream in) { + field_1_options = in.readUShort(); + field_2_textOrientation = in.readUShort(); + field_3_reserved4 = in.readUShort(); + field_4_reserved5 = in.readUShort(); + field_5_reserved6 = in.readUShort(); + int field_6_textLength = in.readUShort(); + int field_7_formattingDataLength = in.readUShort(); + field_8_reserved7 = in.readInt(); + + if (in.remaining() > 0) { + // Text Objects can have simple reference formulas + // (This bit not mentioned in the MS document) + if (in.remaining() < 11) { + throw new RecordFormatException("Not enough remaining data for a link formula"); + } + int formulaSize = in.readUShort(); + _unknownPreFormulaInt = in.readInt(); + Ptg[] ptgs = Ptg.readTokens(formulaSize, in); + if (ptgs.length != 1) { + throw new RecordFormatException("Read " + ptgs.length + + " tokens but expected exactly 1"); + } + _linkRefPtg = ptgs[0]; + if (in.remaining() > 0) { + _unknownPostFormulaByte = new Byte(in.readByte()); + } else { + _unknownPostFormulaByte = null; + } + } else { + _linkRefPtg = null; + } + if (in.remaining() > 0) { + throw new RecordFormatException("Unused " + in.remaining() + " bytes at end of record"); + } + + String text; + if (field_6_textLength > 0) { + text = readRawString(in, field_6_textLength); + } else { + text = ""; + } + _text = new HSSFRichTextString(text); + + if (field_7_formattingDataLength > 0) { + if (in.isContinueNext() && in.remaining() == 0) { + in.nextRecord(); + processFontRuns(in, _text, field_7_formattingDataLength); + } else { + throw new RecordFormatException( + "Expected Continue Record to hold font runs for TextObjectRecord"); + } + } + } + + private static String readRawString(RecordInputStream in, int textLength) { + byte compressByte = in.readByte(); + boolean isCompressed = (compressByte & 0x01) == 0; + if (isCompressed) { + return in.readCompressedUnicode(textLength); + } + return in.readUnicodeLEString(textLength); + } + + private static void processFontRuns(RecordInputStream in, HSSFRichTextString str, + int formattingRunDataLength) { + if (formattingRunDataLength % FORMAT_RUN_ENCODED_SIZE != 0) { + throw new RecordFormatException("Bad format run data length " + formattingRunDataLength + + ")"); + } + if (in.remaining() != formattingRunDataLength) { + throw new RecordFormatException("Expected " + formattingRunDataLength + + " bytes but got " + in.remaining()); + } + int nRuns = formattingRunDataLength / FORMAT_RUN_ENCODED_SIZE; + for (int i = 0; i < nRuns; i++) { + short index = in.readShort(); + short iFont = in.readShort(); + in.readInt(); // skip reserved. + str.applyFont(index, str.length(), iFont); + } + } + + public short getSid() { + return sid; + } + + /** + * Only for the current record. does not include any subsequent Continue + * records + */ + private int getDataSize() { + int result = 2 + 2 + 2 + 2 + 2 + 2 + 2 + 4; + if (_linkRefPtg != null) { + result += 2 // formula size + + 4 // unknownInt + +_linkRefPtg.getSize(); + if (_unknownPostFormulaByte != null) { + result += 1; + } + } + return result; + } + + private int serializeTXORecord(int offset, byte[] data) { + int dataSize = getDataSize(); + + LittleEndian.putUShort(data, 0 + offset, TextObjectRecord.sid); + LittleEndian.putUShort(data, 2 + offset, dataSize); + + + LittleEndian.putUShort(data, 4 + offset, field_1_options); + LittleEndian.putUShort(data, 6 + offset, field_2_textOrientation); + LittleEndian.putUShort(data, 8 + offset, field_3_reserved4); + LittleEndian.putUShort(data, 10 + offset, field_4_reserved5); + LittleEndian.putUShort(data, 12 + offset, field_5_reserved6); + LittleEndian.putUShort(data, 14 + offset, _text.length()); + LittleEndian.putUShort(data, 16 + offset, getFormattingDataLength()); + LittleEndian.putInt(data, 18 + offset, field_8_reserved7); + + if (_linkRefPtg != null) { + int pos = offset+22; + int formulaSize = _linkRefPtg.getSize(); + LittleEndian.putUShort(data, pos, formulaSize); + pos += LittleEndian.SHORT_SIZE; + LittleEndian.putInt(data, pos, _unknownPreFormulaInt); + pos += LittleEndian.INT_SIZE; + _linkRefPtg.writeBytes(data, pos); + pos += formulaSize; + if (_unknownPostFormulaByte != null) { + LittleEndian.putByte(data, pos, _unknownPostFormulaByte.byteValue()); + pos += LittleEndian.BYTE_SIZE; + } + } + + return 4 + dataSize; + } + + private int serializeTrailingRecords(int offset, byte[] data) { + byte[] textBytes; + try { + textBytes = _text.getString().getBytes("UTF-16LE"); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e.getMessage(), e); + } + int remainingLength = textBytes.length; + + int countTextBytesWritten = 0; + int pos = offset; + // (regardless what was read, we always serialize double-byte + // unicode characters (UTF-16LE). + Byte unicodeFlag = new Byte((byte)1); + while (remainingLength > 0) { + int chunkSize = Math.min(RecordInputStream.MAX_RECORD_DATA_SIZE - 2, remainingLength); + remainingLength -= chunkSize; + pos += ContinueRecord.write(data, pos, unicodeFlag, textBytes, countTextBytesWritten, chunkSize); + countTextBytesWritten += chunkSize; + } + + byte[] formatData = createFormatData(_text); + pos += ContinueRecord.write(data, pos, null, formatData); + return pos - offset; + } + + private int getTrailingRecordsSize() { + if (_text.length() < 1) { + return 0; + } + int encodedTextSize = 0; + int textBytesLength = _text.length() * LittleEndian.SHORT_SIZE; + while (textBytesLength > 0) { + int chunkSize = Math.min(RecordInputStream.MAX_RECORD_DATA_SIZE - 2, textBytesLength); + textBytesLength -= chunkSize; + + encodedTextSize += 4; // +4 for ContinueRecord sid+size + encodedTextSize += 1+chunkSize; // +1 for compressed unicode flag, + } + + int encodedFormatSize = (_text.numFormattingRuns() + 1) * FORMAT_RUN_ENCODED_SIZE + + 4; // +4 for ContinueRecord sid+size + return encodedTextSize + encodedFormatSize; + } + + + public int serialize(int offset, byte[] data) { + + int expectedTotalSize = getRecordSize(); + int totalSize = serializeTXORecord(offset, data); + + if (_text.getString().length() > 0) { + totalSize += serializeTrailingRecords(offset+totalSize, data); + } + + if (totalSize != expectedTotalSize) + throw new RecordFormatException(totalSize + + " bytes written but getRecordSize() reports " + expectedTotalSize); + return totalSize; + } + + /** + * Note - this total size includes all potential {@link ContinueRecord}s written + */ + public int getRecordSize() { + int baseSize = 4 + getDataSize(); + return baseSize + getTrailingRecordsSize(); + } + + + private int getFormattingDataLength() { + if (_text.length() < 1) { + // important - no formatting data if text is empty + return 0; + } + return (_text.numFormattingRuns() + 1) * FORMAT_RUN_ENCODED_SIZE; + } + + private static byte[] createFormatData(HSSFRichTextString str) { + int nRuns = str.numFormattingRuns(); + byte[] result = new byte[(nRuns + 1) * FORMAT_RUN_ENCODED_SIZE]; + int pos = 0; + for (int i = 0; i < nRuns; i++) { + LittleEndian.putUShort(result, pos, str.getIndexOfFormattingRun(i)); + pos += 2; + int fontIndex = str.getFontOfFormattingRun(i); + LittleEndian.putUShort(result, pos, fontIndex == str.NO_FONT ? 0 : fontIndex); + pos += 2; + pos += 4; // skip reserved + } + LittleEndian.putUShort(result, pos, str.length()); + pos += 2; + LittleEndian.putUShort(result, pos, 0); + pos += 2; + pos += 4; // skip reserved + + return result; + } + + /** + * Sets the Horizontal text alignment field value. + */ + public void setHorizontalTextAlignment(int value) { + field_1_options = HorizontalTextAlignment.setValue(field_1_options, value); + } + + /** + * @return the Horizontal text alignment field value. + */ + public int getHorizontalTextAlignment() { + return HorizontalTextAlignment.getValue(field_1_options); + } + + /** + * Sets the Vertical text alignment field value. + */ + public void setVerticalTextAlignment(int value) { + field_1_options = VerticalTextAlignment.setValue(field_1_options, value); + } + + /** + * @return the Vertical text alignment field value. + */ + public int getVerticalTextAlignment() { + return VerticalTextAlignment.getValue(field_1_options); + } + + /** + * Sets the text locked field value. + */ + public void setTextLocked(boolean value) { + field_1_options = textLocked.setBoolean(field_1_options, value); + } + + /** + * @return the text locked field value. + */ + public boolean isTextLocked() { + return textLocked.isSet(field_1_options); + } + + /** + * Get the text orientation field for the TextObjectBase record. + * + * @return One of TEXT_ORIENTATION_NONE TEXT_ORIENTATION_TOP_TO_BOTTOM + * TEXT_ORIENTATION_ROT_RIGHT TEXT_ORIENTATION_ROT_LEFT + */ + public int getTextOrientation() { + return field_2_textOrientation; + } + + /** + * Set the text orientation field for the TextObjectBase record. + * + * @param textOrientation + * One of TEXT_ORIENTATION_NONE TEXT_ORIENTATION_TOP_TO_BOTTOM + * TEXT_ORIENTATION_ROT_RIGHT TEXT_ORIENTATION_ROT_LEFT + */ + public void setTextOrientation(int textOrientation) { + this.field_2_textOrientation = textOrientation; + } + + public HSSFRichTextString getStr() { + return _text; + } + + public void setStr(HSSFRichTextString str) { + _text = str; + } + + public Ptg getLinkRefPtg() { + return _linkRefPtg; + } + + public String toString() { + StringBuffer sb = new StringBuffer(); + + sb.append("[TXO]\n"); + sb.append(" .options = ").append(HexDump.shortToHex(field_1_options)).append("\n"); + sb.append(" .isHorizontal = ").append(getHorizontalTextAlignment()).append('\n'); + sb.append(" .isVertical = ").append(getVerticalTextAlignment()).append('\n'); + sb.append(" .textLocked = ").append(isTextLocked()).append('\n'); + sb.append(" .textOrientation= ").append(HexDump.shortToHex(getTextOrientation())).append("\n"); + sb.append(" .reserved4 = ").append(HexDump.shortToHex(field_3_reserved4)).append("\n"); + sb.append(" .reserved5 = ").append(HexDump.shortToHex(field_4_reserved5)).append("\n"); + sb.append(" .reserved6 = ").append(HexDump.shortToHex(field_5_reserved6)).append("\n"); + sb.append(" .textLength = ").append(HexDump.shortToHex(_text.length())).append("\n"); + sb.append(" .reserved7 = ").append(HexDump.intToHex(field_8_reserved7)).append("\n"); + + sb.append(" .string = ").append(_text).append('\n'); + + for (int i = 0; i < _text.numFormattingRuns(); i++) { + sb.append(" .textrun = ").append(_text.getFontOfFormattingRun(i)).append('\n'); + + } + sb.append("[/TXO]\n"); + return sb.toString(); + } + + public Object clone() { + + TextObjectRecord rec = new TextObjectRecord(); + rec._text = _text; + + rec.field_1_options = field_1_options; + rec.field_2_textOrientation = field_2_textOrientation; + rec.field_3_reserved4 = field_3_reserved4; + rec.field_4_reserved5 = field_4_reserved5; + rec.field_5_reserved6 = field_5_reserved6; + rec.field_8_reserved7 = field_8_reserved7; + + rec._text = _text; // clone needed? + + if (_linkRefPtg != null) { + rec._unknownPreFormulaInt = _unknownPreFormulaInt; + rec._linkRefPtg = _linkRefPtg.copy(); + rec._unknownPostFormulaByte = rec._unknownPostFormulaByte; + } + return rec; + } } diff --git a/src/java/org/apache/poi/hssf/record/formula/Ptg.java b/src/java/org/apache/poi/hssf/record/formula/Ptg.java index 4b952b65f7..55fac1b0b0 100644 --- a/src/java/org/apache/poi/hssf/record/formula/Ptg.java +++ b/src/java/org/apache/poi/hssf/record/formula/Ptg.java @@ -19,10 +19,8 @@ package org.apache.poi.hssf.record.formula; import java.util.ArrayList; import java.util.List; -import java.util.Stack; import org.apache.poi.hssf.record.RecordInputStream; -import org.apache.poi.hssf.usermodel.HSSFWorkbook; /** * Ptg represents a syntactic token in a formula. 'PTG' is an acronym for @@ -49,15 +47,7 @@ public abstract class Ptg implements Cloneable { * Extra data (beyond size) may be read if and ArrayPtgs are present. */ public static Ptg[] readTokens(int size, RecordInputStream in) { - Stack temp = createParsedExpressionTokens((short)size, in); - return toPtgArray(temp); - } - - /** - * @deprecated - use readTokens() - */ - public static Stack createParsedExpressionTokens(short size, RecordInputStream in) { - Stack stack = new Stack(); + List temp = new ArrayList(4 + size / 2); int pos = 0; List arrayPtgs = null; while (pos < size) { @@ -71,7 +61,7 @@ public abstract class Ptg implements Cloneable { } else { pos += ptg.getSize(); } - stack.push( ptg ); + temp.add( ptg ); } if(pos != size) { throw new RuntimeException("Ptg array size mismatch"); @@ -82,7 +72,7 @@ public abstract class Ptg implements Cloneable { p.readTokenValues(in); } } - return stack; + return toPtgArray(temp); } public static Ptg createPtg(RecordInputStream in) { @@ -200,19 +190,11 @@ public abstract class Ptg implements Cloneable { l.toArray(result); return result; } - private static Stack createStack(Ptg[] formulaTokens) { - Stack result = new Stack(); - for (int i = 0; i < formulaTokens.length; i++) { - result.add(formulaTokens[i]); - } - return result; - } /** * This method will return the same result as {@link #getEncodedSizeWithoutArrayData(Ptg[])} * if there are no array tokens present. * @return the full size taken to encode the specified Ptgs */ - // TODO - several duplicates of this code should be refactored here public static int getEncodedSize(Ptg[] ptgs) { int result = 0; for (int i = 0; i < ptgs.length; i++) { @@ -243,23 +225,14 @@ public abstract class Ptg implements Cloneable { * The 2 byte encode length field is not written by this method. * @return number of bytes written */ - public static int serializePtgs(Ptg[] ptgs, byte[] data, int offset) { - return serializePtgStack(createStack(ptgs), data, offset); - } - - /** - * @deprecated use serializePtgs() - */ - public static int serializePtgStack(Stack expression, byte[] array, int offset) { + public static int serializePtgs(Ptg[] ptgs, byte[] array, int offset) { int pos = 0; - int size = 0; - if (expression != null) - size = expression.size(); + int size = ptgs.length; List arrayPtgs = null; for (int k = 0; k < size; k++) { - Ptg ptg = ( Ptg ) expression.get(k); + Ptg ptg = ptgs[k]; ptg.writeBytes(array, pos + offset); if (ptg instanceof ArrayPtg) { diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFComment.java b/src/java/org/apache/poi/hssf/usermodel/HSSFComment.java index 0c8a16e420..3d28fc1e25 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFComment.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFComment.java @@ -149,10 +149,7 @@ public class HSSFComment extends HSSFTextbox implements Comment { if (hstring.numFormattingRuns() == 0) hstring.applyFont((short)0); if (txo != null) { - int frLength = ( hstring.numFormattingRuns() + 1 ) * 8; - txo.setFormattingRunLength( (short) frLength ); - txo.setTextLength( (short) hstring.length() ); - txo.setStr( hstring ); + txo.setStr(hstring); } super.setString(string); } diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFRichTextString.java b/src/java/org/apache/poi/hssf/usermodel/HSSFRichTextString.java index ce5a40acbf..9d57c99a43 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFRichTextString.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFRichTextString.java @@ -196,7 +196,7 @@ public class HSSFRichTextString /** - * @return the number of characters in the font. + * @return the number of characters in the text. */ public int length() { diff --git a/src/scratchpad/src/org/apache/poi/hssf/usermodel/HSSFChart.java b/src/scratchpad/src/org/apache/poi/hssf/usermodel/HSSFChart.java index 3a7c5c20e0..3b1fd1e1e7 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/usermodel/HSSFChart.java +++ b/src/scratchpad/src/org/apache/poi/hssf/usermodel/HSSFChart.java @@ -20,7 +20,6 @@ package org.apache.poi.hssf.usermodel; import java.util.ArrayList; import java.util.Iterator; import java.util.List; -import java.util.Stack; import org.apache.poi.hssf.record.AreaFormatRecord; import org.apache.poi.hssf.record.AxisLineFormatRecord; @@ -68,6 +67,7 @@ import org.apache.poi.hssf.record.UnknownRecord; import org.apache.poi.hssf.record.VCenterRecord; import org.apache.poi.hssf.record.ValueRangeRecord; import org.apache.poi.hssf.record.formula.Area3DPtg; +import org.apache.poi.hssf.record.formula.Ptg; /** * Has methods for construction of a chart object. @@ -759,11 +759,9 @@ public final class HSSFChart { r.setCustomNumberFormat( false ); r.setIndexNumberFmtRecord( (short) 0 ); LinkedDataFormulaField formula = new LinkedDataFormulaField(); - Stack tokens = new Stack(); Area3DPtg p = new Area3DPtg(0, 31, 1, 1, false, false, false, false, 0); - tokens.add( p ); - formula.setFormulaTokens( tokens ); + formula.setFormulaTokens(new Ptg[] { p, }); r.setFormulaOfLink( formula ); return r; } @@ -776,11 +774,9 @@ public final class HSSFChart { r.setCustomNumberFormat( false ); r.setIndexNumberFmtRecord( (short) 0 ); LinkedDataFormulaField formula = new LinkedDataFormulaField(); - Stack tokens = new Stack(); Area3DPtg p = new Area3DPtg(0, 31, 0, 0, false, false, false, false, 0); - tokens.add( p ); - formula.setFormulaTokens( tokens ); + formula.setFormulaTokens(new Ptg[] { p, }); r.setFormulaOfLink( formula ); return r; } diff --git a/src/testcases/org/apache/poi/hssf/eventmodel/TestEventRecordFactory.java b/src/testcases/org/apache/poi/hssf/eventmodel/TestEventRecordFactory.java index 88f620ca44..8825fed700 100644 --- a/src/testcases/org/apache/poi/hssf/eventmodel/TestEventRecordFactory.java +++ b/src/testcases/org/apache/poi/hssf/eventmodel/TestEventRecordFactory.java @@ -87,10 +87,8 @@ public final class TestEventRecordFactory extends TestCase { bof.setHistoryBitMask(BOFRecord.HISTORY_MASK); byte[] bytes = bof.serialize(); - byte[] nbytes = new byte[bytes.length - 4]; - System.arraycopy(bytes,4,nbytes,0,nbytes.length); - Record[] records = RecordFactory.createRecord(new TestcaseRecordInputStream(bof.getSid(),(short)nbytes.length,nbytes)); + Record[] records = RecordFactory.createRecord(TestcaseRecordInputStream.create(bytes)); assertTrue("record.length must be 1, was ="+records.length,records.length == 1); assertTrue("record is the same", compareRec(bof,records[0])); diff --git a/src/testcases/org/apache/poi/hssf/record/AllRecordTests.java b/src/testcases/org/apache/poi/hssf/record/AllRecordTests.java index fb3270ae75..5fb6f4aa03 100755 --- a/src/testcases/org/apache/poi/hssf/record/AllRecordTests.java +++ b/src/testcases/org/apache/poi/hssf/record/AllRecordTests.java @@ -84,6 +84,7 @@ public final class AllRecordTests { result.addTestSuite(TestPaneRecord.class); result.addTestSuite(TestPlotAreaRecord.class); result.addTestSuite(TestPlotGrowthRecord.class); + result.addTestSuite(TestRecordInputStream.class); result.addTestSuite(TestRecordFactory.class); result.addTestSuite(TestSCLRecord.class); result.addTestSuite(TestSSTDeserializer.class); diff --git a/src/testcases/org/apache/poi/hssf/record/TestAreaFormatRecord.java b/src/testcases/org/apache/poi/hssf/record/TestAreaFormatRecord.java index de834be95e..fb852ba88c 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestAreaFormatRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestAreaFormatRecord.java @@ -41,7 +41,7 @@ public final class TestAreaFormatRecord extends TestCase { public void testLoad() { - AreaFormatRecord record = new AreaFormatRecord(new TestcaseRecordInputStream((short)0x100a, (short)data.length, data)); + AreaFormatRecord record = new AreaFormatRecord(TestcaseRecordInputStream.create(0x100a, data)); assertEquals( 0xFFFFFF, record.getForegroundColor()); assertEquals( 0x000000, record.getBackgroundColor()); assertEquals( 1, record.getPattern()); diff --git a/src/testcases/org/apache/poi/hssf/record/TestAreaRecord.java b/src/testcases/org/apache/poi/hssf/record/TestAreaRecord.java index 2131e73192..f514feccba 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestAreaRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestAreaRecord.java @@ -35,7 +35,7 @@ public final class TestAreaRecord extends TestCase { public void testLoad() { - AreaRecord record = new AreaRecord(new TestcaseRecordInputStream((short)0x101A, (short)data.length, data)); + AreaRecord record = new AreaRecord(TestcaseRecordInputStream.create(0x101A, data)); assertEquals( 2, record.getFormatFlags()); assertEquals( false, record.isStacked() ); assertEquals( true, record.isDisplayAsPercentage() ); diff --git a/src/testcases/org/apache/poi/hssf/record/TestAxisLineFormatRecord.java b/src/testcases/org/apache/poi/hssf/record/TestAxisLineFormatRecord.java index 2146a31cfb..4e9e29a6f7 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestAxisLineFormatRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestAxisLineFormatRecord.java @@ -34,7 +34,7 @@ public final class TestAxisLineFormatRecord extends TestCase { }; public void testLoad() { - AxisLineFormatRecord record = new AxisLineFormatRecord(new TestcaseRecordInputStream((short)0x1021, (short)data.length, data)); + AxisLineFormatRecord record = new AxisLineFormatRecord(TestcaseRecordInputStream.create(0x1021, data)); assertEquals( AxisLineFormatRecord.AXIS_TYPE_MAJOR_GRID_LINE, record.getAxisType()); assertEquals( 6, record.getRecordSize() ); diff --git a/src/testcases/org/apache/poi/hssf/record/TestAxisOptionsRecord.java b/src/testcases/org/apache/poi/hssf/record/TestAxisOptionsRecord.java index 4d88e18a69..de51b48b0d 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestAxisOptionsRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestAxisOptionsRecord.java @@ -37,7 +37,7 @@ public final class TestAxisOptionsRecord extends TestCase { }; public void testLoad() { - AxisOptionsRecord record = new AxisOptionsRecord(new TestcaseRecordInputStream((short)0x1062, (short)data.length, data)); + AxisOptionsRecord record = new AxisOptionsRecord(TestcaseRecordInputStream.create(0x1062, data)); assertEquals( 0, record.getMinimumCategory()); assertEquals( 0, record.getMaximumCategory()); assertEquals( 1, record.getMajorUnitValue()); diff --git a/src/testcases/org/apache/poi/hssf/record/TestAxisParentRecord.java b/src/testcases/org/apache/poi/hssf/record/TestAxisParentRecord.java index a9787a2e8b..406b68fd60 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestAxisParentRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestAxisParentRecord.java @@ -37,7 +37,7 @@ public final class TestAxisParentRecord extends TestCase { }; public void testLoad() { - AxisParentRecord record = new AxisParentRecord(new TestcaseRecordInputStream((short)0x1041, (short)data.length, data)); + AxisParentRecord record = new AxisParentRecord(TestcaseRecordInputStream.create(0x1041, data)); assertEquals( AxisParentRecord.AXIS_TYPE_MAIN, record.getAxisType()); assertEquals( 0x021d, record.getX()); assertEquals( 0xdd, record.getY()); diff --git a/src/testcases/org/apache/poi/hssf/record/TestAxisRecord.java b/src/testcases/org/apache/poi/hssf/record/TestAxisRecord.java index 719e930d25..21e41773ce 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestAxisRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestAxisRecord.java @@ -39,7 +39,7 @@ public final class TestAxisRecord extends TestCase { public void testLoad() { - AxisRecord record = new AxisRecord(new TestcaseRecordInputStream((short)0x101d, (short)data.length, data)); + AxisRecord record = new AxisRecord(TestcaseRecordInputStream.create(0x101d, data)); assertEquals( AxisRecord.AXIS_TYPE_CATEGORY_OR_X_AXIS, record.getAxisType()); assertEquals( 0, record.getReserved1()); assertEquals( 0, record.getReserved2()); diff --git a/src/testcases/org/apache/poi/hssf/record/TestAxisUsedRecord.java b/src/testcases/org/apache/poi/hssf/record/TestAxisUsedRecord.java index 98812ddd6f..5f02d2874c 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestAxisUsedRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestAxisUsedRecord.java @@ -34,7 +34,7 @@ public final class TestAxisUsedRecord extends TestCase { }; public void testLoad() { - AxisUsedRecord record = new AxisUsedRecord(new TestcaseRecordInputStream((short)0x1046, (short)data.length, data)); + AxisUsedRecord record = new AxisUsedRecord(TestcaseRecordInputStream.create(0x1046, data)); assertEquals( 1, record.getNumAxis()); assertEquals( 6, record.getRecordSize() ); diff --git a/src/testcases/org/apache/poi/hssf/record/TestBarRecord.java b/src/testcases/org/apache/poi/hssf/record/TestBarRecord.java index 1da17aae92..80c729c212 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestBarRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestBarRecord.java @@ -37,7 +37,7 @@ public final class TestBarRecord extends TestCase { public void testLoad() { - BarRecord record = new BarRecord(new TestcaseRecordInputStream((short)0x1017, (short)data.length, data)); + BarRecord record = new BarRecord(TestcaseRecordInputStream.create(0x1017, data)); assertEquals( 0, record.getBarSpace()); assertEquals( 0x96, record.getCategorySpace()); assertEquals( 0, record.getFormatFlags()); diff --git a/src/testcases/org/apache/poi/hssf/record/TestBoundSheetRecord.java b/src/testcases/org/apache/poi/hssf/record/TestBoundSheetRecord.java index f973da37db..766e396473 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestBoundSheetRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestBoundSheetRecord.java @@ -69,7 +69,7 @@ public final class TestBoundSheetRecord extends TestCase { // }; - RecordInputStream in = new TestcaseRecordInputStream(BoundSheetRecord.sid, data); + RecordInputStream in = TestcaseRecordInputStream.create(BoundSheetRecord.sid, data); BoundSheetRecord bsr = new BoundSheetRecord(in); // sheet name is unicode Russian for 'minor page' assertEquals("\u0421\u0442\u0440\u0430\u043D\u0438\u0447\u043A\u0430", bsr.getSheetname()); diff --git a/src/testcases/org/apache/poi/hssf/record/TestCFHeaderRecord.java b/src/testcases/org/apache/poi/hssf/record/TestCFHeaderRecord.java index ec291ffd49..239f2092f7 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestCFHeaderRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestCFHeaderRecord.java @@ -90,7 +90,7 @@ public final class TestCFHeaderRecord extends TestCase (byte)0x03, (byte)0x00, }; - CFHeaderRecord record = new CFHeaderRecord(new TestcaseRecordInputStream(CFHeaderRecord.sid, (short)recordData.length, recordData)); + CFHeaderRecord record = new CFHeaderRecord(TestcaseRecordInputStream.create(CFHeaderRecord.sid, recordData)); assertEquals("#CFRULES", 3, record.getNumberOfConditionalFormats()); assertTrue(record.getNeedRecalculation()); @@ -143,7 +143,7 @@ public final class TestCFHeaderRecord extends TestCase CFHeaderRecord record; try { - record = new CFHeaderRecord(new TestcaseRecordInputStream(CFHeaderRecord.sid, (short)recordData.length, recordData)); + record = new CFHeaderRecord(TestcaseRecordInputStream.create(CFHeaderRecord.sid, recordData)); } catch (IllegalArgumentException e) { if(e.getMessage().equals("invalid cell range (-25536, 2, -15536, 2)")) { throw new AssertionFailedError("Identified bug 44739b"); diff --git a/src/testcases/org/apache/poi/hssf/record/TestCFRuleRecord.java b/src/testcases/org/apache/poi/hssf/record/TestCFRuleRecord.java index 1eb052bec7..80de959809 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestCFRuleRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestCFRuleRecord.java @@ -54,7 +54,7 @@ public final class TestCFRuleRecord extends TestCase System.arraycopy(serializedRecord, 4, recordData, 0, recordData.length); // Deserialize - record = new CFRuleRecord(new TestcaseRecordInputStream(CFRuleRecord.sid, (short)recordData.length, recordData)); + record = new CFRuleRecord(TestcaseRecordInputStream.create(CFRuleRecord.sid, recordData)); // Serialize again byte[] output = record.serialize(); @@ -317,7 +317,7 @@ public final class TestCFRuleRecord extends TestCase */ public void testReserializeRefNTokens() { - RecordInputStream is = new TestcaseRecordInputStream(CFRuleRecord.sid, DATA_REFN); + RecordInputStream is = TestcaseRecordInputStream.create(CFRuleRecord.sid, DATA_REFN); CFRuleRecord rr = new CFRuleRecord(is); Ptg[] ptgs = rr.getParsedExpression1(); assertEquals(3, ptgs.length); diff --git a/src/testcases/org/apache/poi/hssf/record/TestCategorySeriesAxisRecord.java b/src/testcases/org/apache/poi/hssf/record/TestCategorySeriesAxisRecord.java index 415b302e87..080918aa05 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestCategorySeriesAxisRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestCategorySeriesAxisRecord.java @@ -38,7 +38,7 @@ public final class TestCategorySeriesAxisRecord extends TestCase { public void testLoad() { - CategorySeriesAxisRecord record = new CategorySeriesAxisRecord(new TestcaseRecordInputStream((short)0x1020, (short)data.length, data)); + CategorySeriesAxisRecord record = new CategorySeriesAxisRecord(TestcaseRecordInputStream.create(0x1020, data)); assertEquals( 1, record.getCrossingPoint()); assertEquals( 1, record.getLabelFrequency()); assertEquals( 1, record.getTickMarkFrequency()); diff --git a/src/testcases/org/apache/poi/hssf/record/TestChartRecord.java b/src/testcases/org/apache/poi/hssf/record/TestChartRecord.java index 996fb1102b..994b15b32c 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestChartRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestChartRecord.java @@ -38,7 +38,7 @@ public final class TestChartRecord extends TestCase { public void testLoad() { - ChartRecord record = new ChartRecord(new TestcaseRecordInputStream((short)0x1002, (short)data.length, data)); + ChartRecord record = new ChartRecord(TestcaseRecordInputStream.create(0x1002, data)); assertEquals( 0, record.getX()); assertEquals( 0, record.getY()); assertEquals( 30474216, record.getWidth()); diff --git a/src/testcases/org/apache/poi/hssf/record/TestCommonObjectDataSubRecord.java b/src/testcases/org/apache/poi/hssf/record/TestCommonObjectDataSubRecord.java index e68b5026d8..ad629c3f17 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestCommonObjectDataSubRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestCommonObjectDataSubRecord.java @@ -38,7 +38,7 @@ public final class TestCommonObjectDataSubRecord extends TestCase { }; public void testLoad() { - CommonObjectDataSubRecord record = new CommonObjectDataSubRecord(new TestcaseRecordInputStream((short)0x15, (short)data.length, data)); + CommonObjectDataSubRecord record = new CommonObjectDataSubRecord(TestcaseRecordInputStream.create(0x15, data)); assertEquals( CommonObjectDataSubRecord.OBJECT_TYPE_LIST_BOX, record.getObjectType()); assertEquals( (short)1, record.getObjectId()); diff --git a/src/testcases/org/apache/poi/hssf/record/TestDatRecord.java b/src/testcases/org/apache/poi/hssf/record/TestDatRecord.java index 8efbe70ecb..408d80e568 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestDatRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestDatRecord.java @@ -35,7 +35,7 @@ public final class TestDatRecord extends TestCase { public void testLoad() { - DatRecord record = new DatRecord(new TestcaseRecordInputStream((short)0x1063, (short)data.length, data)); + DatRecord record = new DatRecord(TestcaseRecordInputStream.create(0x1063, data)); assertEquals( 0xD, record.getOptions()); assertEquals( true, record.isHorizontalBorder() ); assertEquals( false, record.isVerticalBorder() ); diff --git a/src/testcases/org/apache/poi/hssf/record/TestDataFormatRecord.java b/src/testcases/org/apache/poi/hssf/record/TestDataFormatRecord.java index 8de2f24dac..953f13ec08 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestDataFormatRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestDataFormatRecord.java @@ -38,7 +38,7 @@ public final class TestDataFormatRecord extends TestCase { public void testLoad() { - DataFormatRecord record = new DataFormatRecord(new TestcaseRecordInputStream((short)0x1006, (short)data.length, data)); + DataFormatRecord record = new DataFormatRecord(TestcaseRecordInputStream.create(0x1006, data)); assertEquals( (short)0xFFFF, record.getPointNumber()); assertEquals( 0, record.getSeriesIndex()); assertEquals( 0, record.getSeriesNumber()); diff --git a/src/testcases/org/apache/poi/hssf/record/TestDefaultDataLabelTextPropertiesRecord.java b/src/testcases/org/apache/poi/hssf/record/TestDefaultDataLabelTextPropertiesRecord.java index f96dca90bf..8557359e8a 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestDefaultDataLabelTextPropertiesRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestDefaultDataLabelTextPropertiesRecord.java @@ -35,7 +35,7 @@ public final class TestDefaultDataLabelTextPropertiesRecord extends TestCase { public void testLoad() { - DefaultDataLabelTextPropertiesRecord record = new DefaultDataLabelTextPropertiesRecord(new TestcaseRecordInputStream((short)0x1024, (short)data.length, data)); + DefaultDataLabelTextPropertiesRecord record = new DefaultDataLabelTextPropertiesRecord(TestcaseRecordInputStream.create(0x1024, data)); assertEquals( 2, record.getCategoryDataType()); assertEquals( 6, record.getRecordSize() ); diff --git a/src/testcases/org/apache/poi/hssf/record/TestEmbeddedObjectRefSubRecord.java b/src/testcases/org/apache/poi/hssf/record/TestEmbeddedObjectRefSubRecord.java index e09f9e34ab..bf8da6fece 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestEmbeddedObjectRefSubRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestEmbeddedObjectRefSubRecord.java @@ -127,7 +127,7 @@ public final class TestEmbeddedObjectRefSubRecord extends TestCase { } private static void confirmRead(byte[] data, int i) { - RecordInputStream in = new TestcaseRecordInputStream(EmbeddedObjectRefSubRecord.sid, (short)data.length, data); + RecordInputStream in = TestcaseRecordInputStream.create(EmbeddedObjectRefSubRecord.sid, data); EmbeddedObjectRefSubRecord rec = new EmbeddedObjectRefSubRecord(in); byte[] ser2 = rec.serialize(); diff --git a/src/testcases/org/apache/poi/hssf/record/TestEndSubRecord.java b/src/testcases/org/apache/poi/hssf/record/TestEndSubRecord.java index d809392420..d16c227149 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestEndSubRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestEndSubRecord.java @@ -33,7 +33,7 @@ public final class TestEndSubRecord extends TestCase { }; public void testLoad() { - EndSubRecord record = new EndSubRecord(new TestcaseRecordInputStream((short)0x00, (short)data.length, data)); + EndSubRecord record = new EndSubRecord(TestcaseRecordInputStream.create(0x00, data)); assertEquals( 4, record.getRecordSize() ); } diff --git a/src/testcases/org/apache/poi/hssf/record/TestExtendedFormatRecord.java b/src/testcases/org/apache/poi/hssf/record/TestExtendedFormatRecord.java index 3faa69ed6a..00d5c8c111 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestExtendedFormatRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestExtendedFormatRecord.java @@ -37,7 +37,7 @@ public final class TestExtendedFormatRecord extends TestCase { }; public void testLoad() { - ExtendedFormatRecord record = new ExtendedFormatRecord(new TestcaseRecordInputStream((short)0xe0, (short)data.length, data)); + ExtendedFormatRecord record = new ExtendedFormatRecord(TestcaseRecordInputStream.create(0xe0, data)); assertEquals(0, record.getFontIndex()); assertEquals(0, record.getFormatIndex()); assertEquals(0xF5-256, record.getCellOptions()); @@ -117,7 +117,7 @@ public final class TestExtendedFormatRecord extends TestCase { } public void testCloneOnto() throws Exception { - ExtendedFormatRecord base = new ExtendedFormatRecord(new TestcaseRecordInputStream((short)0xe0, (short)data.length, data)); + ExtendedFormatRecord base = new ExtendedFormatRecord(TestcaseRecordInputStream.create(0xe0, data)); ExtendedFormatRecord other = new ExtendedFormatRecord(); other.cloneStyleFrom(base); diff --git a/src/testcases/org/apache/poi/hssf/record/TestExternalNameRecord.java b/src/testcases/org/apache/poi/hssf/record/TestExternalNameRecord.java index e55876e6f6..54c1f35b3b 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestExternalNameRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestExternalNameRecord.java @@ -43,7 +43,7 @@ public final class TestExternalNameRecord extends TestCase { }; private static ExternalNameRecord createSimpleENR(byte[] data) { - return new ExternalNameRecord(new TestcaseRecordInputStream((short)0x0023, data)); + return new ExternalNameRecord(TestcaseRecordInputStream.create(0x0023, data)); } public void testBasicDeserializeReserialize() { diff --git a/src/testcases/org/apache/poi/hssf/record/TestFontBasisRecord.java b/src/testcases/org/apache/poi/hssf/record/TestFontBasisRecord.java index acd5a361ad..65c19f0916 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestFontBasisRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestFontBasisRecord.java @@ -39,7 +39,7 @@ public final class TestFontBasisRecord extends TestCase { public void testLoad() { - FontBasisRecord record = new FontBasisRecord(new TestcaseRecordInputStream((short)0x1060, (short)data.length, data)); + FontBasisRecord record = new FontBasisRecord(TestcaseRecordInputStream.create(0x1060, data)); assertEquals( 0x1a28, record.getXBasis()); assertEquals( 0x0f9c, record.getYBasis()); assertEquals( 0xc8, record.getHeightBasis()); diff --git a/src/testcases/org/apache/poi/hssf/record/TestFontIndexRecord.java b/src/testcases/org/apache/poi/hssf/record/TestFontIndexRecord.java index 49cfe4d650..c962e0daee 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestFontIndexRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestFontIndexRecord.java @@ -35,7 +35,7 @@ public final class TestFontIndexRecord extends TestCase { public void testLoad() { - FontIndexRecord record = new FontIndexRecord(new TestcaseRecordInputStream((short)0x1026, (short)data.length, data)); + FontIndexRecord record = new FontIndexRecord(TestcaseRecordInputStream.create(0x1026, data)); assertEquals( 5, record.getFontIndex()); assertEquals( 6, record.getRecordSize() ); diff --git a/src/testcases/org/apache/poi/hssf/record/TestFontRecord.java b/src/testcases/org/apache/poi/hssf/record/TestFontRecord.java index 19449c2f56..5a8855b66e 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestFontRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestFontRecord.java @@ -44,7 +44,7 @@ public final class TestFontRecord extends TestCase { public void testLoad() { - FontRecord record = new FontRecord(new TestcaseRecordInputStream((short)0x31, (short)data.length, data)); + FontRecord record = new FontRecord(TestcaseRecordInputStream.create(0x31, data)); assertEquals( 0xc8, record.getFontHeight()); assertEquals( 0x00, record.getAttributes()); assertFalse( record.isItalic()); @@ -100,7 +100,7 @@ public final class TestFontRecord extends TestCase { } public void testCloneOnto() throws Exception { - FontRecord base = new FontRecord(new TestcaseRecordInputStream((short)0x31, (short)data.length, data)); + FontRecord base = new FontRecord(TestcaseRecordInputStream.create(0x31, data)); FontRecord other = new FontRecord(); other.cloneStyleFrom(base); @@ -112,8 +112,8 @@ public final class TestFontRecord extends TestCase { } public void testSameProperties() throws Exception { - FontRecord f1 = new FontRecord(new TestcaseRecordInputStream((short)0x31, (short)data.length, data)); - FontRecord f2 = new FontRecord(new TestcaseRecordInputStream((short)0x31, (short)data.length, data)); + FontRecord f1 = new FontRecord(TestcaseRecordInputStream.create(0x31, data)); + FontRecord f2 = new FontRecord(TestcaseRecordInputStream.create(0x31, data)); assertTrue(f1.sameProperties(f2)); diff --git a/src/testcases/org/apache/poi/hssf/record/TestFormulaRecord.java b/src/testcases/org/apache/poi/hssf/record/TestFormulaRecord.java index 4696539f23..703664443c 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestFormulaRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestFormulaRecord.java @@ -82,7 +82,7 @@ public final class TestFormulaRecord extends TestCase { }; - FormulaRecord record = new FormulaRecord(new TestcaseRecordInputStream(FormulaRecord.sid, (short)29, formulaByte)); + FormulaRecord record = new FormulaRecord(TestcaseRecordInputStream.create(FormulaRecord.sid, formulaByte)); assertEquals("Row", 0, record.getRow()); assertEquals("Column", 0, record.getColumn()); assertEquals(HSSFCell.CELL_TYPE_ERROR, record.getCachedResultType()); @@ -108,7 +108,7 @@ public final class TestFormulaRecord extends TestCase { formulaByte[19]=(byte)0xFD; formulaByte[20]=(byte)0x05; formulaByte[22]=(byte)0x01; - FormulaRecord record = new FormulaRecord(new TestcaseRecordInputStream(FormulaRecord.sid, (short)27, formulaByte)); + FormulaRecord record = new FormulaRecord(TestcaseRecordInputStream.create(FormulaRecord.sid, formulaByte)); assertEquals("Row", 0, record.getRow()); assertEquals("Column", 0, record.getColumn()); byte[] output = record.serialize(); diff --git a/src/testcases/org/apache/poi/hssf/record/TestFrameRecord.java b/src/testcases/org/apache/poi/hssf/record/TestFrameRecord.java index f35a04b488..23f1593efb 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestFrameRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestFrameRecord.java @@ -36,7 +36,7 @@ public final class TestFrameRecord extends TestCase { public void testLoad() { - FrameRecord record = new FrameRecord(new TestcaseRecordInputStream((short)0x1032, (short)data.length, data)); + FrameRecord record = new FrameRecord(TestcaseRecordInputStream.create(0x1032, data)); assertEquals( FrameRecord.BORDER_TYPE_REGULAR, record.getBorderType()); assertEquals( 2, record.getOptions()); assertEquals( false, record.isAutoSize() ); diff --git a/src/testcases/org/apache/poi/hssf/record/TestHyperlinkRecord.java b/src/testcases/org/apache/poi/hssf/record/TestHyperlinkRecord.java index 3d2ca406ce..1919a4b038 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestHyperlinkRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestHyperlinkRecord.java @@ -17,7 +17,6 @@ package org.apache.poi.hssf.record; import java.io.ByteArrayInputStream; -import java.net.URL; import java.util.Arrays; import junit.framework.TestCase; @@ -28,7 +27,7 @@ import junit.framework.TestCase; * @author Nick Burch * @author Yegor Kozlov */ -public class TestHyperlinkRecord extends TestCase { +public final class TestHyperlinkRecord extends TestCase { //link to http://www.lakings.com/ byte[] data1 = { 0x02, 0x00, //First row of the hyperlink @@ -165,7 +164,7 @@ public class TestHyperlinkRecord extends TestCase { 0x00, 0x41, 0x00, 0x31, 0x00, 0x00, 0x00}; public void testReadURLLink(){ - RecordInputStream is = new TestcaseRecordInputStream((short)HyperlinkRecord.sid, (short)data1.length, data1); + RecordInputStream is = TestcaseRecordInputStream.create(HyperlinkRecord.sid, data1); HyperlinkRecord link = new HyperlinkRecord(is); assertEquals(2, link.getFirstRow()); assertEquals(2, link.getLastRow()); @@ -184,7 +183,7 @@ public class TestHyperlinkRecord extends TestCase { } public void testReadFileLink(){ - RecordInputStream is = new TestcaseRecordInputStream((short)HyperlinkRecord.sid, (short)data2.length, data2); + RecordInputStream is = TestcaseRecordInputStream.create(HyperlinkRecord.sid, data2); HyperlinkRecord link = new HyperlinkRecord(is); assertEquals(0, link.getFirstRow()); assertEquals(0, link.getLastRow()); @@ -202,7 +201,7 @@ public class TestHyperlinkRecord extends TestCase { } public void testReadEmailLink(){ - RecordInputStream is = new TestcaseRecordInputStream((short)HyperlinkRecord.sid, (short)data3.length, data3); + RecordInputStream is = TestcaseRecordInputStream.create(HyperlinkRecord.sid, data3); HyperlinkRecord link = new HyperlinkRecord(is); assertEquals(1, link.getFirstRow()); assertEquals(1, link.getLastRow()); @@ -220,7 +219,7 @@ public class TestHyperlinkRecord extends TestCase { } public void testReadDocumentLink(){ - RecordInputStream is = new TestcaseRecordInputStream((short)HyperlinkRecord.sid, (short)data4.length, data4); + RecordInputStream is = TestcaseRecordInputStream.create(HyperlinkRecord.sid, data4); HyperlinkRecord link = new HyperlinkRecord(is); assertEquals(3, link.getFirstRow()); assertEquals(3, link.getLastRow()); @@ -237,7 +236,7 @@ public class TestHyperlinkRecord extends TestCase { } private void serialize(byte[] data){ - RecordInputStream is = new TestcaseRecordInputStream((short)HyperlinkRecord.sid, (short)data.length, data); + RecordInputStream is = TestcaseRecordInputStream.create(HyperlinkRecord.sid, data); HyperlinkRecord link = new HyperlinkRecord(is); byte[] bytes1 = link.serialize(); is = new RecordInputStream(new ByteArrayInputStream(bytes1)); @@ -318,7 +317,7 @@ public class TestHyperlinkRecord extends TestCase { public void testClone() throws Exception { byte[][] data = {data1, data2, data3, data4}; for (int i = 0; i < data.length; i++) { - RecordInputStream is = new TestcaseRecordInputStream((short)HyperlinkRecord.sid, (short)data[i].length, data[i]); + RecordInputStream is = TestcaseRecordInputStream.create(HyperlinkRecord.sid, data[i]); HyperlinkRecord link = new HyperlinkRecord(is); HyperlinkRecord clone = (HyperlinkRecord)link.clone(); assertTrue(Arrays.equals(link.serialize(), clone.serialize())); diff --git a/src/testcases/org/apache/poi/hssf/record/TestLegendRecord.java b/src/testcases/org/apache/poi/hssf/record/TestLegendRecord.java index aaee94fe82..6bae58f2a4 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestLegendRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestLegendRecord.java @@ -17,80 +17,73 @@ package org.apache.poi.hssf.record; - import junit.framework.TestCase; /** - * Tests the serialization and deserialization of the LegendRecord - * class works correctly. Test data taken directly from a real - * Excel file. - * - + * Tests the serialization and deserialization of the LegendRecord class works + * correctly. Test data taken directly from a real Excel file. + * + * * @author Andrew C. Oliver (acoliver at apache.org) */ -public class TestLegendRecord extends TestCase { - byte[] data = new byte[] { - (byte)0x76,(byte)0x0E,(byte)0x00,(byte)0x00,(byte)0x86,(byte)0x07,(byte)0x00,(byte)0x00,(byte)0x19,(byte)0x01,(byte)0x00,(byte)0x00,(byte)0x8B,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x03,(byte)0x01,(byte)0x1F,(byte)0x00 - }; - - public void testLoad() { - LegendRecord record = new LegendRecord(new TestcaseRecordInputStream((short)0x1015, (short)data.length, data)); - - - assertEquals( (int)0xe76, record.getXAxisUpperLeft()); - - assertEquals( (int)0x786, record.getYAxisUpperLeft()); - - assertEquals( (int)0x119, record.getXSize()); +public final class TestLegendRecord extends TestCase { + byte[] data = new byte[] { (byte) 0x76, (byte) 0x0E, (byte) 0x00, (byte) 0x00, (byte) 0x86, + (byte) 0x07, (byte) 0x00, (byte) 0x00, (byte) 0x19, (byte) 0x01, (byte) 0x00, + (byte) 0x00, (byte) 0x8B, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x03, + (byte) 0x01, (byte) 0x1F, (byte) 0x00 }; - assertEquals( (int)0x8b, record.getYSize()); + public void testLoad() { + LegendRecord record = new LegendRecord(TestcaseRecordInputStream.create(0x1015, data)); - assertEquals( (byte)0x3, record.getType()); + assertEquals(0xe76, record.getXAxisUpperLeft()); - assertEquals( (byte)0x1, record.getSpacing()); + assertEquals(0x786, record.getYAxisUpperLeft()); - assertEquals( (short)0x1f, record.getOptions()); - assertEquals( true, record.isAutoPosition() ); - assertEquals( true, record.isAutoSeries() ); - assertEquals( true, record.isAutoXPositioning() ); - assertEquals( true, record.isAutoYPositioning() ); - assertEquals( true, record.isVertical() ); - assertEquals( false, record.isDataTable() ); + assertEquals(0x119, record.getXSize()); + assertEquals(0x8b, record.getYSize()); - assertEquals( 24, record.getRecordSize() ); - } + assertEquals((byte) 0x3, record.getType()); - public void testStore() - { - LegendRecord record = new LegendRecord(); + assertEquals((byte) 0x1, record.getSpacing()); + assertEquals((short) 0x1f, record.getOptions()); + assertEquals(true, record.isAutoPosition()); + assertEquals(true, record.isAutoSeries()); + assertEquals(true, record.isAutoXPositioning()); + assertEquals(true, record.isAutoYPositioning()); + assertEquals(true, record.isVertical()); + assertEquals(false, record.isDataTable()); + assertEquals(24, record.getRecordSize()); + } - record.setXAxisUpperLeft( (int)0xe76 ); + public void testStore() { + LegendRecord record = new LegendRecord(); - record.setYAxisUpperLeft( (int)0x786 ); + record.setXAxisUpperLeft(0xe76); - record.setXSize( (int)0x119 ); + record.setYAxisUpperLeft(0x786); - record.setYSize( (int)0x8b ); + record.setXSize(0x119); - record.setType( (byte)0x3 ); + record.setYSize(0x8b); - record.setSpacing( (byte)0x1 ); + record.setType((byte) 0x3); - record.setOptions( (short)0x1f ); - record.setAutoPosition( true ); - record.setAutoSeries( true ); - record.setAutoXPositioning( true ); - record.setAutoYPositioning( true ); - record.setVertical( true ); - record.setDataTable( false ); + record.setSpacing((byte) 0x1); + record.setOptions((short) 0x1f); + record.setAutoPosition(true); + record.setAutoSeries(true); + record.setAutoXPositioning(true); + record.setAutoYPositioning(true); + record.setVertical(true); + record.setDataTable(false); - byte [] recordBytes = record.serialize(); - assertEquals(recordBytes.length - 4, data.length); - for (int i = 0; i < data.length; i++) - assertEquals("At offset " + i, data[i], recordBytes[i+4]); - } + byte[] recordBytes = record.serialize(); + assertEquals(recordBytes.length - 4, data.length); + for (int i = 0; i < data.length; i++) + assertEquals("At offset " + i, data[i], recordBytes[i + 4]); + } } diff --git a/src/testcases/org/apache/poi/hssf/record/TestLineFormatRecord.java b/src/testcases/org/apache/poi/hssf/record/TestLineFormatRecord.java index f4e833dd7c..f3b4c3d326 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestLineFormatRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestLineFormatRecord.java @@ -28,7 +28,7 @@ import junit.framework.TestCase; * @author Glen Stampoultzis (glens at apache.org) */ -public class TestLineFormatRecord extends TestCase { +public final class TestLineFormatRecord extends TestCase { byte[] data = new byte[] { (byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00, // colour (byte)0x00,(byte)0x00, // pattern @@ -38,7 +38,7 @@ public class TestLineFormatRecord extends TestCase { }; public void testLoad() { - LineFormatRecord record = new LineFormatRecord(new TestcaseRecordInputStream((short)0x1007, (short)data.length, data)); + LineFormatRecord record = new LineFormatRecord(TestcaseRecordInputStream.create(0x1007, data)); assertEquals( 0, record.getLineColor()); assertEquals( 0, record.getLinePattern()); assertEquals( 0, record.getWeight()); diff --git a/src/testcases/org/apache/poi/hssf/record/TestLinkedDataRecord.java b/src/testcases/org/apache/poi/hssf/record/TestLinkedDataRecord.java index 641f1e8c54..adca938147 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestLinkedDataRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestLinkedDataRecord.java @@ -19,9 +19,9 @@ package org.apache.poi.hssf.record; import junit.framework.TestCase; -import org.apache.poi.hssf.record.formula.Area3DPtg; -import java.util.Stack; +import org.apache.poi.hssf.record.formula.Area3DPtg; +import org.apache.poi.hssf.record.formula.Ptg; /** * Tests the serialization and deserialization of the LinkedDataRecord @@ -157,7 +157,7 @@ recordid = 0x1051, size =8 public void testLoad() { - LinkedDataRecord record = new LinkedDataRecord(new TestcaseRecordInputStream((short)0x1051, (short)data.length, data)); + LinkedDataRecord record = new LinkedDataRecord(TestcaseRecordInputStream.create(0x1051, data)); assertEquals( LinkedDataRecord.LINK_TYPE_VALUES, record.getLinkType()); assertEquals( LinkedDataRecord.REFERENCE_TYPE_WORKSHEET, record.getReferenceType()); assertEquals( 0, record.getOptions()); @@ -167,7 +167,7 @@ recordid = 0x1051, size =8 Area3DPtg ptgExpected = new Area3DPtg(0, 7936, 0, 0, false, false, false, false, 0); - Object ptgActual = record.getFormulaOfLink().getFormulaTokens().get(0); + Object ptgActual = record.getFormulaOfLink().getFormulaTokens()[0]; assertEquals(ptgExpected.toString(), ptgActual.toString()); assertEquals( data.length + 4, record.getRecordSize() ); @@ -182,10 +182,8 @@ recordid = 0x1051, size =8 record.setIndexNumberFmtRecord( (short)0 ); Area3DPtg ptg = new Area3DPtg(0, 7936, 0, 0, false, false, false, false, 0); - Stack s = new Stack(); - s.push(ptg); LinkedDataFormulaField formulaOfLink = new LinkedDataFormulaField(); - formulaOfLink.setFormulaTokens(s); + formulaOfLink.setFormulaTokens(new Ptg[] { ptg, }); record.setFormulaOfLink(formulaOfLink ); byte [] recordBytes = record.serialize(); diff --git a/src/testcases/org/apache/poi/hssf/record/TestNameRecord.java b/src/testcases/org/apache/poi/hssf/record/TestNameRecord.java index 115e06f65e..cbb4b048a0 100755 --- a/src/testcases/org/apache/poi/hssf/record/TestNameRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestNameRecord.java @@ -1,4 +1,3 @@ - /* ==================================================================== Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with @@ -25,9 +24,7 @@ import junit.framework.TestCase; * * @author Danny Mui (dmui at apache dot org) */ -public class TestNameRecord - extends TestCase -{ +public final class TestNameRecord extends TestCase { /** * Makes sure that additional name information is parsed properly such as menu/description @@ -55,13 +52,11 @@ public class TestNameRecord }; - NameRecord name = new NameRecord(new TestcaseRecordInputStream(NameRecord.sid, (short) examples.length, examples)); + NameRecord name = new NameRecord(TestcaseRecordInputStream.create(NameRecord.sid, examples)); String description = name.getDescriptionText(); assertNotNull( description ); assertTrue( "text contains ALLWOR", description.indexOf( "ALLWOR" ) > 0 ); - } - } diff --git a/src/testcases/org/apache/poi/hssf/record/TestNoteRecord.java b/src/testcases/org/apache/poi/hssf/record/TestNoteRecord.java index 063f34e0c7..e31601be57 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestNoteRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestNoteRecord.java @@ -29,9 +29,7 @@ import java.util.Arrays; * * @author Yegor Kozlov */ -public class TestNoteRecord - extends TestCase -{ +public final class TestNoteRecord extends TestCase { private byte[] data = new byte[] { 0x06, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02, 0x04, 0x1A, 0x00, 0x00, 0x41, 0x70, 0x61, 0x63, 0x68, 0x65, 0x20, 0x53, 0x6F, @@ -41,7 +39,7 @@ public class TestNoteRecord public void testRead() { - NoteRecord record = new NoteRecord(new TestcaseRecordInputStream(NoteRecord.sid, (short)data.length, data)); + NoteRecord record = new NoteRecord(TestcaseRecordInputStream.create(NoteRecord.sid, data)); assertEquals(NoteRecord.sid, record.getSid()); assertEquals(6, record.getRow()); diff --git a/src/testcases/org/apache/poi/hssf/record/TestNoteStructureSubRecord.java b/src/testcases/org/apache/poi/hssf/record/TestNoteStructureSubRecord.java index 014a5be2ba..fd2ae059b7 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestNoteStructureSubRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestNoteStructureSubRecord.java @@ -38,7 +38,7 @@ public final class TestNoteStructureSubRecord extends TestCase { public void testRead() { - NoteStructureSubRecord record = new NoteStructureSubRecord(new TestcaseRecordInputStream(NoteStructureSubRecord.sid, (short)data.length, data)); + NoteStructureSubRecord record = new NoteStructureSubRecord(TestcaseRecordInputStream.create(NoteStructureSubRecord.sid, data)); assertEquals(NoteStructureSubRecord.sid, record.getSid()); assertEquals(data.length + 4, record.getRecordSize()); diff --git a/src/testcases/org/apache/poi/hssf/record/TestNumberFormatIndexRecord.java b/src/testcases/org/apache/poi/hssf/record/TestNumberFormatIndexRecord.java index 1ee74f2cc7..570d71ec62 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestNumberFormatIndexRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestNumberFormatIndexRecord.java @@ -35,7 +35,7 @@ public final class TestNumberFormatIndexRecord extends TestCase { public void testLoad() { - NumberFormatIndexRecord record = new NumberFormatIndexRecord(new TestcaseRecordInputStream((short)0x104e, (short)data.length, data)); + NumberFormatIndexRecord record = new NumberFormatIndexRecord(TestcaseRecordInputStream.create(0x104e, data)); assertEquals( 5, record.getFormatIndex()); assertEquals( 6, record.getRecordSize() ); diff --git a/src/testcases/org/apache/poi/hssf/record/TestObjRecord.java b/src/testcases/org/apache/poi/hssf/record/TestObjRecord.java index e8a6596e55..df26797807 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestObjRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestObjRecord.java @@ -51,7 +51,7 @@ public final class TestObjRecord extends TestCase { }; public void testLoad() { - ObjRecord record = new ObjRecord(new TestcaseRecordInputStream(ObjRecord.sid, (short)recdata.length, recdata)); + ObjRecord record = new ObjRecord(TestcaseRecordInputStream.create(ObjRecord.sid, recdata)); assertEquals(28, record.getRecordSize() - 4); @@ -63,7 +63,7 @@ public final class TestObjRecord extends TestCase { } public void testStore() { - ObjRecord record = new ObjRecord(new TestcaseRecordInputStream(ObjRecord.sid, (short)recdata.length, recdata)); + ObjRecord record = new ObjRecord(TestcaseRecordInputStream.create(ObjRecord.sid, recdata)); byte [] recordBytes = record.serialize(); assertEquals(28, recordBytes.length - 4); @@ -91,7 +91,7 @@ public final class TestObjRecord extends TestCase { byte [] bytes = new byte[recordBytes.length-4]; System.arraycopy(recordBytes, 4, bytes, 0, bytes.length); - record = new ObjRecord(new TestcaseRecordInputStream(ObjRecord.sid, (short)bytes.length, bytes)); + record = new ObjRecord(TestcaseRecordInputStream.create(ObjRecord.sid, bytes)); List subrecords = record.getSubRecords(); assertEquals( 2, subrecords.size() ); assertTrue( subrecords.get(0) instanceof CommonObjectDataSubRecord); @@ -99,7 +99,7 @@ public final class TestObjRecord extends TestCase { } public void testReadWriteWithPadding_bug45133() { - ObjRecord record = new ObjRecord(new TestcaseRecordInputStream(ObjRecord.sid, (short)recdataNeedingPadding.length, recdataNeedingPadding)); + ObjRecord record = new ObjRecord(TestcaseRecordInputStream.create(ObjRecord.sid, recdataNeedingPadding)); if (record.getRecordSize() == 34) { throw new AssertionFailedError("Identified bug 45133"); diff --git a/src/testcases/org/apache/poi/hssf/record/TestObjectLinkRecord.java b/src/testcases/org/apache/poi/hssf/record/TestObjectLinkRecord.java index e9d536df0a..9d8168d4b5 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestObjectLinkRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestObjectLinkRecord.java @@ -34,7 +34,7 @@ public final class TestObjectLinkRecord extends TestCase { }; public void testLoad() { - ObjectLinkRecord record = new ObjectLinkRecord(new TestcaseRecordInputStream((short)0x1027, (short)data.length, data)); + ObjectLinkRecord record = new ObjectLinkRecord(TestcaseRecordInputStream.create(0x1027, data)); assertEquals( (short)3, record.getAnchorId()); assertEquals( (short)0x00, record.getLink1()); diff --git a/src/testcases/org/apache/poi/hssf/record/TestPaneRecord.java b/src/testcases/org/apache/poi/hssf/record/TestPaneRecord.java index aa80047913..93d1a1f987 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestPaneRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestPaneRecord.java @@ -37,7 +37,7 @@ public final class TestPaneRecord extends TestCase { }; public void testLoad() { - PaneRecord record = new PaneRecord(new TestcaseRecordInputStream((short)0x41, (short)data.length, data)); + PaneRecord record = new PaneRecord(TestcaseRecordInputStream.create(0x41, data)); assertEquals( (short)1, record.getX()); assertEquals( (short)2, record.getY()); diff --git a/src/testcases/org/apache/poi/hssf/record/TestPlotAreaRecord.java b/src/testcases/org/apache/poi/hssf/record/TestPlotAreaRecord.java index aa5941a49a..631d6895d9 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestPlotAreaRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestPlotAreaRecord.java @@ -34,7 +34,7 @@ public final class TestPlotAreaRecord extends TestCase { }; public void testLoad() { - PlotAreaRecord record = new PlotAreaRecord(new TestcaseRecordInputStream((short)0x1035, (short)data.length, data)); + PlotAreaRecord record = new PlotAreaRecord(TestcaseRecordInputStream.create(0x1035, data)); assertEquals( 4, record.getRecordSize() ); } diff --git a/src/testcases/org/apache/poi/hssf/record/TestPlotGrowthRecord.java b/src/testcases/org/apache/poi/hssf/record/TestPlotGrowthRecord.java index 2897d8c332..c5896d2b38 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestPlotGrowthRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestPlotGrowthRecord.java @@ -35,7 +35,7 @@ public final class TestPlotGrowthRecord extends TestCase { public void testLoad() { - PlotGrowthRecord record = new PlotGrowthRecord(new TestcaseRecordInputStream((short)0x1064, (short)data.length, data)); + PlotGrowthRecord record = new PlotGrowthRecord(TestcaseRecordInputStream.create(0x1064, data)); assertEquals( 65536, record.getHorizontalScale()); assertEquals( 65536, record.getVerticalScale()); diff --git a/src/testcases/org/apache/poi/hssf/record/TestRecordFactory.java b/src/testcases/org/apache/poi/hssf/record/TestRecordFactory.java index 6927c6820a..13cea4189c 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestRecordFactory.java +++ b/src/testcases/org/apache/poi/hssf/record/TestRecordFactory.java @@ -49,7 +49,7 @@ public final class TestRecordFactory extends TestCase { 0, 6, 5, 0, -2, 28, -51, 7, -55, 64, 0, 0, 6, 1, 0, 0 }; short size = 16; - Record[] record = RecordFactory.createRecord(new TestcaseRecordInputStream(recType, size, data)); + Record[] record = RecordFactory.createRecord(TestcaseRecordInputStream.create(recType, data)); assertEquals(BOFRecord.class.getName(), record[ 0 ].getClass().getName()); @@ -69,7 +69,7 @@ public final class TestRecordFactory extends TestCase { { 0, 0 }; - record = RecordFactory.createRecord(new TestcaseRecordInputStream(recType, size, data)); + record = RecordFactory.createRecord(TestcaseRecordInputStream.create(recType, data)); assertEquals(MMSRecord.class.getName(), record[ 0 ].getClass().getName()); MMSRecord mmsRecord = ( MMSRecord ) record[ 0 ]; @@ -94,7 +94,7 @@ public final class TestRecordFactory extends TestCase { 0, 0, 0, 0, 21, 0, 0, 0, 0, 0 }; short size = 10; - Record[] record = RecordFactory.createRecord(new TestcaseRecordInputStream(recType, size, data)); + Record[] record = RecordFactory.createRecord(TestcaseRecordInputStream.create(recType, data)); assertEquals(NumberRecord.class.getName(), record[ 0 ].getClass().getName()); diff --git a/src/testcases/org/apache/poi/hssf/record/TestRecordInputStream.java b/src/testcases/org/apache/poi/hssf/record/TestRecordInputStream.java new file mode 100644 index 0000000000..2b236e1ac7 --- /dev/null +++ b/src/testcases/org/apache/poi/hssf/record/TestRecordInputStream.java @@ -0,0 +1,97 @@ +/* ==================================================================== + 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.util.HexRead; + +import junit.framework.AssertionFailedError; +import junit.framework.TestCase; + +/** + * Tests for {@link RecordInputStream} + * + * @author Josh Micich + */ +public final class TestRecordInputStream extends TestCase { + + /** + * Data inspired by attachment 22626 of bug 45866
+ * A unicode string of 18 chars, with a continue record where the compression flag changes + */ + private static final String HED_DUMP1 = "" + + "1A 59 00 8A 9E 8A " // 3 uncompressed unicode chars + + "3C 00 " // Continue sid + + "10 00 " // rec size 16 (1+15) + + "00" // next chunk is compressed + + "20 2D 20 4D 75 6C 74 69 6C 69 6E 67 75 61 6C " // 15 chars + ; + /** + * same string re-arranged + */ + private static final String HED_DUMP2 = "" + // 15 chars at end of current record + + "4D 75 6C 74 69 6C 69 6E 67 75 61 6C 20 2D 20" + + "3C 00 " // Continue sid + + "07 00 " // rec size 7 (1+6) + + "01" // this bit uncompressed + + "1A 59 00 8A 9E 8A " // 3 uncompressed unicode chars + ; + public void testChangeOfCompressionFlag_bug25866() { + byte[] changingFlagSimpleData = HexRead.readFromString("" + + "AA AA " // fake SID + + "06 00 " // first rec len 6 + + HED_DUMP1 + ); + RecordInputStream in = TestcaseRecordInputStream.create(changingFlagSimpleData); + String actual; + try { + actual = in.readUnicodeLEString(18); + } catch (IllegalArgumentException e) { + if ("compressByte in continue records must be 1 while reading unicode LE string".equals(e.getMessage())) { + throw new AssertionFailedError("Identified bug 45866"); + } + + throw e; + } + assertEquals("\u591A\u8A00\u8A9E - Multilingual", actual); + } + + public void testChangeFromUnCompressedToCompressed() { + byte[] changingFlagSimpleData = HexRead.readFromString("" + + "AA AA " // fake SID + + "0F 00 " // first rec len 15 + + HED_DUMP2 + ); + RecordInputStream in = TestcaseRecordInputStream.create(changingFlagSimpleData); + String actual = in.readCompressedUnicode(18); + assertEquals("Multilingual - \u591A\u8A00\u8A9E", actual); + } + + public void testReadString() { + byte[] changingFlagFullData = HexRead.readFromString("" + + "AA AA " // fake SID + + "12 00 " // first rec len 18 (15 + next 3 bytes) + + "12 00 " // total chars 18 + + "00 " // this bit compressed + + HED_DUMP2 + ); + RecordInputStream in = TestcaseRecordInputStream.create(changingFlagFullData); + String actual = in.readString(); + assertEquals("Multilingual - \u591A\u8A00\u8A9E", actual); + } +} diff --git a/src/testcases/org/apache/poi/hssf/record/TestSCLRecord.java b/src/testcases/org/apache/poi/hssf/record/TestSCLRecord.java index 9b98dab1f6..335b6605d7 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestSCLRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestSCLRecord.java @@ -34,7 +34,7 @@ public final class TestSCLRecord extends TestCase { }; public void testLoad() { - SCLRecord record = new SCLRecord(new TestcaseRecordInputStream((short)0xa0, (short)data.length, data)); + SCLRecord record = new SCLRecord(TestcaseRecordInputStream.create(0xa0, data)); assertEquals( 3, record.getNumerator()); assertEquals( 4, record.getDenominator()); diff --git a/src/testcases/org/apache/poi/hssf/record/TestSSTDeserializer.java b/src/testcases/org/apache/poi/hssf/record/TestSSTDeserializer.java index 1cb1252b45..b16d2f83c7 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestSSTDeserializer.java +++ b/src/testcases/org/apache/poi/hssf/record/TestSSTDeserializer.java @@ -32,31 +32,30 @@ import org.apache.poi.util.IntMapper; * @author Glen Stampoultzis (glens at apache.org) */ public final class TestSSTDeserializer extends TestCase { + private static final int FAKE_SID = -5555; - - private byte[] joinArray(byte[] array1, byte[] array2) { - byte[] bigArray = new byte[array1.length + array2.length]; - System.arraycopy(array1, 0, bigArray, 0, array1.length); - System.arraycopy(array2, 0, bigArray, array1.length, array2.length); - return bigArray; + private static byte[] concat(byte[] a, byte[] b) { + byte[] result = new byte[a.length + b.length]; + System.arraycopy(a, 0, result, 0, a.length); + System.arraycopy(b, 0, result, a.length, b.length); + return result; } - private static byte[] readSampleHexData(String sampleFileName, String sectionName) { + private static byte[] readSampleHexData(String sampleFileName, String sectionName, int recSid) { InputStream is = HSSFTestDataSamples.openSampleFileStream(sampleFileName); + byte[] data; try { - return HexRead.readData(is, sectionName); + data = HexRead.readData(is, sectionName); } catch (IOException e) { throw new RuntimeException(e); } + return TestcaseRecordInputStream.mergeDataAndSid(recSid, data.length, data); } - public void testSpanRichTextToPlainText() - throws Exception - { - byte[] header = readSampleHexData("richtextdata.txt", "header" ); - byte[] continueBytes = readSampleHexData("richtextdata.txt", "continue1" ); - continueBytes = TestcaseRecordInputStream.mergeDataAndSid(ContinueRecord.sid, (short)continueBytes.length, continueBytes); - TestcaseRecordInputStream in = new TestcaseRecordInputStream((short)0, (short)header.length, joinArray(header, continueBytes)); + public void testSpanRichTextToPlainText() { + byte[] header = readSampleHexData("richtextdata.txt", "header", FAKE_SID); + byte[] continueBytes = readSampleHexData("richtextdata.txt", "continue1", ContinueRecord.sid); + RecordInputStream in = TestcaseRecordInputStream.create(concat(header, continueBytes)); IntMapper strings = new IntMapper(); @@ -66,13 +65,10 @@ public final class TestSSTDeserializer extends TestCase { assertEquals( "At a dinner party orAt At At ", strings.get( 0 ) + "" ); } - public void testContinuationWithNoOverlap() - throws Exception - { - byte[] header = readSampleHexData("evencontinuation.txt", "header" ); - byte[] continueBytes = readSampleHexData("evencontinuation.txt", "continue1" ); - continueBytes = TestcaseRecordInputStream.mergeDataAndSid(ContinueRecord.sid, (short)continueBytes.length, continueBytes); - TestcaseRecordInputStream in = new TestcaseRecordInputStream((short)0, (short)header.length, joinArray(header, continueBytes)); + public void testContinuationWithNoOverlap() { + byte[] header = readSampleHexData("evencontinuation.txt", "header", FAKE_SID); + byte[] continueBytes = readSampleHexData("evencontinuation.txt", "continue1", ContinueRecord.sid); + RecordInputStream in = TestcaseRecordInputStream.create(concat(header, continueBytes)); IntMapper strings = new IntMapper(); SSTDeserializer deserializer = new SSTDeserializer( strings ); @@ -85,18 +81,12 @@ public final class TestSSTDeserializer extends TestCase { /** * Strings can actually span across more than one continuation. */ - public void testStringAcross2Continuations() - throws Exception - { - byte[] header = readSampleHexData("stringacross2continuations.txt", "header" ); - byte[] continue1 = readSampleHexData("stringacross2continuations.txt", "continue1" ); - continue1 = TestcaseRecordInputStream.mergeDataAndSid(ContinueRecord.sid, (short)continue1.length, continue1); - byte[] continue2 = readSampleHexData("stringacross2continuations.txt", "continue2" ); - continue2 = TestcaseRecordInputStream.mergeDataAndSid(ContinueRecord.sid, (short)continue2.length, continue2); + public void testStringAcross2Continuations() { + byte[] header = readSampleHexData("stringacross2continuations.txt", "header", FAKE_SID); + byte[] continue1 = readSampleHexData("stringacross2continuations.txt", "continue1", ContinueRecord.sid); + byte[] continue2 = readSampleHexData("stringacross2continuations.txt", "continue2", ContinueRecord.sid); - byte[] bytes = joinArray(header, continue1); - bytes = joinArray(bytes, continue2); - TestcaseRecordInputStream in = new TestcaseRecordInputStream((short)0, (short)header.length, bytes); + RecordInputStream in = TestcaseRecordInputStream.create(concat(header, concat(continue1, continue2))); IntMapper strings = new IntMapper(); SSTDeserializer deserializer = new SSTDeserializer( strings ); @@ -107,10 +97,9 @@ public final class TestSSTDeserializer extends TestCase { } public void testExtendedStrings() { - byte[] header = readSampleHexData("extendedtextstrings.txt", "rich-header" ); - byte[] continueBytes = readSampleHexData("extendedtextstrings.txt", "rich-continue1" ); - continueBytes = TestcaseRecordInputStream.mergeDataAndSid(ContinueRecord.sid, (short)continueBytes.length, continueBytes); - TestcaseRecordInputStream in = new TestcaseRecordInputStream((short)0, (short)header.length, joinArray(header, continueBytes)); + byte[] header = readSampleHexData("extendedtextstrings.txt", "rich-header", FAKE_SID); + byte[] continueBytes = readSampleHexData("extendedtextstrings.txt", "rich-continue1", ContinueRecord.sid); + RecordInputStream in = TestcaseRecordInputStream.create(concat(header, continueBytes)); IntMapper strings = new IntMapper(); SSTDeserializer deserializer = new SSTDeserializer( strings ); @@ -119,10 +108,9 @@ public final class TestSSTDeserializer extends TestCase { assertEquals( "At a dinner party orAt At At ", strings.get( 0 ) + "" ); - header = readSampleHexData("extendedtextstrings.txt", "norich-header" ); - continueBytes = readSampleHexData("extendedtextstrings.txt", "norich-continue1" ); - continueBytes = TestcaseRecordInputStream.mergeDataAndSid(ContinueRecord.sid, (short)continueBytes.length, continueBytes); - in = new TestcaseRecordInputStream((short)0, (short)header.length, joinArray(header, continueBytes)); + header = readSampleHexData("extendedtextstrings.txt", "norich-header", FAKE_SID); + continueBytes = readSampleHexData("extendedtextstrings.txt", "norich-continue1", ContinueRecord.sid); + in = TestcaseRecordInputStream.create(concat(header, continueBytes)); strings = new IntMapper(); deserializer = new SSTDeserializer( strings ); diff --git a/src/testcases/org/apache/poi/hssf/record/TestSeriesChartGroupIndexRecord.java b/src/testcases/org/apache/poi/hssf/record/TestSeriesChartGroupIndexRecord.java index 1f30f26ec0..cd09e061e6 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestSeriesChartGroupIndexRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestSeriesChartGroupIndexRecord.java @@ -33,7 +33,7 @@ public final class TestSeriesChartGroupIndexRecord extends TestCase { }; public void testLoad() { - SeriesChartGroupIndexRecord record = new SeriesChartGroupIndexRecord(new TestcaseRecordInputStream((short)0x1045, (short)data.length, data)); + SeriesChartGroupIndexRecord record = new SeriesChartGroupIndexRecord(TestcaseRecordInputStream.create(0x1045, data)); assertEquals( 0, record.getChartGroupIndex()); assertEquals( 6, record.getRecordSize() ); diff --git a/src/testcases/org/apache/poi/hssf/record/TestSeriesIndexRecord.java b/src/testcases/org/apache/poi/hssf/record/TestSeriesIndexRecord.java index b971128c99..9ba9b0ad9e 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestSeriesIndexRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestSeriesIndexRecord.java @@ -34,7 +34,7 @@ public final class TestSeriesIndexRecord extends TestCase { }; public void testLoad() { - SeriesIndexRecord record = new SeriesIndexRecord(new TestcaseRecordInputStream((short)0x1065, (short)data.length, data)); + SeriesIndexRecord record = new SeriesIndexRecord(TestcaseRecordInputStream.create(0x1065, data)); assertEquals( (short)3, record.getIndex()); assertEquals( 6, record.getRecordSize() ); diff --git a/src/testcases/org/apache/poi/hssf/record/TestSeriesLabelsRecord.java b/src/testcases/org/apache/poi/hssf/record/TestSeriesLabelsRecord.java index 265583655d..c1602dd2a3 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestSeriesLabelsRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestSeriesLabelsRecord.java @@ -34,7 +34,7 @@ public final class TestSeriesLabelsRecord extends TestCase { }; public void testLoad() { - SeriesLabelsRecord record = new SeriesLabelsRecord(new TestcaseRecordInputStream((short)0x100c, (short)data.length, data)); + SeriesLabelsRecord record = new SeriesLabelsRecord(TestcaseRecordInputStream.create(0x100c, data)); assertEquals( 3, record.getFormatFlags()); assertEquals( true, record.isShowActual() ); assertEquals( true, record.isShowPercent() ); diff --git a/src/testcases/org/apache/poi/hssf/record/TestSeriesListRecord.java b/src/testcases/org/apache/poi/hssf/record/TestSeriesListRecord.java index 027b6c3867..1669dc4dfc 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestSeriesListRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestSeriesListRecord.java @@ -35,7 +35,7 @@ public final class TestSeriesListRecord extends TestCase { public void testLoad() { - SeriesListRecord record = new SeriesListRecord(new TestcaseRecordInputStream((short)0x1016, (short)data.length, data)); + SeriesListRecord record = new SeriesListRecord(TestcaseRecordInputStream.create(0x1016, data)); assertEquals( (short)0x2001, record.getSeriesNumbers()[0]); assertEquals( (short)0xf0ff, record.getSeriesNumbers()[1]); assertEquals( 2, record.getSeriesNumbers().length); diff --git a/src/testcases/org/apache/poi/hssf/record/TestSeriesRecord.java b/src/testcases/org/apache/poi/hssf/record/TestSeriesRecord.java index 69232754fb..2e7cfa6fee 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestSeriesRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestSeriesRecord.java @@ -39,7 +39,7 @@ public final class TestSeriesRecord extends TestCase { public void testLoad() { - SeriesRecord record = new SeriesRecord(new TestcaseRecordInputStream((short)0x1003, (short)data.length, data)); + SeriesRecord record = new SeriesRecord(TestcaseRecordInputStream.create(0x1003, data)); assertEquals( SeriesRecord.CATEGORY_DATA_TYPE_NUMERIC, record.getCategoryDataType()); assertEquals( SeriesRecord.VALUES_DATA_TYPE_NUMERIC, record.getValuesDataType()); assertEquals( 27, record.getNumCategories()); diff --git a/src/testcases/org/apache/poi/hssf/record/TestSeriesTextRecord.java b/src/testcases/org/apache/poi/hssf/record/TestSeriesTextRecord.java index 08e4189afb..a016e60e91 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestSeriesTextRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestSeriesTextRecord.java @@ -34,7 +34,7 @@ public final class TestSeriesTextRecord extends TestCase { }; public void testLoad() { - SeriesTextRecord record = new SeriesTextRecord(new TestcaseRecordInputStream((short)0x100d, (short)data.length, data)); + SeriesTextRecord record = new SeriesTextRecord(TestcaseRecordInputStream.create(0x100d, data)); assertEquals( (short)0, record.getId()); assertEquals( (byte)0x0C, record.getTextLength()); diff --git a/src/testcases/org/apache/poi/hssf/record/TestSeriesToChartGroupRecord.java b/src/testcases/org/apache/poi/hssf/record/TestSeriesToChartGroupRecord.java index 4f20e0e696..8112c54b70 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestSeriesToChartGroupRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestSeriesToChartGroupRecord.java @@ -34,7 +34,7 @@ public final class TestSeriesToChartGroupRecord extends TestCase { }; public void testLoad() { - SeriesToChartGroupRecord record = new SeriesToChartGroupRecord(new TestcaseRecordInputStream((short)0x1045, (short)data.length, data)); + SeriesToChartGroupRecord record = new SeriesToChartGroupRecord(TestcaseRecordInputStream.create(0x1045, data)); assertEquals( 0x0, record.getChartGroupIndex()); assertEquals( 0x6, record.getRecordSize() ); diff --git a/src/testcases/org/apache/poi/hssf/record/TestSharedFormulaRecord.java b/src/testcases/org/apache/poi/hssf/record/TestSharedFormulaRecord.java index 7a13cfe5fd..8a52211a6a 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestSharedFormulaRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestSharedFormulaRecord.java @@ -59,7 +59,7 @@ public final class TestSharedFormulaRecord extends TestCase { */ public void testConvertSharedFormulasOperandClasses_bug45123() { - TestcaseRecordInputStream in = new TestcaseRecordInputStream(0, SHARED_FORMULA_WITH_REF_ARRAYS_DATA); + RecordInputStream in = TestcaseRecordInputStream.createWithFakeSid(SHARED_FORMULA_WITH_REF_ARRAYS_DATA); int encodedLen = in.readUShort(); Ptg[] sharedFormula = Ptg.readTokens(encodedLen, in); diff --git a/src/testcases/org/apache/poi/hssf/record/TestSheetPropertiesRecord.java b/src/testcases/org/apache/poi/hssf/record/TestSheetPropertiesRecord.java index 932ff6eace..aa870a3374 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestSheetPropertiesRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestSheetPropertiesRecord.java @@ -36,7 +36,7 @@ public final class TestSheetPropertiesRecord extends TestCase { }; public void testLoad() { - SheetPropertiesRecord record = new SheetPropertiesRecord(new TestcaseRecordInputStream((short)0x1044, (short)data.length, data)); + SheetPropertiesRecord record = new SheetPropertiesRecord(TestcaseRecordInputStream.create(0x1044, data)); assertEquals( 10, record.getFlags()); assertEquals( false, record.isChartTypeManuallyFormatted() ); assertEquals( true, record.isPlotVisibleOnly() ); diff --git a/src/testcases/org/apache/poi/hssf/record/TestStringRecord.java b/src/testcases/org/apache/poi/hssf/record/TestStringRecord.java index 7f06c54ab3..14b708cdc8 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestStringRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestStringRecord.java @@ -27,7 +27,7 @@ import junit.framework.TestCase; * * @author Glen Stampoultzis (glens at apache.org) */ -public class TestStringRecord extends TestCase { +public final class TestStringRecord extends TestCase { byte[] data = new byte[] { (byte)0x0B,(byte)0x00, // length (byte)0x00, // option @@ -37,7 +37,7 @@ public class TestStringRecord extends TestCase { public void testLoad() { - StringRecord record = new StringRecord(new TestcaseRecordInputStream((short)0x207, (short)data.length, data)); + StringRecord record = new StringRecord(TestcaseRecordInputStream.create(0x207, data)); assertEquals( "Fahrzeugtyp", record.getString()); assertEquals( 18, record.getRecordSize() ); diff --git a/src/testcases/org/apache/poi/hssf/record/TestSupBookRecord.java b/src/testcases/org/apache/poi/hssf/record/TestSupBookRecord.java index 5506f6abdf..d7725b8ee0 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestSupBookRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestSupBookRecord.java @@ -51,7 +51,7 @@ public final class TestSupBookRecord extends TestCase { */ public void testLoadIR() { - SupBookRecord record = new SupBookRecord(new TestcaseRecordInputStream((short)0x01AE, dataIR)); + SupBookRecord record = new SupBookRecord(TestcaseRecordInputStream.create(0x01AE, dataIR)); assertTrue( record.isInternalReferences() ); //expected flag assertEquals( 0x4, record.getNumberOfSheets() ); //expected # of sheets @@ -62,7 +62,7 @@ public final class TestSupBookRecord extends TestCase { */ public void testLoadER() { - SupBookRecord record = new SupBookRecord(new TestcaseRecordInputStream((short)0x01AE, dataER)); + SupBookRecord record = new SupBookRecord(TestcaseRecordInputStream.create(0x01AE, dataER)); assertTrue( record.isExternalReferences() ); //expected flag assertEquals( 0x2, record.getNumberOfSheets() ); //expected # of sheets @@ -80,7 +80,7 @@ public final class TestSupBookRecord extends TestCase { */ public void testLoadAIF() { - SupBookRecord record = new SupBookRecord(new TestcaseRecordInputStream((short)0x01AE, dataAIF)); + SupBookRecord record = new SupBookRecord(TestcaseRecordInputStream.create(0x01AE, dataAIF)); assertTrue( record.isAddInFunctions() ); //expected flag assertEquals( 0x1, record.getNumberOfSheets() ); //expected # of sheets assertEquals( 8, record.getRecordSize() ); //sid+size+data diff --git a/src/testcases/org/apache/poi/hssf/record/TestTableRecord.java b/src/testcases/org/apache/poi/hssf/record/TestTableRecord.java index 19c91bbacb..3a2ada6e78 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestTableRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestTableRecord.java @@ -44,7 +44,7 @@ public final class TestTableRecord extends TestCase { public void testLoad() { - TableRecord record = new TableRecord(new TestcaseRecordInputStream((short)0x236, (short)data.length, data)); + TableRecord record = new TableRecord(TestcaseRecordInputStream.create(0x236, data)); CellRangeAddress8Bit range = record.getRange(); assertEquals(3, range.getFirstRow()); diff --git a/src/testcases/org/apache/poi/hssf/record/TestTextObjectBaseRecord.java b/src/testcases/org/apache/poi/hssf/record/TestTextObjectBaseRecord.java index b9d80dbad5..b8f9e86468 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestTextObjectBaseRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestTextObjectBaseRecord.java @@ -18,6 +18,11 @@ package org.apache.poi.hssf.record; +import java.io.ByteArrayInputStream; + +import org.apache.poi.hssf.usermodel.HSSFRichTextString; +import org.apache.poi.util.HexRead; + import junit.framework.TestCase; /** @@ -25,63 +30,62 @@ import junit.framework.TestCase; * class works correctly. Test data taken directly from a real * Excel file. * - * @author Glen Stampoultzis (glens at apache.org) */ -public class TestTextObjectBaseRecord extends TestCase { - byte[] data = new byte[] { - 0x44, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x00, 0x00, - }; +public final class TestTextObjectBaseRecord extends TestCase { + /** data for one TXO rec and two continue recs */ + private static final byte[] data = HexRead.readFromString( + "B6 01 " + // TextObjectRecord.sid + "12 00 " + // size 18 + "44 02 02 00 00 00 00 00" + + "00 00 " + + "02 00 " + // strLen 2 + "10 00 " + // 16 bytes for 2 format runs + "00 00" + + "00 00 " + + "3C 00 " + // ContinueRecord.sid + "05 00 " + // size 5 + "01 " + // unicode uncompressed + "41 00 42 00 " + // 'AB' + "3C 00 " + // ContinueRecord.sid + "10 00 " + // size 16 + "00 00 18 00 00 00 00 00 " + + "02 00 00 00 00 00 00 00 " + ); + public void testLoad() { - TextObjectBaseRecord record = new TextObjectBaseRecord(new TestcaseRecordInputStream((short)0x1B6, (short)data.length, data)); - - -// assertEquals( (short), record.getOptions()); - assertEquals( false, record.isReserved1() ); - assertEquals( TextObjectBaseRecord.HORIZONTAL_TEXT_ALIGNMENT_CENTERED, record.getHorizontalTextAlignment() ); - assertEquals( TextObjectBaseRecord.VERTICAL_TEXT_ALIGNMENT_JUSTIFY, record.getVerticalTextAlignment() ); - assertEquals( 0, record.getReserved2() ); - assertEquals( true, record.isTextLocked() ); - assertEquals( 0, record.getReserved3() ); - assertEquals( TextObjectBaseRecord.TEXT_ORIENTATION_ROT_RIGHT, record.getTextOrientation()); - assertEquals( 0, record.getReserved4()); - assertEquals( 0, record.getReserved5()); - assertEquals( 0, record.getReserved6()); - assertEquals( 2, record.getTextLength()); - assertEquals( 2, record.getFormattingRunLength()); - assertEquals( 0, record.getReserved7()); - - - assertEquals( 22, record.getRecordSize() ); + RecordInputStream in = new RecordInputStream(new ByteArrayInputStream(data)); + in.nextRecord(); + TextObjectRecord record = new TextObjectRecord(in); + + + assertEquals(TextObjectRecord.HORIZONTAL_TEXT_ALIGNMENT_CENTERED, record.getHorizontalTextAlignment()); + assertEquals(TextObjectRecord.VERTICAL_TEXT_ALIGNMENT_JUSTIFY, record.getVerticalTextAlignment()); + assertEquals(true, record.isTextLocked()); + assertEquals(TextObjectRecord.TEXT_ORIENTATION_ROT_RIGHT, record.getTextOrientation()); + + assertEquals(51, record.getRecordSize() ); } public void testStore() { - TextObjectBaseRecord record = new TextObjectBaseRecord(); + TextObjectRecord record = new TextObjectRecord(); + HSSFRichTextString str = new HSSFRichTextString("AB"); + str.applyFont(0, 2, (short)0x0018); + str.applyFont(2, 2, (short)0x0320); -// record.setOptions( (short) 0x0000); - record.setReserved1( false ); - record.setHorizontalTextAlignment( TextObjectBaseRecord.HORIZONTAL_TEXT_ALIGNMENT_CENTERED ); - record.setVerticalTextAlignment( TextObjectBaseRecord.VERTICAL_TEXT_ALIGNMENT_JUSTIFY ); - record.setReserved2( (short)0 ); - record.setTextLocked( true ); - record.setReserved3( (short)0 ); - record.setTextOrientation( TextObjectBaseRecord.TEXT_ORIENTATION_ROT_RIGHT ); - record.setReserved4( (short)0 ); - record.setReserved5( (short)0 ); - record.setReserved6( (short)0 ); - record.setTextLength( (short)2 ); - record.setFormattingRunLength( (short)2 ); - record.setReserved7( 0 ); + record.setHorizontalTextAlignment(TextObjectRecord.HORIZONTAL_TEXT_ALIGNMENT_CENTERED); + record.setVerticalTextAlignment(TextObjectRecord.VERTICAL_TEXT_ALIGNMENT_JUSTIFY); + record.setTextLocked(true); + record.setTextOrientation(TextObjectRecord.TEXT_ORIENTATION_ROT_RIGHT); + record.setStr(str); byte [] recordBytes = record.serialize(); - assertEquals(recordBytes.length - 4, data.length); + assertEquals(recordBytes.length, data.length); for (int i = 0; i < data.length; i++) - assertEquals("At offset " + i, data[i], recordBytes[i+4]); + assertEquals("At offset " + i, data[i], recordBytes[i]); } } diff --git a/src/testcases/org/apache/poi/hssf/record/TestTextObjectRecord.java b/src/testcases/org/apache/poi/hssf/record/TestTextObjectRecord.java index 91458e9ddb..b7d45e28b0 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestTextObjectRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestTextObjectRecord.java @@ -22,7 +22,11 @@ import java.util.Arrays; import junit.framework.TestCase; +import org.apache.poi.hssf.record.formula.Ptg; +import org.apache.poi.hssf.record.formula.RefPtg; import org.apache.poi.hssf.usermodel.HSSFRichTextString; +import org.apache.poi.util.HexRead; +import org.apache.poi.util.LittleEndian; /** * Tests that serialization and deserialization of the TextObjectRecord . @@ -32,17 +36,23 @@ import org.apache.poi.hssf.usermodel.HSSFRichTextString; */ public final class TestTextObjectRecord extends TestCase { - byte[] data = {(byte)0xB6, 0x01, 0x12, 0x00, 0x12, 0x02, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x3C, 0x00, 0x1B, 0x00, 0x01, 0x48, 0x00, 0x65, 0x00, 0x6C, - 0x00, 0x6C, 0x00, 0x6F, 0x00, 0x2C, 0x00, 0x20, 0x00, 0x57, 0x00, - 0x6F, 0x00, 0x72, 0x00, 0x6C, 0x00, 0x64, 0x00, 0x21, 0x00, 0x3C, - 0x00, 0x08, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + private static final byte[] simpleData = HexRead.readFromString( + "B6 01 12 00 " + + "12 02 00 00 00 00 00 00" + + "00 00 0D 00 08 00 00 00" + + "00 00 " + + "3C 00 1B 00 " + + "01 48 00 65 00 6C 00 6C 00 6F 00 " + + "2C 00 20 00 57 00 6F 00 72 00 6C " + + "00 64 00 21 00 " + + "3C 00 08 " + + "00 0D 00 00 00 00 00 00 00" + ); public void testRead() { - RecordInputStream is = new RecordInputStream(new ByteArrayInputStream(data)); + RecordInputStream is = new RecordInputStream(new ByteArrayInputStream(simpleData)); is.nextRecord(); TextObjectRecord record = new TextObjectRecord(is); @@ -50,36 +60,51 @@ public final class TestTextObjectRecord extends TestCase { assertEquals(TextObjectRecord.HORIZONTAL_TEXT_ALIGNMENT_LEFT_ALIGNED, record.getHorizontalTextAlignment()); assertEquals(TextObjectRecord.VERTICAL_TEXT_ALIGNMENT_TOP, record.getVerticalTextAlignment()); assertEquals(TextObjectRecord.TEXT_ORIENTATION_NONE, record.getTextOrientation()); - assertEquals(0, record.getReserved7()); assertEquals("Hello, World!", record.getStr().getString()); - } - public void testWrite() - { + public void testWrite() { HSSFRichTextString str = new HSSFRichTextString("Hello, World!"); TextObjectRecord record = new TextObjectRecord(); - int frLength = ( str.numFormattingRuns() + 1 ) * 8; - record.setFormattingRunLength( (short) frLength ); - record.setTextLength( (short) str.length() ); - record.setStr( str ); + record.setStr(str); record.setHorizontalTextAlignment( TextObjectRecord.HORIZONTAL_TEXT_ALIGNMENT_LEFT_ALIGNED ); record.setVerticalTextAlignment( TextObjectRecord.VERTICAL_TEXT_ALIGNMENT_TOP ); record.setTextLocked( true ); record.setTextOrientation( TextObjectRecord.TEXT_ORIENTATION_NONE ); - record.setReserved7( 0 ); byte [] ser = record.serialize(); - //assertEquals(ser.length , data.length); + assertEquals(ser.length , simpleData.length); - //assertTrue(Arrays.equals(data, ser)); + assertTrue(Arrays.equals(simpleData, ser)); //read again - RecordInputStream is = new RecordInputStream(new ByteArrayInputStream(data)); + RecordInputStream is = new RecordInputStream(new ByteArrayInputStream(simpleData)); is.nextRecord(); record = new TextObjectRecord(is); + } + + /** + * Zero {@link ContinueRecord}s follow a {@link TextObjectRecord} if the text is empty + */ + public void testWriteEmpty() { + HSSFRichTextString str = new HSSFRichTextString(""); + + TextObjectRecord record = new TextObjectRecord(); + record.setStr(str); + byte [] ser = record.serialize(); + + int formatDataLen = LittleEndian.getUShort(ser, 16); + assertEquals("formatDataLength", 0, formatDataLen); + + assertEquals(22, ser.length); // just the TXO record + + //read again + RecordInputStream is = new RecordInputStream(new ByteArrayInputStream(ser)); + is.nextRecord(); + record = new TextObjectRecord(is); + assertEquals(0, record.getStr().length()); } /** @@ -95,10 +120,7 @@ public final class TestTextObjectRecord extends TestCase { HSSFRichTextString str = new HSSFRichTextString(buff.toString()); TextObjectRecord obj = new TextObjectRecord(); - int frLength = ( str.numFormattingRuns() + 1 ) * 8; - obj.setFormattingRunLength( (short) frLength ); - obj.setTextLength( (short) str.length() ); - obj.setStr( str ); + obj.setStr(str); byte [] data = obj.serialize(); RecordInputStream is = new RecordInputStream(new ByteArrayInputStream(data)); @@ -120,30 +142,12 @@ public final class TestTextObjectRecord extends TestCase { HSSFRichTextString str = new HSSFRichTextString(text); TextObjectRecord obj = new TextObjectRecord(); - int frLength = ( str.numFormattingRuns() + 1 ) * 8; - obj.setFormattingRunLength( (short) frLength ); - obj.setTextLength( (short) str.length() ); - obj.setReserved1(true); - obj.setReserved2((short)2); - obj.setReserved3((short)3); - obj.setReserved4((short)4); - obj.setReserved5((short)5); - obj.setReserved6((short)6); - obj.setReserved7((short)7); obj.setStr( str ); TextObjectRecord cloned = (TextObjectRecord)obj.clone(); - assertEquals(obj.getReserved2(), cloned.getReserved2()); - assertEquals(obj.getReserved3(), cloned.getReserved3()); - assertEquals(obj.getReserved4(), cloned.getReserved4()); - assertEquals(obj.getReserved5(), cloned.getReserved5()); - assertEquals(obj.getReserved6(), cloned.getReserved6()); - assertEquals(obj.getReserved7(), cloned.getReserved7()); assertEquals(obj.getRecordSize(), cloned.getRecordSize()); - assertEquals(obj.getOptions(), cloned.getOptions()); assertEquals(obj.getHorizontalTextAlignment(), cloned.getHorizontalTextAlignment()); - assertEquals(obj.getFormattingRunLength(), cloned.getFormattingRunLength()); assertEquals(obj.getStr().getString(), cloned.getStr().getString()); //finally check that the serialized data is the same @@ -151,4 +155,47 @@ public final class TestTextObjectRecord extends TestCase { byte[] cln = cloned.serialize(); assertTrue(Arrays.equals(src, cln)); } + + /** similar to {@link #simpleData} but with link formula at end of TXO rec*/ + private static final byte[] linkData = HexRead.readFromString( + "B6 01 " + // TextObjectRecord.sid + "1E 00 " + // size 18 + "44 02 02 00 00 00 00 00" + + "00 00 " + + "02 00 " + // strLen 2 + "10 00 " + // 16 bytes for 2 format runs + "00 00 00 00 " + + + "05 00 " + // formula size + "D4 F0 8A 03 " + // unknownInt + "24 01 00 13 C0 " + //tRef(T2) + "13 " + // ?? + + "3C 00 " + // ContinueRecord.sid + "05 00 " + // size 5 + "01 " + // unicode uncompressed + "41 00 42 00 " + // 'AB' + "3C 00 " + // ContinueRecord.sid + "10 00 " + // size 16 + "00 00 18 00 00 00 00 00 " + + "02 00 00 00 00 00 00 00 " + ); + + + public void testLinkFormula() { + RecordInputStream is = new RecordInputStream(new ByteArrayInputStream(linkData)); + is.nextRecord(); + TextObjectRecord rec = new TextObjectRecord(is); + + Ptg ptg = rec.getLinkRefPtg(); + assertNotNull(ptg); + assertEquals(RefPtg.class, ptg.getClass()); + RefPtg rptg = (RefPtg) ptg; + assertEquals("T2", rptg.toFormulaString()); + + byte [] data2 = rec.serialize(); + assertEquals(linkData.length, data2.length); + assertTrue(Arrays.equals(linkData, data2)); + } + } diff --git a/src/testcases/org/apache/poi/hssf/record/TestTextRecord.java b/src/testcases/org/apache/poi/hssf/record/TestTextRecord.java index 40e98dff93..8d416050f7 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestTextRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestTextRecord.java @@ -27,7 +27,7 @@ import junit.framework.TestCase; * * @author Glen Stampoultzis (glens at apache.org) */ -public class TestTextRecord extends TestCase { +public final class TestTextRecord extends TestCase { byte[] data = new byte[] { (byte)0x02, // horiz align (byte)0x02, // vert align @@ -45,7 +45,7 @@ public class TestTextRecord extends TestCase { public void testLoad() { - TextRecord record = new TextRecord(new TestcaseRecordInputStream((short)0x1025, (short)data.length, data)); + TextRecord record = new TextRecord(TestcaseRecordInputStream.create(0x1025, data)); assertEquals( TextRecord.HORIZONTAL_ALIGNMENT_CENTER, record.getHorizontalAlignment()); assertEquals( TextRecord.VERTICAL_ALIGNMENT_CENTER, record.getVerticalAlignment()); assertEquals( TextRecord.DISPLAY_MODE_TRANSPARENT, record.getDisplayMode()); diff --git a/src/testcases/org/apache/poi/hssf/record/TestTickRecord.java b/src/testcases/org/apache/poi/hssf/record/TestTickRecord.java index 4f2d9efd36..b0b8ced7b0 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestTickRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestTickRecord.java @@ -40,7 +40,7 @@ public final class TestTickRecord extends TestCase { }; public void testLoad() { - TickRecord record = new TickRecord(new TestcaseRecordInputStream((short)0x101e, (short)data.length, data)); + TickRecord record = new TickRecord(TestcaseRecordInputStream.create(0x101e, data)); assertEquals( (byte)2, record.getMajorTickType()); assertEquals( (byte)0, record.getMinorTickType()); assertEquals( (byte)3, record.getLabelPosition()); diff --git a/src/testcases/org/apache/poi/hssf/record/TestUnicodeString.java b/src/testcases/org/apache/poi/hssf/record/TestUnicodeString.java index e449f167d5..8f3c65be49 100755 --- a/src/testcases/org/apache/poi/hssf/record/TestUnicodeString.java +++ b/src/testcases/org/apache/poi/hssf/record/TestUnicodeString.java @@ -1,4 +1,3 @@ - /* ==================================================================== Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with @@ -19,6 +18,8 @@ package org.apache.poi.hssf.record; +import org.apache.poi.util.HexRead; + import junit.framework.TestCase; /** @@ -26,18 +27,10 @@ import junit.framework.TestCase; * * @author Jason Height (jheight at apache.org) */ -public class TestUnicodeString - extends TestCase -{ +public final class TestUnicodeString extends TestCase { - public TestUnicodeString( String s ) - { - super( s ); - } - public void testSmallStringSize() - throws Exception - { + public void testSmallStringSize() { //Test a basic string UnicodeString s = makeUnicodeString("Test"); UnicodeString.UnicodeRecordStats stats = new UnicodeString.UnicodeRecordStats(); @@ -80,9 +73,7 @@ public class TestUnicodeString assertEquals(30, stats.recordSize); } - public void testPerfectStringSize() - throws Exception - { + public void testPerfectStringSize() { //Test a basic string UnicodeString s = makeUnicodeString(SSTRecord.MAX_RECORD_SIZE-2-1); UnicodeString.UnicodeRecordStats stats = new UnicodeString.UnicodeRecordStats(); @@ -99,9 +90,7 @@ public class TestUnicodeString assertEquals(SSTRecord.MAX_RECORD_SIZE-1, stats.recordSize); } - public void testPerfectRichStringSize() - throws Exception - { + public void testPerfectRichStringSize() { //Test a rich text string UnicodeString s = makeUnicodeString(SSTRecord.MAX_RECORD_SIZE-2-1-8-2); s.addFormatRun(new UnicodeString.FormatRun((short)1,(short)0)); @@ -123,7 +112,7 @@ public class TestUnicodeString assertEquals(SSTRecord.MAX_RECORD_SIZE-1, stats.recordSize); } - public void testContinuedStringSize() throws Exception { + public void testContinuedStringSize() { //Test a basic string UnicodeString s = makeUnicodeString(SSTRecord.MAX_RECORD_SIZE-2-1+20); UnicodeString.UnicodeRecordStats stats = new UnicodeString.UnicodeRecordStats(); @@ -132,7 +121,7 @@ public class TestUnicodeString } /** Tests that a string size calculation that fits neatly in two records, the second being a continue*/ - public void testPerfectContinuedStringSize() throws Exception { + public void testPerfectContinuedStringSize() { //Test a basic string int strSize = SSTRecord.MAX_RECORD_SIZE*2; //String overhead @@ -150,19 +139,18 @@ public class TestUnicodeString - private UnicodeString makeUnicodeString( String s ) + private static UnicodeString makeUnicodeString( String s ) { UnicodeString st = new UnicodeString(s); st.setOptionFlags((byte)0); return st; } - private UnicodeString makeUnicodeString( int numChars) { + private static UnicodeString makeUnicodeString( int numChars) { StringBuffer b = new StringBuffer(numChars); for (int i=0;idata are assumed to be record identifier and length. The supplied + * data can contain multiple records (sequentially encoded in the same way) + */ + public static RecordInputStream create(byte[] data) { + InputStream is = new ByteArrayInputStream(data); + RecordInputStream result = new RecordInputStream(is); + result.nextRecord(); + return result; + } + /** * Convenience constructor */ - public TestcaseRecordInputStream(int sid, byte[] data) - { - super(new ByteArrayInputStream(mergeDataAndSid((short)sid, (short)data.length, data))); - nextRecord(); - } - public TestcaseRecordInputStream(short sid, short length, byte[] data) - { - super(new ByteArrayInputStream(mergeDataAndSid(sid, length, data))); - nextRecord(); - } +// public TestcaseRecordInputStream(int sid, byte[] data) +// { +// super(new ByteArrayInputStream(mergeDataAndSid(sid, data.length, data))); +// nextRecord(); +// } +// public TestcaseRecordInputStream(short sid, short length, byte[] data) +// { +// super(new ByteArrayInputStream(mergeDataAndSid(sid, length, data))); +// nextRecord(); +// } - public static byte[] mergeDataAndSid(short sid, short length, byte[] data) { + public static byte[] mergeDataAndSid(int sid, int length, byte[] data) { byte[] result = new byte[data.length + 4]; - LittleEndian.putShort(result, 0, sid); - LittleEndian.putShort(result, 2, length); + LittleEndian.putUShort(result, 0, sid); + LittleEndian.putUShort(result, 2, length); System.arraycopy(data, 0, result, 4, data.length); return result; } diff --git a/src/testcases/org/apache/poi/hssf/record/constant/TestConstantValueParser.java b/src/testcases/org/apache/poi/hssf/record/constant/TestConstantValueParser.java index 52c6f679d7..17a0901040 100644 --- a/src/testcases/org/apache/poi/hssf/record/constant/TestConstantValueParser.java +++ b/src/testcases/org/apache/poi/hssf/record/constant/TestConstantValueParser.java @@ -25,6 +25,7 @@ import org.apache.poi.hssf.record.RecordInputStream; import org.apache.poi.hssf.record.TestcaseRecordInputStream; import org.apache.poi.hssf.record.UnicodeString; import org.apache.poi.hssf.usermodel.HSSFErrorConstants; +import org.apache.poi.util.HexRead; /** * * @author Josh Micich @@ -37,13 +38,12 @@ public final class TestConstantValueParser extends TestCase { new UnicodeString("Sample text"), ErrorConstant.valueOf(HSSFErrorConstants.ERROR_DIV_0), }; - private static final byte[] SAMPLE_ENCODING = { - 4, 1, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, -102, -103, -103, -103, -103, -103, -15, 63, - 2, 11, 0, 0, 83, 97, 109, 112, 108, 101, 32, 116, 101, 120, 116, - 16, 7, 0, 0, 0, 0, 0, 0, 0, - }; + private static final byte[] SAMPLE_ENCODING = HexRead.readFromString( + "04 01 00 00 00 00 00 00 00 " + + "00 00 00 00 00 00 00 00 00 " + + "01 9A 99 99 99 99 99 F1 3F " + + "02 0B 00 00 53 61 6D 70 6C 65 20 74 65 78 74 " + + "10 07 00 00 00 00 00 00 00"); public void testGetEncodedSize() { int actual = ConstantValueParser.getEncodedSize(SAMPLE_VALUES); @@ -59,7 +59,7 @@ public final class TestConstantValueParser extends TestCase { } } public void testDecode() { - RecordInputStream in = new TestcaseRecordInputStream(0x0001, SAMPLE_ENCODING); + RecordInputStream in = TestcaseRecordInputStream.createWithFakeSid(SAMPLE_ENCODING); Object[] values = ConstantValueParser.parse(in, 4); for (int i = 0; i < values.length; i++) { diff --git a/src/testcases/org/apache/poi/hssf/record/formula/TestArrayPtg.java b/src/testcases/org/apache/poi/hssf/record/formula/TestArrayPtg.java index df2c1f77bd..8d2fe631d2 100644 --- a/src/testcases/org/apache/poi/hssf/record/formula/TestArrayPtg.java +++ b/src/testcases/org/apache/poi/hssf/record/formula/TestArrayPtg.java @@ -54,9 +54,9 @@ public final class TestArrayPtg extends TestCase { */ public void testReadWriteTokenValueBytes() { - ArrayPtg ptg = new ArrayPtg(new TestcaseRecordInputStream(ArrayPtg.sid, ENCODED_PTG_DATA)); + ArrayPtg ptg = new ArrayPtg(TestcaseRecordInputStream.createWithFakeSid(ENCODED_PTG_DATA)); - ptg.readTokenValues(new TestcaseRecordInputStream(0, ENCODED_CONSTANT_DATA)); + ptg.readTokenValues(TestcaseRecordInputStream.createWithFakeSid(ENCODED_CONSTANT_DATA)); assertEquals(3, ptg.getColumnCount()); assertEquals(2, ptg.getRowCount()); Object[][] values = ptg.getTokenArrayValues(); @@ -82,8 +82,8 @@ public final class TestArrayPtg extends TestCase { * Excel stores array elements column by column. This test makes sure POI does the same. */ public void testElementOrdering() { - ArrayPtg ptg = new ArrayPtg(new TestcaseRecordInputStream(ArrayPtg.sid, ENCODED_PTG_DATA)); - ptg.readTokenValues(new TestcaseRecordInputStream(0, ENCODED_CONSTANT_DATA)); + ArrayPtg ptg = new ArrayPtg(TestcaseRecordInputStream.createWithFakeSid(ENCODED_PTG_DATA)); + ptg.readTokenValues(TestcaseRecordInputStream.createWithFakeSid(ENCODED_CONSTANT_DATA)); assertEquals(3, ptg.getColumnCount()); assertEquals(2, ptg.getRowCount()); @@ -113,9 +113,9 @@ public final class TestArrayPtg extends TestCase { } public void testToFormulaString() { - ArrayPtg ptg = new ArrayPtg(new TestcaseRecordInputStream(ArrayPtg.sid, ENCODED_PTG_DATA)); + ArrayPtg ptg = new ArrayPtg(TestcaseRecordInputStream.createWithFakeSid(ENCODED_PTG_DATA)); - ptg.readTokenValues(new TestcaseRecordInputStream(0, ENCODED_CONSTANT_DATA)); + ptg.readTokenValues(TestcaseRecordInputStream.createWithFakeSid(ENCODED_CONSTANT_DATA)); String actualFormula; try { @@ -146,7 +146,7 @@ public final class TestArrayPtg extends TestCase { // Force encoded operand class for tArray fullData[0] = (byte) (ArrayPtg.sid + operandClass); - RecordInputStream in = new TestcaseRecordInputStream(ArrayPtg.sid, fullData); + RecordInputStream in = TestcaseRecordInputStream.createWithFakeSid(fullData); Ptg[] ptgs = Ptg.readTokens(ENCODED_PTG_DATA.length, in); assertEquals(1, ptgs.length); diff --git a/src/testcases/org/apache/poi/hssf/record/formula/TestFuncPtg.java b/src/testcases/org/apache/poi/hssf/record/formula/TestFuncPtg.java index 89997b59d1..827bea8332 100644 --- a/src/testcases/org/apache/poi/hssf/record/formula/TestFuncPtg.java +++ b/src/testcases/org/apache/poi/hssf/record/formula/TestFuncPtg.java @@ -34,7 +34,7 @@ public final class TestFuncPtg extends TestCase { 0, }; - FuncPtg ptg = new FuncPtg( new TestcaseRecordInputStream((short)0, (short)fakeData.length, fakeData) ); + FuncPtg ptg = new FuncPtg(TestcaseRecordInputStream.createWithFakeSid(fakeData) ); 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() ); diff --git a/src/testcases/org/apache/poi/hssf/record/formula/TestReferencePtg.java b/src/testcases/org/apache/poi/hssf/record/formula/TestReferencePtg.java index b50bb76b45..6be329ed5a 100644 --- a/src/testcases/org/apache/poi/hssf/record/formula/TestReferencePtg.java +++ b/src/testcases/org/apache/poi/hssf/record/formula/TestReferencePtg.java @@ -18,12 +18,12 @@ package org.apache.poi.hssf.record.formula; import java.util.Arrays; -import java.util.Stack; import junit.framework.AssertionFailedError; import junit.framework.TestCase; import org.apache.poi.hssf.HSSFTestDataSamples; +import org.apache.poi.hssf.record.RecordInputStream; import org.apache.poi.hssf.record.TestcaseRecordInputStream; import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.poi.hssf.usermodel.HSSFWorkbook; @@ -94,10 +94,10 @@ public final class TestReferencePtg extends TestCase { 0x2C, 33, 44, 55, 66, }; public void testReadWrite_tRefN_bug45091() { - TestcaseRecordInputStream in = new TestcaseRecordInputStream(-1, tRefN_data); - Stack ptgs = Ptg.createParsedExpressionTokens((short)tRefN_data.length, in); + RecordInputStream in = TestcaseRecordInputStream.createWithFakeSid(tRefN_data); + Ptg[] ptgs = Ptg.readTokens(tRefN_data.length, in); byte[] outData = new byte[5]; - Ptg.serializePtgStack(ptgs, outData, 0); + Ptg.serializePtgs(ptgs, outData, 0); if (outData[0] == 0x24) { throw new AssertionFailedError("Identified bug 45091"); } -- 2.39.5