]> source.dussan.org Git - poi.git/commitdiff
Merged revisions 703100,703197,703302,703596,703620,703645,703651,706540 via svnmerge...
authorJosh Micich <josh@apache.org>
Sat, 25 Oct 2008 01:47:25 +0000 (01:47 +0000)
committerJosh Micich <josh@apache.org>
Sat, 25 Oct 2008 01:47:25 +0000 (01:47 +0000)
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 &lt; 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

87 files changed:
src/documentation/content/xdocs/changes.xml
src/documentation/content/xdocs/index.xml
src/documentation/content/xdocs/status.xml
src/java/org/apache/poi/hssf/dev/BiffViewer.java
src/java/org/apache/poi/hssf/model/TextboxShape.java
src/java/org/apache/poi/hssf/record/ContinueRecord.java
src/java/org/apache/poi/hssf/record/CustomField.java [deleted file]
src/java/org/apache/poi/hssf/record/ExternalNameRecord.java
src/java/org/apache/poi/hssf/record/LinkedDataFormulaField.java
src/java/org/apache/poi/hssf/record/LinkedDataRecord.java
src/java/org/apache/poi/hssf/record/RecordFactory.java
src/java/org/apache/poi/hssf/record/RecordInputStream.java
src/java/org/apache/poi/hssf/record/TextObjectBaseRecord.java [deleted file]
src/java/org/apache/poi/hssf/record/TextObjectRecord.java
src/java/org/apache/poi/hssf/record/formula/Ptg.java
src/java/org/apache/poi/hssf/usermodel/HSSFComment.java
src/java/org/apache/poi/hssf/usermodel/HSSFRichTextString.java
src/scratchpad/src/org/apache/poi/hssf/usermodel/HSSFChart.java
src/testcases/org/apache/poi/hssf/eventmodel/TestEventRecordFactory.java
src/testcases/org/apache/poi/hssf/record/AllRecordTests.java
src/testcases/org/apache/poi/hssf/record/TestAreaFormatRecord.java
src/testcases/org/apache/poi/hssf/record/TestAreaRecord.java
src/testcases/org/apache/poi/hssf/record/TestAxisLineFormatRecord.java
src/testcases/org/apache/poi/hssf/record/TestAxisOptionsRecord.java
src/testcases/org/apache/poi/hssf/record/TestAxisParentRecord.java
src/testcases/org/apache/poi/hssf/record/TestAxisRecord.java
src/testcases/org/apache/poi/hssf/record/TestAxisUsedRecord.java
src/testcases/org/apache/poi/hssf/record/TestBarRecord.java
src/testcases/org/apache/poi/hssf/record/TestBoundSheetRecord.java
src/testcases/org/apache/poi/hssf/record/TestCFHeaderRecord.java
src/testcases/org/apache/poi/hssf/record/TestCFRuleRecord.java
src/testcases/org/apache/poi/hssf/record/TestCategorySeriesAxisRecord.java
src/testcases/org/apache/poi/hssf/record/TestChartRecord.java
src/testcases/org/apache/poi/hssf/record/TestCommonObjectDataSubRecord.java
src/testcases/org/apache/poi/hssf/record/TestDatRecord.java
src/testcases/org/apache/poi/hssf/record/TestDataFormatRecord.java
src/testcases/org/apache/poi/hssf/record/TestDefaultDataLabelTextPropertiesRecord.java
src/testcases/org/apache/poi/hssf/record/TestEmbeddedObjectRefSubRecord.java
src/testcases/org/apache/poi/hssf/record/TestEndSubRecord.java
src/testcases/org/apache/poi/hssf/record/TestExtendedFormatRecord.java
src/testcases/org/apache/poi/hssf/record/TestExternalNameRecord.java
src/testcases/org/apache/poi/hssf/record/TestFontBasisRecord.java
src/testcases/org/apache/poi/hssf/record/TestFontIndexRecord.java
src/testcases/org/apache/poi/hssf/record/TestFontRecord.java
src/testcases/org/apache/poi/hssf/record/TestFormulaRecord.java
src/testcases/org/apache/poi/hssf/record/TestFrameRecord.java
src/testcases/org/apache/poi/hssf/record/TestHyperlinkRecord.java
src/testcases/org/apache/poi/hssf/record/TestLegendRecord.java
src/testcases/org/apache/poi/hssf/record/TestLineFormatRecord.java
src/testcases/org/apache/poi/hssf/record/TestLinkedDataRecord.java
src/testcases/org/apache/poi/hssf/record/TestNameRecord.java
src/testcases/org/apache/poi/hssf/record/TestNoteRecord.java
src/testcases/org/apache/poi/hssf/record/TestNoteStructureSubRecord.java
src/testcases/org/apache/poi/hssf/record/TestNumberFormatIndexRecord.java
src/testcases/org/apache/poi/hssf/record/TestObjRecord.java
src/testcases/org/apache/poi/hssf/record/TestObjectLinkRecord.java
src/testcases/org/apache/poi/hssf/record/TestPaneRecord.java
src/testcases/org/apache/poi/hssf/record/TestPlotAreaRecord.java
src/testcases/org/apache/poi/hssf/record/TestPlotGrowthRecord.java
src/testcases/org/apache/poi/hssf/record/TestRecordFactory.java
src/testcases/org/apache/poi/hssf/record/TestRecordInputStream.java [new file with mode: 0644]
src/testcases/org/apache/poi/hssf/record/TestSCLRecord.java
src/testcases/org/apache/poi/hssf/record/TestSSTDeserializer.java
src/testcases/org/apache/poi/hssf/record/TestSeriesChartGroupIndexRecord.java
src/testcases/org/apache/poi/hssf/record/TestSeriesIndexRecord.java
src/testcases/org/apache/poi/hssf/record/TestSeriesLabelsRecord.java
src/testcases/org/apache/poi/hssf/record/TestSeriesListRecord.java
src/testcases/org/apache/poi/hssf/record/TestSeriesRecord.java
src/testcases/org/apache/poi/hssf/record/TestSeriesTextRecord.java
src/testcases/org/apache/poi/hssf/record/TestSeriesToChartGroupRecord.java
src/testcases/org/apache/poi/hssf/record/TestSharedFormulaRecord.java
src/testcases/org/apache/poi/hssf/record/TestSheetPropertiesRecord.java
src/testcases/org/apache/poi/hssf/record/TestStringRecord.java
src/testcases/org/apache/poi/hssf/record/TestSupBookRecord.java
src/testcases/org/apache/poi/hssf/record/TestTableRecord.java
src/testcases/org/apache/poi/hssf/record/TestTextObjectBaseRecord.java
src/testcases/org/apache/poi/hssf/record/TestTextObjectRecord.java
src/testcases/org/apache/poi/hssf/record/TestTextRecord.java
src/testcases/org/apache/poi/hssf/record/TestTickRecord.java
src/testcases/org/apache/poi/hssf/record/TestUnicodeString.java
src/testcases/org/apache/poi/hssf/record/TestUnitsRecord.java
src/testcases/org/apache/poi/hssf/record/TestValueRangeRecord.java
src/testcases/org/apache/poi/hssf/record/TestcaseRecordInputStream.java
src/testcases/org/apache/poi/hssf/record/constant/TestConstantValueParser.java
src/testcases/org/apache/poi/hssf/record/formula/TestArrayPtg.java
src/testcases/org/apache/poi/hssf/record/formula/TestFuncPtg.java
src/testcases/org/apache/poi/hssf/record/formula/TestReferencePtg.java

index 7fa34db87849b08ddffc2819c0658e1f45e13849..9dbd18ead202b2c25847e71b3d8f447b223d60bf 100644 (file)
            <action dev="POI-DEVELOPERS" type="add">Created a common interface for handling PowerPoint files, irrespective of if they are .ppt or .pptx</action>
            <action dev="POI-DEVELOPERS" type="add">Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx</action>
         </release>
-        <release version="3.2-alpha1" date="2008-??-??">
+        <release version="3.5-beta4" date="2008-??-??">
+           <action dev="POI-DEVELOPERS" type="fix">YK: remove me. required to keep Forrest DTD compiler quiet</action>
+        </release>
+        <release version="3.2-FINAL" date="2008-10-19">
+           <action dev="POI-DEVELOPERS" type="fix">45866 - allowed for change of unicode compression across Continue records</action>
+           <action dev="POI-DEVELOPERS" type="fix">45964 - support for link formulas in Text Objects</action>
            <action dev="POI-DEVELOPERS" type="fix">43354 - support for evalating formulas with missing args</action>
            <action dev="POI-DEVELOPERS" type="fix">45912 - fixed ArrayIndexOutOfBoundsException in EmbeddedObjectRefSubRecord</action>
            <action dev="POI-DEVELOPERS" type="fix">45889 - fixed ArrayIndexOutOfBoundsException when constructing HSLF Table with a single row </action>
index cfbcafc2dbec70a2462691d3bf2be5d4b037a3a2..6deed531a2a4204b6acaa31221ad03cca51950b7 100644 (file)
        People interested should also follow the
        <link href="mailinglists.html">dev list</link> to track progress.</p>
     </section>
-    <section><title>POI 3.1-FINAL Released (2008-06-29)</title>
+    <section><title>POI 3.2-FINAL Released (2008-10-19)</title>
       <p>
-        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. 
        </p><p>  A full list of changes is available in
       <link href="./changes.html">the changelog</link>, and 
                <link href="http://www.apache.org/dyn/closer.cgi/poi/release/">download</link>
@@ -56,7 +56,7 @@
       </p>
       <p>
         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".
       </p>  
     </section>
 
index baead2a3581dd20040c149ede9b82c601d081ba6..ee52d97065a9d984ac4ea97fdea4c0480b855e1a 100644 (file)
            <action dev="POI-DEVELOPERS" type="add">Created a common interface for handling PowerPoint files, irrespective of if they are .ppt or .pptx</action>
            <action dev="POI-DEVELOPERS" type="add">Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx</action>
         </release>
-        <release version="3.2-alpha1" date="2008-??-??">
+        <release version="3.5-beta4" date="2008-??-??">
+           <action dev="POI-DEVELOPERS" type="fix">YK: remove me. required to keep Forrest DTD compiler quiet</action>
+        </release>
+        <release version="3.2-FINAL" date="2008-10-19">
+           <action dev="POI-DEVELOPERS" type="fix">45866 - allowed for change of unicode compression across Continue records</action>
+           <action dev="POI-DEVELOPERS" type="fix">45964 - support for link formulas in Text Objects</action>
            <action dev="POI-DEVELOPERS" type="fix">43354 - support for evalating formulas with missing args</action>
            <action dev="POI-DEVELOPERS" type="fix">45912 - fixed ArrayIndexOutOfBoundsException in EmbeddedObjectRefSubRecord</action>
            <action dev="POI-DEVELOPERS" type="fix">45889 - fixed ArrayIndexOutOfBoundsException when constructing HSLF Table with a single row </action>
index 15177d0d95ab5069926aa37b36c07c9ddc8c9996..6d2def084ea53a432208fa956f0d103baa1c6989 100644 (file)
 
 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<P>
-     *
-     * with 2 arguments where the second argument is "on" - run biffviewer<P>
-     *
-     * with hex dumps of records <P>
-     *
-     * 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
-     * <p>
-     * Define the system property <code>poi.deserialize.escher</code> 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<P>
+        *
+        * with 2 arguments where the second argument is "on" - run biffviewer<P>
+        *
+        * with hex dumps of records <P>
+        *
+        * 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
+        * <p>
+        * Define the system property <code>poi.deserialize.escher</code> 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);
+       }
 }
 
index b1d3370fbf0d5e94fa9b82e4717fbd646b800ed2..e74197711b24921a21ac7fb42b0efdd25cdab789 100644 (file)
@@ -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;
     }
index 435c45471231430f2f90d71fb395a6b119472c4f..e20c4633c3b8936022e43ef81af4b27cbc0aad9b 100644 (file)
@@ -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 <P>
+ * Title:        Continue Record(0x003C) - Helper class used primarily for SST Records <P>
  * Description:  handles overflow for prior record in the input
  *               stream; content is tailored to that prior record<P>
  * @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 (file)
index 474d3b2..0000000
+++ /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 <code>fillField()</code>
-     */
-    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);
-
-
-}
index d2135c085ee1e3a307229a29b8b5c9d50d6630e1..4d7f312bd5942f9d001a1b1f7b6fc0a85885e8b8 100755 (executable)
@@ -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);
        }
 
 
index 9e82adec6eea16cbcf9556c7c0ce133747fbf440..4a607c9e37d10feb53884013a82d11869cf11c5f 100644 (file)
@@ -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;
+       }
 }
index 46610ec2bc76383751421ab4068fa4401e703625..543418c35384afe3dd02aae002f1d8d9a38f3723 100644 (file)
@@ -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;
     }
 
index 864065de77cebf96d118e0fe35578f8ee78d1b58..7539e597da5a9742b27b56b960f7978f4a056829 100644 (file)
@@ -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;
index c23868c711d934bbb084edd7126a9216356d1f80..696f4fef7b5b8c8cbcf6c44df068551c47a6d542 100755 (executable)
@@ -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<length;i++) {
-      if ((remaining() == 0) && (isContinueNext())){
-        nextRecord();
-        int compressByte = readByte();
-        if(compressByte != 1) throw new IllegalArgumentException("compressByte in continue records must be 1 while reading unicode LE string");
-      }
-      char ch = (char)readShort();
-      buf.append(ch);
-    }
-    return buf.toString();
-  }
+       public String readString() {
+               int requestedLength = readUShort();
+               byte compressFlag = readByte();
+               return readStringCommon(requestedLength, compressFlag == 0);
+       }
+       /**
+        *  given a byte array of 16-bit unicode characters, compress to 8-bit and
+        *  return a string
+        *
+        * { 0x16, 0x00 } -0x16
+        *
+        * @param requestedLength 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 requestedLength) {
+               return readStringCommon(requestedLength, false);
+       }
 
-  public String readCompressedUnicode(int length) {
-    if ((length < 0) || ((remaining() < length) && !isContinueNext())) {
-            throw new IllegalArgumentException("Illegal length " + length);
-    }
+       public String readCompressedUnicode(int requestedLength) {
+               return readStringCommon(requestedLength, true);
+       }
 
-    StringBuffer buf = new StringBuffer(length);
-    for (int i=0;i<length;i++) {
-      if ((remaining() == 0) && (isContinueNext())) {
-          nextRecord();
-          int compressByte = readByte();
-          if(compressByte != 0) throw new IllegalArgumentException("compressByte in continue records must be 0 while reading compressed unicode");
-      }
-      byte b = readByte();
-      char ch = (char)(0x00FF & b); // avoid sex
-      buf.append(ch);
-    }
-    return buf.toString();
-  }
+       private String readStringCommon(int requestedLength, boolean pIsCompressedEncoding) {
+               // Sanity check to detect garbage string lengths
+               if (requestedLength < 0 || requestedLength > 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.
    * <i>Note:</i> Unicode strings differ from <b>normal</b> 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 (file)
index 59e0cd2..0000000
+++ /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.<p/>
- * 
- * @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);
-    }
-}
index 600aaf1542c6d63e74c20aa85ea4beef28d8e12e..6529dc93f8664902f403558b6d4b0a2956f9cc99 100644 (file)
@@ -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.<p/>
+ * 
+ * @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;
+       }
 }
index 4b952b65f747091d2cf7f7267ecbb2d35c7a6896..55fac1b0b0f402d20b24fef925c02824ad7d329c 100644 (file)
@@ -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;
 
 /**
  * <tt>Ptg</tt> 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 <tt>size</tt>) may be read if and <tt>ArrayPtg</tt>s 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 <tt>Ptg</tt>s 
         */
-       // 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 <b>not</b> 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) {
index 0c8a16e4202c3cfd53a529cadc3d8e8ea18491f9..3d28fc1e2550d8028d09b9a4fd9c26189b715210 100644 (file)
@@ -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);
     }
index ce5a40acbf3cc7d0edaab1c50232ef389bcc304f..9d57c99a4308c9c59393683b1868b6cd065509be 100644 (file)
@@ -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()
     {
index 3a7c5c20e0a555ba42e79d1db470b66d6f8c1ba2..3b1fd1e1e700ad54ca6afc31e9d4cec868bdb986 100644 (file)
@@ -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;
        }
index 88f620ca44eab4691587c7eb775c64eaa1995150..8825fed700d583bfc2adb3bc7adfaa2e3f003721 100644 (file)
@@ -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]));
index fb3270ae753105ed830cd85b6f9c4cbb24b23fb6..5fb6f4aa03a7ed7ff5e820a2c9b8d98e5e981667 100755 (executable)
@@ -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);
index de834be95eed8fbc06908d2fa7ac0495b24da110..fb852ba88c1322e3f8976553a67f0601fc4e6dec 100644 (file)
@@ -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());
index 2131e7319284e173e535e9c069e6b4d4d99ccf9d..f514feccbab73eab75e167e6af98e1c9b24f41eb 100644 (file)
@@ -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() );
index 2146a31cfb58cb23558d3f7eee80ebc6221a986b..4e9e29a6f709d38dba963c9fb8a66228debb8bea 100644 (file)
@@ -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() );
index 4d88e18a69552d4e62c3b6ac98783e9f5d0e4551..de51b48b0d0c3a79ba446862365414782a8e7ff2 100644 (file)
@@ -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());
index a9787a2e8b4584f87110f266ea14b76bdacb3efe..406b68fd60e968346094af04e3a78c4481c8e296 100644 (file)
@@ -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());
index 719e930d2545e0ec35d94b29b8f925fc6043bc64..21e41773ce4d5cf0f6da676b843b1fab82f44080 100644 (file)
@@ -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());
index 98812ddd6f8f8abf22f890a7790b03182559dd63..5f02d2874c00fe5f7d2e7a79c9856180f82afa5c 100644 (file)
@@ -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() );
index 1da17aae926e97b5d5c9e2f9f26c905d95601b54..80c729c21291b8d54002211b6f85c8b90b9b6c3f 100644 (file)
@@ -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());
index f973da37dbc682e3266365ed060cd6a6f000dedf..766e396473eac2558bcb0498954498b02e3c9db6 100644 (file)
@@ -69,7 +69,7 @@ public final class TestBoundSheetRecord extends TestCase {
                        // </str>
                };
        
-               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());
index ec291ffd49354d235a4e0c8d139cdc879831bb37..239f2092f714825d9efc0e7de2813c3ef1475a17 100644 (file)
@@ -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");
index 1eb052bec7aef725bf71716dd9862ff1edac1c86..80de9598091b2374c67eef4e481c6a52ea9212eb 100644 (file)
@@ -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);
index 415b302e87508480fccc288150644f54af2265d1..080918aa05fe0d4eff8f6ff56c1656026b235eb8 100644 (file)
@@ -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());
index 996fb1102b12d171aab12ff4685882ef255ff694..994b15b32cc51be7e7314139416007966a5660b9 100644 (file)
@@ -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());
index e68b5026d85b640a79b304c5254e05cfb06f2c1c..ad629c3f176563095fcf0a34be46a6f087944c0f 100644 (file)
@@ -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());
index 8efbe70ecbccf3b9a8663ac4c8a116943c73a3bb..408d80e56823c8d46e0a8bc443578cd9c4991541 100644 (file)
@@ -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() );
index 8de2f24dac549b165402ae69fe1dcce9018b7473..953f13ec08a83c81d00d3a19271a9fc613ecb590 100644 (file)
@@ -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());
index f96dca90bfdfe486e1e85adf440034bd5040ac33..8557359e8a57ea68217d477d332c8676b5af8afb 100644 (file)
@@ -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() );
index e09f9e34ab1ccc3e4501b7a216623c7cfeff2916..bf8da6fecebec9464053094794f2306de3fb4710 100644 (file)
@@ -127,7 +127,7 @@ public final class TestEmbeddedObjectRefSubRecord extends TestCase {
        }\r
 \r
        private static void confirmRead(byte[] data, int i) {\r
-               RecordInputStream in = new TestcaseRecordInputStream(EmbeddedObjectRefSubRecord.sid, (short)data.length, data);\r
+               RecordInputStream in = TestcaseRecordInputStream.create(EmbeddedObjectRefSubRecord.sid, data);\r
 \r
                EmbeddedObjectRefSubRecord rec = new EmbeddedObjectRefSubRecord(in);\r
                byte[] ser2 = rec.serialize();\r
index d809392420fc0e70425e28375292e3d459da3294..d16c22714900b3fa9466fea4089ea2f9c532a794 100644 (file)
@@ -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() );
     }
index 3faa69ed6a8d901024d01f9b2bcc51b1eb008d53..00d5c8c11136d3da513e7f979969ba752a7d322c 100644 (file)
@@ -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);
index e55876e6f6a6de416365cf7e55eb709ca6e3ceca..54c1f35b3bfb984f30ca1de2a3f50610b6b56d4a 100644 (file)
@@ -43,7 +43,7 @@ public final class TestExternalNameRecord extends TestCase {
        };\r
        \r
        private static ExternalNameRecord createSimpleENR(byte[] data) {\r
-               return new ExternalNameRecord(new TestcaseRecordInputStream((short)0x0023, data));\r
+               return new ExternalNameRecord(TestcaseRecordInputStream.create(0x0023, data));\r
        }\r
        public void testBasicDeserializeReserialize() {\r
                \r
index acd5a361ad454f211d77c8cdc84ced7c3b2735a7..65c19f091615c53b6f31118640948381d4c2fce3 100644 (file)
@@ -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());
index 49cfe4d65019b256f4290c270efb3d2ab71af23e..c962e0daee509a05d91decccb02769c9362e0bee 100644 (file)
@@ -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() );
index 19449c2f56bbecf4de4909fabb18b19038b822eb..5a8855b66ea144bec5c1d9121592f0719dc3d097 100644 (file)
@@ -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));
         
index 4696539f2385057b0569c13cf3b2d3efcb8f5b89..703664443ccb29eb26d22bb4bd3608bd47d1e790 100644 (file)
@@ -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();
index f35a04b48836df92a9e4bc3d5f15b9d90b727b30..23f1593efbd846947f9a2db37b950e1466f6e3e7 100644 (file)
@@ -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() );
index 3d2ca406ce4b9dd7b5e1f3e67525688f3d4883e2..1919a4b038f11343033b63b5f60410e3f97779d7 100644 (file)
@@ -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()));
index aaee94fe8215cd79505f539d8ad5562afa442c38..6bae58f2a493ad49ded20715c6d35b3fc28bdf39 100644 (file)
 
 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]);
+       }
 }
index f4e833dd7c11d6a8646fc5a0f9456fba1c482b87..f3b4c3d32689360e5248ca4eb153e6ff6b122022 100644 (file)
@@ -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());
index 641f1e8c54a50a1843187ca2c1fc43df17b49c1c..adca938147d37106b808591012a3e50c1ecf3776 100644 (file)
@@ -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();
index 115e06f65efdcb43b3a2466817fc19a895c65018..cbb4b048a0e7a88e34108711310f0244c8cad5f0 100755 (executable)
@@ -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 );
-
     }
-
 }
 
 
index 063f34e0c7155f32292ffd2eb5446aca7b62e73b..e31601be576d08e5aea2ad4b64c487212dc97249 100644 (file)
@@ -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());
index 014a5be2baec66f14f409155ff2b25a068309e48..fd2ae059b70935cc1aaf184646c7a9c537d7943b 100644 (file)
@@ -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());
index 1ee74f2cc70b49dba0506ba0d38cfc828fb70719..570d71ec62682a6ed52c99f678cafe0be1fffca4 100644 (file)
@@ -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() );
index e8a6596e556c1ae0905951d9f529497f113888b8..df2679780793fcec5998f635fea481f3d86de1ae 100644 (file)
@@ -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");
index e9d536df0ac656f633713ad603729eb4a45bc170..9d8168d4b51060c5c7237c7d43455b53ccb44b0d 100644 (file)
@@ -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());
index aa8004791302ad485b7008b9ff771c56214d4037..93d1a1f987b52dc905d166b2ed113c31b97a0a7d 100644 (file)
@@ -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());
index aa5941a49a64d29e291e0677cdebd72cdd07bf28..631d6895d9e4a88eba9d42e02aafa3cc4626e89b 100644 (file)
@@ -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() );
     }
index 2897d8c33252e47e7bf54f2684fb99f3dab50b32..c5896d2b380b672d064bb709b89955614e5c4a25 100644 (file)
@@ -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());
 
index 6927c6820ab5cc33041b4f61c90fa85745c8f5c9..13cea4189c79307bd42e681eb7111bca9fb46415 100644 (file)
@@ -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 (file)
index 0000000..2b236e1
--- /dev/null
@@ -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<br/>
+        * 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);
+       }
+}
index 9b98dab1f658231ab091685f4c606e94d0f60055..335b6605d73df7729e9980feed73aed6344dcaaf 100644 (file)
@@ -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());
 
index 1cb1252b45597b6dbe88f3ac1a8a710e0326e33b..b16d2f83c74e035f8cc4d04fa6d4c197243a0464 100644 (file)
@@ -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 );
index 1f30f26ec0c8bf069d751e94f3d24b9980af55a4..cd09e061e6f5e5ba6491640b0ff711eac0649090 100644 (file)
@@ -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() );
index b971128c998a16a8109a22c2627609d2a63bce5d..9ba9b0ad9e972a60d222fc64d81d84938f4965d9 100644 (file)
@@ -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() );
index 265583655da475341c90908b22f0a5bf42eccc2d..c1602dd2a3d9375a4fd2f545290a43c6865b9236 100644 (file)
@@ -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() );
index 027b6c3867d49c37835def05d6e705f5b93d9a34..1669dc4dfc25ca53539dede328bfdb91c877d42a 100644 (file)
@@ -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);
index 69232754fb8e857ce7d58cc7f697db01d7e592c7..2e7cfa6fee1f91c15a01c2cbcf7f6a8fa1b15d92 100644 (file)
@@ -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());
index 08e4189afbc6f52ebdbf5051fcd204fddc720e87..a016e60e91e4339d69ebf3a4fd4799f32130672c 100644 (file)
@@ -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());
index 4f20e0e696ab6ee16ec685662c7b4075fb1ae84b..8112c54b70d7d6320fe01a6f6054ab1f7a16f757 100644 (file)
@@ -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() );
index 7a13cfe5fda3c25db6380351308c607a5d2ad06d..8a52211a6a540fc00a420315c1e6585cb43f22a2 100644 (file)
@@ -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);
                
index 932ff6eace66206e19131f8065e6c76b1cee093a..aa870a3374bac05137a49983ce1cd10cdb54c638 100644 (file)
@@ -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() );
index 7f06c54ab3210b0d1ed397681d9e05678dce5592..14b708cdc8d6a5d7ceeb5b2f1b186d4fad06a4e2 100644 (file)
@@ -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() );
index 5506f6abdf67dde521d7ac864c7cf1f38e12cdd4..d7725b8ee00bc1ef2b934facfcbab7391899a92c 100644 (file)
@@ -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
index 19c91bbacb014bd2fe4fc5903cab1da98d9291c2..3a2ada6e78ec745ec1faaedd0518a55f6c73ae3e 100644 (file)
@@ -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());
index b9d80dbad50fdf10c67b7aca345e4510f87ce4f6..b8f9e86468169cc47b7ef4b53e5b2dba05dcbab5 100644 (file)
 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]);
     }
 }
index 91458e9ddb720426c16c04063590d5468cd6f314..b7d45e28b0ef6df0ec798e4370495c4365ffc991 100644 (file)
@@ -22,7 +22,11 @@ import java.util.Arrays;
 \r
 import junit.framework.TestCase;\r
 \r
+import org.apache.poi.hssf.record.formula.Ptg;\r
+import org.apache.poi.hssf.record.formula.RefPtg;\r
 import org.apache.poi.hssf.usermodel.HSSFRichTextString;\r
+import org.apache.poi.util.HexRead;\r
+import org.apache.poi.util.LittleEndian;\r
 \r
 /**\r
  * Tests that serialization and deserialization of the TextObjectRecord .\r
@@ -32,17 +36,23 @@ import org.apache.poi.hssf.usermodel.HSSFRichTextString;
  */\r
 public final class TestTextObjectRecord extends TestCase {\r
 \r
-    byte[] data = {(byte)0xB6, 0x01, 0x12, 0x00, 0x12, 0x02, 0x00, 0x00, 0x00, 0x00,\r
-                   0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,\r
-                   0x00, 0x3C, 0x00, 0x1B, 0x00, 0x01, 0x48, 0x00, 0x65, 0x00, 0x6C,\r
-                   0x00, 0x6C, 0x00, 0x6F, 0x00, 0x2C, 0x00, 0x20, 0x00, 0x57, 0x00,\r
-                   0x6F, 0x00, 0x72, 0x00, 0x6C, 0x00, 0x64, 0x00, 0x21, 0x00, 0x3C,\r
-                   0x00, 0x08, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };\r
+    private static final byte[] simpleData = HexRead.readFromString(\r
+       "B6 01 12 00 " +\r
+       "12 02 00 00 00 00 00 00" +\r
+       "00 00 0D 00 08 00      00 00" +\r
+       "00 00 " +\r
+       "3C 00 1B 00 " +\r
+       "01 48 00 65 00 6C 00 6C 00 6F 00 " +\r
+       "2C 00 20 00 57 00 6F 00 72 00 6C " +\r
+       "00 64 00 21 00 " + \r
+       "3C 00 08 " +\r
+       "00 0D 00 00 00 00 00 00 00"\r
+    );\r
 \r
 \r
     public void testRead() {\r
 \r
-        RecordInputStream is = new RecordInputStream(new ByteArrayInputStream(data));\r
+        RecordInputStream is = new RecordInputStream(new ByteArrayInputStream(simpleData));\r
         is.nextRecord();\r
         TextObjectRecord record = new TextObjectRecord(is);\r
 \r
@@ -50,36 +60,51 @@ public final class TestTextObjectRecord extends TestCase {
         assertEquals(TextObjectRecord.HORIZONTAL_TEXT_ALIGNMENT_LEFT_ALIGNED, record.getHorizontalTextAlignment());\r
         assertEquals(TextObjectRecord.VERTICAL_TEXT_ALIGNMENT_TOP, record.getVerticalTextAlignment());\r
         assertEquals(TextObjectRecord.TEXT_ORIENTATION_NONE, record.getTextOrientation());\r
-        assertEquals(0, record.getReserved7());\r
         assertEquals("Hello, World!", record.getStr().getString());\r
-\r
     }\r
 \r
-    public void testWrite()\r
-    {\r
+    public void testWrite() {\r
         HSSFRichTextString str = new HSSFRichTextString("Hello, World!");\r
 \r
         TextObjectRecord record = new TextObjectRecord();\r
-        int frLength = ( str.numFormattingRuns() + 1 ) * 8;\r
-        record.setFormattingRunLength( (short) frLength );\r
-        record.setTextLength( (short) str.length() );\r
-        record.setStr( str );\r
+        record.setStr(str);\r
         record.setHorizontalTextAlignment( TextObjectRecord.HORIZONTAL_TEXT_ALIGNMENT_LEFT_ALIGNED );\r
         record.setVerticalTextAlignment( TextObjectRecord.VERTICAL_TEXT_ALIGNMENT_TOP );\r
         record.setTextLocked( true );\r
         record.setTextOrientation( TextObjectRecord.TEXT_ORIENTATION_NONE );\r
-        record.setReserved7( 0 );\r
 \r
         byte [] ser = record.serialize();\r
-        //assertEquals(ser.length , data.length);\r
+        assertEquals(ser.length , simpleData.length);\r
 \r
-        //assertTrue(Arrays.equals(data, ser));\r
+        assertTrue(Arrays.equals(simpleData, ser));\r
 \r
         //read again\r
-        RecordInputStream is = new RecordInputStream(new ByteArrayInputStream(data));\r
+        RecordInputStream is = new RecordInputStream(new ByteArrayInputStream(simpleData));\r
         is.nextRecord();\r
         record = new TextObjectRecord(is);\r
+    }\r
+\r
+    /**\r
+     * Zero {@link ContinueRecord}s follow a {@link TextObjectRecord} if the text is empty\r
+     */\r
+    public void testWriteEmpty() {\r
+        HSSFRichTextString str = new HSSFRichTextString("");\r
+\r
+        TextObjectRecord record = new TextObjectRecord();\r
+        record.setStr(str);\r
 \r
+        byte [] ser = record.serialize();\r
+        \r
+        int formatDataLen = LittleEndian.getUShort(ser, 16);\r
+        assertEquals("formatDataLength", 0, formatDataLen);\r
+\r
+        assertEquals(22, ser.length); // just the TXO record\r
+        \r
+        //read again\r
+        RecordInputStream is = new RecordInputStream(new ByteArrayInputStream(ser));\r
+        is.nextRecord();\r
+        record = new TextObjectRecord(is);\r
+        assertEquals(0, record.getStr().length());\r
     }\r
 \r
     /**\r
@@ -95,10 +120,7 @@ public final class TestTextObjectRecord extends TestCase {
             HSSFRichTextString str = new HSSFRichTextString(buff.toString());\r
 \r
             TextObjectRecord obj = new TextObjectRecord();\r
-            int frLength = ( str.numFormattingRuns() + 1 ) * 8;\r
-            obj.setFormattingRunLength( (short) frLength );\r
-            obj.setTextLength( (short) str.length() );\r
-            obj.setStr( str );\r
+            obj.setStr(str);\r
 \r
             byte [] data = obj.serialize();\r
             RecordInputStream is = new RecordInputStream(new ByteArrayInputStream(data));\r
@@ -120,30 +142,12 @@ public final class TestTextObjectRecord extends TestCase {
         HSSFRichTextString str = new HSSFRichTextString(text);\r
 \r
         TextObjectRecord obj = new TextObjectRecord();\r
-        int frLength = ( str.numFormattingRuns() + 1 ) * 8;\r
-        obj.setFormattingRunLength( (short) frLength );\r
-        obj.setTextLength( (short) str.length() );\r
-        obj.setReserved1(true);\r
-        obj.setReserved2((short)2);\r
-        obj.setReserved3((short)3);\r
-        obj.setReserved4((short)4);\r
-        obj.setReserved5((short)5);\r
-        obj.setReserved6((short)6);\r
-        obj.setReserved7((short)7);\r
         obj.setStr( str );\r
 \r
 \r
         TextObjectRecord cloned = (TextObjectRecord)obj.clone();\r
-        assertEquals(obj.getReserved2(), cloned.getReserved2());\r
-        assertEquals(obj.getReserved3(), cloned.getReserved3());\r
-        assertEquals(obj.getReserved4(), cloned.getReserved4());\r
-        assertEquals(obj.getReserved5(), cloned.getReserved5());\r
-        assertEquals(obj.getReserved6(), cloned.getReserved6());\r
-        assertEquals(obj.getReserved7(), cloned.getReserved7());\r
         assertEquals(obj.getRecordSize(), cloned.getRecordSize());\r
-        assertEquals(obj.getOptions(), cloned.getOptions());\r
         assertEquals(obj.getHorizontalTextAlignment(), cloned.getHorizontalTextAlignment());\r
-        assertEquals(obj.getFormattingRunLength(), cloned.getFormattingRunLength());\r
         assertEquals(obj.getStr().getString(), cloned.getStr().getString());\r
 \r
         //finally check that the serialized data is the same\r
@@ -151,4 +155,47 @@ public final class TestTextObjectRecord extends TestCase {
         byte[] cln = cloned.serialize();\r
         assertTrue(Arrays.equals(src, cln));\r
     }\r
+    \r
+    /** similar to {@link #simpleData} but with link formula at end of TXO rec*/ \r
+    private static final byte[] linkData = HexRead.readFromString(\r
+               "B6 01 " + // TextObjectRecord.sid\r
+               "1E 00 " + // size 18\r
+           "44 02 02 00 00 00 00 00" +\r
+           "00 00 " +\r
+           "02 00 " + // strLen 2\r
+           "10 00 " + // 16 bytes for 2 format runs\r
+           "00 00 00 00 " +\r
+\r
+            "05 00 " +          // formula size\r
+            "D4 F0 8A 03 " +    // unknownInt\r
+            "24 01 00 13 C0 " + //tRef(T2)\r
+            "13 " +             // ??\r
+\r
+               "3C 00 " + // ContinueRecord.sid\r
+           "05 00 " + // size 5\r
+           "01 " + // unicode uncompressed\r
+           "41 00 42 00 " + // 'AB'\r
+               "3C 00 " + // ContinueRecord.sid\r
+           "10 00 " + // size 16 \r
+           "00 00 18 00 00 00 00 00 " +\r
+           "02 00 00 00 00 00 00 00 " \r
+        );\r
+    \r
+    \r
+    public void testLinkFormula() {\r
+        RecordInputStream is = new RecordInputStream(new ByteArrayInputStream(linkData));\r
+        is.nextRecord();\r
+        TextObjectRecord rec = new TextObjectRecord(is);\r
+               \r
+        Ptg ptg = rec.getLinkRefPtg();\r
+        assertNotNull(ptg);\r
+        assertEquals(RefPtg.class, ptg.getClass());\r
+        RefPtg rptg = (RefPtg) ptg;\r
+        assertEquals("T2", rptg.toFormulaString());\r
+\r
+        byte [] data2 = rec.serialize();\r
+        assertEquals(linkData.length, data2.length);\r
+        assertTrue(Arrays.equals(linkData, data2));\r
+       }\r
+    \r
 }\r
index 40e98dff93fe4f5cb43800707961a41432f08827..8d416050f767fb1e6d278d4d1dc6db8e083f6fec 100644 (file)
@@ -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());
index 4f2d9efd360462a8eefd007e9b93abc4483cb8b1..b0b8ced7b0a839024aee428c5e36d115ec6f32a5 100644 (file)
@@ -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());
index e449f167d5c1a1eb0114d6d5c5e1a8217d5f15b1..8f3c65be49b605e99ad64d149951b19060132379 100755 (executable)
@@ -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;i<numChars;i++) {
         b.append(i%10);
       }
       return makeUnicodeString(b.toString());
     }
-
 }
index c43828af485e961c36a4f0f7fb08262aa51d64f1..7b79553df49374a6f1362680134581bae866c5d5 100644 (file)
@@ -35,7 +35,7 @@ public final class TestUnitsRecord extends TestCase {
 
     public void testLoad() {
 
-        UnitsRecord record = new UnitsRecord(new TestcaseRecordInputStream((short)0x1001, (short)data.length, data));
+        UnitsRecord record = new UnitsRecord(TestcaseRecordInputStream.create(0x1001, data));
         assertEquals( 0, record.getUnits());
 
         assertEquals( 6, record.getRecordSize() );
index b974bf9759b2fa645f3deedf86600dbd97cfb451..62d7d34c21eda3b5d11eb79132bccdbd4b2280dd 100644 (file)
@@ -40,7 +40,7 @@ public final class TestValueRangeRecord extends TestCase {
 
     public void testLoad() {
 
-        ValueRangeRecord record = new ValueRangeRecord(new TestcaseRecordInputStream((short)0x101f, (short)data.length, data));
+        ValueRangeRecord record = new ValueRangeRecord(TestcaseRecordInputStream.create(0x101f, data));
         assertEquals( 0.0, record.getMinimumAxisValue(), 0.001);
         assertEquals( 0.0, record.getMaximumAxisValue(), 0.001);
         assertEquals( 0.0, record.getMajorIncrement(), 0.001);
index ecb55ca82c1da95192744f0f55681489f09fb3b6..e16eb2022e75e602c795b2294b218b39e2ed00c6 100755 (executable)
@@ -18,6 +18,7 @@
 package org.apache.poi.hssf.record;
 
 import java.io.ByteArrayInputStream;
+import java.io.InputStream;
 
 import junit.framework.Assert;
 
@@ -30,27 +31,51 @@ import org.apache.poi.util.LittleEndian;
  *
  * @author Jason Height (jheight at apache.org)
  */
-public class TestcaseRecordInputStream
-        extends RecordInputStream
-{
+public final class TestcaseRecordInputStream {
+       
+       private TestcaseRecordInputStream() {
+               // no instances of this class
+       }
+       
+       /**
+        * Prepends a mock record identifier to the supplied data and opens a record input stream 
+        */
+       public static RecordInputStream createWithFakeSid(byte[] data) {
+               return create(-5555, data);
+               
+       }
+       public static RecordInputStream create(int sid, byte[] data) {
+               return create(mergeDataAndSid(sid, data.length, data));
+       }
+       /**
+        * First 4 bytes of <tt>data</tt> are assumed to be record identifier and length. The supplied 
+        * <tt>data</tt> 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;
     }
index 52c6f679d7a7f49b753be4f404c4fc621bd11dbf..17a0901040317b1041852379748e30a42e266054 100644 (file)
@@ -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++) {
index df2c1f77bd6d6e1aad0f858e2c4de4e0f0c61b69..8d2fe631d25cb5b62ae000d7453e6d5a9dc9ffe3 100644 (file)
@@ -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);
index 89997b59d1a98af2ab2ef6d089c014a55894675d..827bea8332dc41d8af9f20794d6edecf9a7cab12 100644 (file)
@@ -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() );
index b50bb76b45b4eab4fcda1da7590448a07e4f5d0c..6be329ed5ae57b7d9ac014f3eb56ac6d9e3f78e0 100644 (file)
 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");
         }