]> source.dussan.org Git - poi.git/commitdiff
Merged revisions 638786-638802,638805-638811,638813-638814,638816-639230,639233-63924...
authorNick Burch <nick@apache.org>
Sun, 7 Sep 2008 17:34:36 +0000 (17:34 +0000)
committerNick Burch <nick@apache.org>
Sun, 7 Sep 2008 17:34:36 +0000 (17:34 +0000)
https://svn.apache.org/repos/asf/poi/trunk

........
  r690739 | nick | 2008-08-31 18:24:10 +0100 (Sun, 31 Aug 2008) | 1 line

  HPBF docs update
........
  r690761 | josh | 2008-08-31 20:08:36 +0100 (Sun, 31 Aug 2008) | 1 line

  removed AreaEval.getValues (initial work for bug 45358)
........
  r690772 | josh | 2008-08-31 20:44:11 +0100 (Sun, 31 Aug 2008) | 1 line

  Partial fix for bug 45358 - parsing area refs with rows above 32767
........
  r690825 | josh | 2008-09-01 00:59:26 +0100 (Mon, 01 Sep 2008) | 1 line

  Improving AreaI interface and AreaPtg hierarchy
........
  r690835 | josh | 2008-09-01 02:48:45 +0100 (Mon, 01 Sep 2008) | 1 line

  Converted AreEval and RefEval to be lazy (part of fix for bug 45358)
........
  r690836 | josh | 2008-09-01 03:26:33 +0100 (Mon, 01 Sep 2008) | 1 line

  Fixed IF() to handle different types for the first arg
........
  r690837 | josh | 2008-09-01 03:34:05 +0100 (Mon, 01 Sep 2008) | 1 line

  Update status for bug 45358 (fixed with r690772, r690835 and r690836)
........
  r691017 | nick | 2008-09-01 17:51:09 +0100 (Mon, 01 Sep 2008) | 1 line

  DV related fixes from Pierre Lavignotte
........
  r691180 | yegor | 2008-09-02 10:59:53 +0100 (Tue, 02 Sep 2008) | 1 line

  improved handling of StyleTextPropAtom bit masks, added more read-write roundtrip tests
........
  r691182 | yegor | 2008-09-02 11:03:11 +0100 (Tue, 02 Sep 2008) | 1 line

  continue making progress with hslf hyperlinks
........

git-svn-id: https://svn.apache.org/repos/asf/poi/branches/ooxml@692907 13f79535-47bb-0310-9956-ffa450edef68

68 files changed:
src/documentation/content/xdocs/changes.xml
src/documentation/content/xdocs/hpbf/file-format.xml
src/documentation/content/xdocs/hpbf/index.xml
src/documentation/content/xdocs/status.xml
src/java/org/apache/poi/hssf/record/NameRecord.java
src/java/org/apache/poi/hssf/record/formula/Area2DPtgBase.java [new file with mode: 0644]
src/java/org/apache/poi/hssf/record/formula/Area3DPtg.java
src/java/org/apache/poi/hssf/record/formula/AreaI.java
src/java/org/apache/poi/hssf/record/formula/AreaNPtg.java
src/java/org/apache/poi/hssf/record/formula/AreaPtg.java
src/java/org/apache/poi/hssf/record/formula/AreaPtgBase.java
src/java/org/apache/poi/hssf/record/formula/RefPtgBase.java
src/java/org/apache/poi/hssf/record/formula/eval/Area2DEval.java [deleted file]
src/java/org/apache/poi/hssf/record/formula/eval/Area3DEval.java [deleted file]
src/java/org/apache/poi/hssf/record/formula/eval/AreaEval.java
src/java/org/apache/poi/hssf/record/formula/eval/AreaEvalBase.java
src/java/org/apache/poi/hssf/record/formula/eval/FunctionEval.java
src/java/org/apache/poi/hssf/record/formula/eval/LazyAreaEval.java [new file with mode: 0644]
src/java/org/apache/poi/hssf/record/formula/eval/LazyRefEval.java [new file with mode: 0644]
src/java/org/apache/poi/hssf/record/formula/eval/NumberEval.java
src/java/org/apache/poi/hssf/record/formula/eval/Ref2DEval.java
src/java/org/apache/poi/hssf/record/formula/eval/Ref3DEval.java [deleted file]
src/java/org/apache/poi/hssf/record/formula/eval/RefEval.java
src/java/org/apache/poi/hssf/record/formula/eval/RefEvalBase.java [new file with mode: 0644]
src/java/org/apache/poi/hssf/record/formula/functions/CountUtils.java
src/java/org/apache/poi/hssf/record/formula/functions/If.java
src/java/org/apache/poi/hssf/record/formula/functions/Index.java
src/java/org/apache/poi/hssf/record/formula/functions/LookupUtils.java
src/java/org/apache/poi/hssf/record/formula/functions/MathX.java
src/java/org/apache/poi/hssf/record/formula/functions/MultiOperandNumericFunction.java
src/java/org/apache/poi/hssf/record/formula/functions/Offset.java
src/java/org/apache/poi/hssf/record/formula/functions/Sumx2my2.java
src/java/org/apache/poi/hssf/record/formula/functions/Sumx2py2.java
src/java/org/apache/poi/hssf/record/formula/functions/Sumxmy2.java
src/java/org/apache/poi/hssf/record/formula/functions/XYNumericFunction.java
src/java/org/apache/poi/hssf/usermodel/HSSFFormulaEvaluator.java
src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java
src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java
src/java/org/apache/poi/hssf/util/AreaReference.java
src/java/org/apache/poi/ss/usermodel/FormulaEvaluator.java
src/java/org/apache/poi/ss/util/AreaReference.java [new file with mode: 0644]
src/scratchpad/src/org/apache/poi/hslf/dev/PPTXMLDump.java
src/scratchpad/src/org/apache/poi/hslf/model/Hyperlink.java
src/scratchpad/src/org/apache/poi/hslf/model/SimpleShape.java
src/scratchpad/src/org/apache/poi/hslf/model/textproperties/CharFlagsTextProp.java
src/scratchpad/src/org/apache/poi/hslf/model/textproperties/TextPropCollection.java
src/scratchpad/src/org/apache/poi/hslf/record/ExHyperlink.java
src/scratchpad/src/org/apache/poi/hslf/record/StyleTextPropAtom.java
src/scratchpad/src/org/apache/poi/hslf/usermodel/SlideShow.java
src/scratchpad/src/org/apache/poi/hssf/usermodel/HSSFChart.java
src/scratchpad/testcases/org/apache/poi/hslf/record/TestStyleTextPropAtom.java
src/testcases/org/apache/poi/hssf/data/FormulaEvalTestData.xls
src/testcases/org/apache/poi/hssf/model/TestFormulaParser.java
src/testcases/org/apache/poi/hssf/record/TestLinkedDataRecord.java
src/testcases/org/apache/poi/hssf/record/formula/eval/TestAreaEval.java
src/testcases/org/apache/poi/hssf/record/formula/eval/TestUnaryPlusEval.java
src/testcases/org/apache/poi/hssf/record/formula/functions/EvalFactory.java
src/testcases/org/apache/poi/hssf/record/formula/functions/TestCountFuncs.java
src/testcases/org/apache/poi/hssf/record/formula/functions/TestIndex.java
src/testcases/org/apache/poi/hssf/record/formula/functions/TestMatch.java
src/testcases/org/apache/poi/hssf/record/formula/functions/TestMathX.java
src/testcases/org/apache/poi/hssf/record/formula/functions/TestMid.java
src/testcases/org/apache/poi/hssf/record/formula/functions/TestSumproduct.java
src/testcases/org/apache/poi/hssf/record/formula/functions/TestTFunc.java
src/testcases/org/apache/poi/hssf/record/formula/functions/TestXYNumericFunction.java
src/testcases/org/apache/poi/hssf/usermodel/TestNamedRange.java
src/testcases/org/apache/poi/hssf/util/TestAreaReference.java
src/testcases/org/apache/poi/hssf/util/TestCellReference.java

index 14dcd3b4fc8088efdbacf34749a4874a3a793f1b..cd86842409f5e6d9585eee5bfe1f907630b20632 100644 (file)
@@ -65,6 +65,8 @@
            <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.1.1-alpha1" date="2008-??-??">
+           <action dev="POI-DEVELOPERS" type="add">Initial support for embedded movies and controls in HSLF</action>
+           <action dev="POI-DEVELOPERS" type="fix">45358 - signed/unsigned error when parsing 3-d area refs, performance problem evaluating area refs, and ClassCastExcecption in IF()</action>
            <action dev="POI-DEVELOPERS" type="add">Support for HPBF Publisher hyperlinks, including during text extraction</action>
            <action dev="POI-DEVELOPERS" type="fix">26321 and 44958 - preserve position of ArrayRecords and TableRecords among cell value records</action>
            <action dev="POI-DEVELOPERS" type="fix">Impove empty header or footer handling in HWPF HeaderStories</action>
index e08ebbac04db850bca3eb1117179b79643253b21..ed018582881ec077913e60a5a7db92e06484489e 100644 (file)
@@ -171,6 +171,27 @@ PL   62 1a 00 00 48 00 00 00 // PL   from: 1a62 (6754), len: 48 (72)
                 think that the second 4 bytes of text describes the format
                 of data block at the offset. The format of the text block
                 is easy, but we're still trying to figure out the others.</p>
+
+           <section><title>Structure of TEXT bit</title>
+           <p>This is very simple. All the text for the document is
+            stored in a single bit of the Quill CONTENTS. The text
+            is stored as little endian 16 bit unicode strings.</p>
+           </section>
+           <section><title>Structure of PLC bit</title>
+           <p>The first four bytes seem to hold the count of the 
+            entries in the bit, and the second four bytes seem to hold
+            the type. There is then some pre-data, and then data for
+            each of the entries, the exact format dependant on the type.</p>
+           <p>Type 0 has 4 2 byte unsigned ints, then a pair of 2 byte
+            unsigned ints for each entry.</p>
+           <p>Type 4 has 4 2 byte unsigned ints, then a pair of 4 byte
+            unsigned ints for each entry.</p>
+           <p>Type 8 has 7 2 byte unsigned ints, then a pair of 4 byte
+            unsigned ints for each entry.</p>
+           <p>Type 12 holds hyperlinks, and is very much more complex.
+            See <code>org.apache.poi.hpbf.model.qcbits.QCPLCBit</code>
+            for our best guess as to how the contents match up.</p>
+           </section>
                </section>
        </body>
 </document>
index 01f49f061fc7bff3c4847c8eafa44f633fd8b7a3..84d6948fd44315724306a3e02cd175e105aef4a8 100755 (executable)
@@ -41,7 +41,7 @@
               lots of offsets to other parts of the file.</p>
             <p>Our initial aim is to provude a text extractor for the format
               (now done), and be able to extract hyperlinks from within
-              the document (not yet supported). Additional low level
+              the document (partly supported). Additional low level
               code to process the file format may follow, if there
               is demand and developer interest warrant it.</p>
                        <p>At this time, there is no <em>usermodel</em> api or similar.
index e92ca9b704d99c42861ee15aa9b19a06761082de..5c7198bce557668f2e23ccc06be91f4e3ba87968 100644 (file)
@@ -62,6 +62,8 @@
            <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.1.1-alpha1" date="2008-??-??">
+           <action dev="POI-DEVELOPERS" type="add">Initial support for embedded movies and controls in HSLF</action>
+           <action dev="POI-DEVELOPERS" type="fix">45358 - signed/unsigned error when parsing 3-d area refs, performance problem evaluating area refs, and ClassCastExcecption in IF()</action>
            <action dev="POI-DEVELOPERS" type="add">Support for HPBF Publisher hyperlinks, including during text extraction</action>
            <action dev="POI-DEVELOPERS" type="fix">26321 and 44958 - preserve position of ArrayRecords and TableRecords among cell value records</action>
            <action dev="POI-DEVELOPERS" type="fix">Impove empty header or footer handling in HWPF HeaderStories</action>
index 6c6c53a92bd40402933ee678b28b7e736424f216..71f3bf6fb7d471e1d6fa9a9638ce2c94a1d98a46 100644 (file)
@@ -27,8 +27,8 @@ import org.apache.poi.hssf.record.formula.Ptg;
 import org.apache.poi.hssf.record.formula.Ref3DPtg;
 import org.apache.poi.hssf.record.formula.UnionPtg;
 import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.hssf.util.AreaReference;
 import org.apache.poi.hssf.util.RangeAddress;
+import org.apache.poi.ss.util.AreaReference;
 import org.apache.poi.util.HexDump;
 import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.StringUtil;
@@ -626,7 +626,7 @@ public final class NameRecord extends Record {
        }
 
        private Ptg createNewPtg(){
-               Ptg ptg = new Area3DPtg();
+               Ptg ptg = new Area3DPtg("A1", 0); // TODO - change to not be partially initialised
                field_13_name_definition.push(ptg);
 
                return ptg;
@@ -673,9 +673,7 @@ public final class NameRecord extends Record {
 
                        // Add the area reference(s) 
                        for(int i=0; i<refs.length; i++) {
-                               ptg = new Area3DPtg();
-                               ((Area3DPtg) ptg).setExternSheetIndex(externSheetIndex);
-                               ((Area3DPtg) ptg).setArea(refs[i].formatAsString());
+                               ptg = new Area3DPtg(refs[i].formatAsString(), externSheetIndex);
                                field_13_name_definition.push(ptg);
                                this.setDefinitionTextLength( (short)(getDefinitionLength() + ptg.getSize()) );
                        }
diff --git a/src/java/org/apache/poi/hssf/record/formula/Area2DPtgBase.java b/src/java/org/apache/poi/hssf/record/formula/Area2DPtgBase.java
new file mode 100644 (file)
index 0000000..2193854
--- /dev/null
@@ -0,0 +1,59 @@
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+\r
+package org.apache.poi.hssf.record.formula;\r
+\r
+import org.apache.poi.hssf.record.RecordInputStream;\r
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;\r
+import org.apache.poi.util.LittleEndian;\r
+\r
+/**\r
+ * Common superclass of 2-D area refs \r
+ */\r
+public abstract class Area2DPtgBase extends AreaPtgBase {\r
+       private final static int  SIZE = 9;\r
+\r
+       protected Area2DPtgBase(int firstRow, int lastRow, int firstColumn, int lastColumn, boolean firstRowRelative, boolean lastRowRelative, boolean firstColRelative, boolean lastColRelative) {\r
+               super(firstRow, lastRow, firstColumn, lastColumn, firstRowRelative, lastRowRelative, firstColRelative, lastColRelative);\r
+       }\r
+       protected Area2DPtgBase(RecordInputStream in) {\r
+               readCoordinates(in);\r
+       }\r
+       protected abstract byte getSid();\r
+\r
+       public final void writeBytes(byte [] array, int offset) {\r
+               LittleEndian.putByte(array, offset+0, getSid() + getPtgClass());\r
+               writeCoordinates(array, offset+1);       \r
+       }\r
+       public Area2DPtgBase(String arearef) {\r
+       super(arearef);\r
+       }\r
+       public final int getSize() {\r
+               return SIZE;\r
+       }\r
+       public final String toFormulaString(HSSFWorkbook book) {\r
+       return formatReferenceAsString();\r
+       }\r
+    public final String toString() {\r
+        StringBuffer sb = new StringBuffer();\r
+        sb.append(getClass().getName());\r
+        sb.append(" [");\r
+        sb.append(formatReferenceAsString());\r
+        sb.append("]");\r
+        return sb.toString();\r
+    }\r
+}\r
index 3c9404ac395b25c72bf4dea1d035b39f0be31d4d..ba207ab5c60843a7ce1c463d86ced0324aec5c4e 100644 (file)
 package org.apache.poi.hssf.record.formula;
 
 import org.apache.poi.ss.usermodel.Workbook;
-import org.apache.poi.ss.util.CellReference;
-import org.apache.poi.hssf.util.AreaReference;
 import org.apache.poi.hssf.record.RecordInputStream;
-import org.apache.poi.util.BitField;
-import org.apache.poi.util.BitFieldFactory;
+import org.apache.poi.ss.util.AreaReference;
+import org.apache.poi.ss.util.CellReference;
 import org.apache.poi.util.LittleEndian;
 
 /**
@@ -34,238 +32,63 @@ import org.apache.poi.util.LittleEndian;
  * @author Jason Height (jheight at chariot dot net dot au)
  * @version 1.0-pre
  */
-public final class Area3DPtg extends OperandPtg implements AreaI {
+public final class Area3DPtg extends AreaPtgBase {
        public final static byte sid = 0x3b;
        private final static int SIZE = 11; // 10 + 1 for Ptg
        
-       private static final BitField rowRelative = BitFieldFactory.getInstance(0x8000);
-       private static final BitField colRelative = BitFieldFactory.getInstance(0x4000);
-       
-       private short field_1_index_extern_sheet;
-       private int field_2_first_row;
-       private int field_3_last_row;
-       private int field_4_first_column;
-       private int field_5_last_column;
+       private int field_1_index_extern_sheet;
 
 
-       /** Creates new AreaPtg */
-       public Area3DPtg()
-       {
-       }
-
-       public Area3DPtg( String arearef, short externIdx )
-       {
-               setArea(arearef);
+       public Area3DPtg( String arearef, int externIdx ) {
+               super(arearef);
                setExternSheetIndex( externIdx );
-
        }
 
-       public Area3DPtg(RecordInputStream in)
-       {
+       public Area3DPtg(RecordInputStream in) {
                field_1_index_extern_sheet = in.readShort();
-               field_2_first_row = in.readUShort();
-               field_3_last_row = in.readUShort();
-               field_4_first_column = in.readUShort();
-               field_5_last_column = in.readUShort();
+               readCoordinates(in);
        }
 
-       public Area3DPtg(short firstRow, short lastRow, short firstColumn, short lastColumn,
+       public Area3DPtg(int firstRow, int lastRow, int firstColumn, int lastColumn,
                        boolean firstRowRelative, boolean lastRowRelative, boolean firstColRelative, boolean lastColRelative,
-                       short externalSheetIndex) {
-                 setFirstRow(firstRow);
-                 setLastRow(lastRow);
-                 setFirstColumn(firstColumn);
-                 setLastColumn(lastColumn);
-                 setFirstRowRelative(firstRowRelative);
-                 setLastRowRelative(lastRowRelative);
-                 setFirstColRelative(firstColRelative);
-                 setLastColRelative(lastColRelative);
-                 setExternSheetIndex(externalSheetIndex);
+                       int externalSheetIndex) {
+               super(firstRow, lastRow, firstColumn, lastColumn, firstRowRelative, lastRowRelative, firstColRelative, lastColRelative);
+               setExternSheetIndex(externalSheetIndex);
        }
 
        public String toString() {
                StringBuffer sb = new StringBuffer();
                sb.append(getClass().getName());
-               sb.append(" [");
                sb.append("sheetIx=").append(getExternSheetIndex());
                sb.append(" ! ");
-               sb.append(AreaReference.formatAsString(this));
+               sb.append(formatReferenceAsString());
                sb.append("]");
                return sb.toString();
        }
 
-       public void writeBytes( byte[] array, int offset )
-       {
-               array[0 + offset] = (byte) ( sid + getPtgClass() );
-               LittleEndian.putShort( array, 1 + offset, getExternSheetIndex() );
-               LittleEndian.putShort( array, 3 + offset, (short)getFirstRow() );
-               LittleEndian.putShort( array, 5 + offset, (short)getLastRow() );
-               LittleEndian.putShort( array, 7 + offset, (short)getFirstColumnRaw() );
-               LittleEndian.putShort( array, 9 + offset, (short)getLastColumnRaw() );
+       public void writeBytes(byte[] array, int offset) {
+               LittleEndian.putByte(array, offset + 0, sid + getPtgClass());
+               LittleEndian.putUShort(array, 1 + offset, field_1_index_extern_sheet);
+               writeCoordinates(array, offset+3);
        }
 
-       public int getSize()
-       {
+       public int getSize() {
                return SIZE;
        }
 
-       public short getExternSheetIndex()
-       {
-               return field_1_index_extern_sheet;
+       public short getExternSheetIndex() {
+               return (short)field_1_index_extern_sheet;
        }
 
-       public void setExternSheetIndex( short index )
-       {
+       public void setExternSheetIndex(int index) {
                field_1_index_extern_sheet = index;
        }
 
-       public int getFirstRow()
-       {
-               return field_2_first_row;
-       }
-
-       public void setFirstRow( int row )
-       {
-               field_2_first_row = row;
-       }
-
-       public int getLastRow()
-       {
-               return field_3_last_row;
-       }
-
-       public void setLastRow( int row )
-       {
-               field_3_last_row = row;
-       }
-
-       public int getFirstColumn()
-       {
-               return field_4_first_column & 0xFF;
-       }
-
-       public int getFirstColumnRaw()
-       {
-               return field_4_first_column;
-       }
-
-       public boolean isFirstRowRelative()
-       {
-               return rowRelative.isSet( field_4_first_column );
-       }
-
-       public boolean isFirstColRelative()
-       {
-               return colRelative.isSet( field_4_first_column );
-       }
-
-       public void setFirstColumn( short column )
-       {
-               field_4_first_column &= 0xFF00;
-               field_4_first_column |= column & 0xFF;
-       }
-
-       public void setFirstColumnRaw( short column )
-       {
-               field_4_first_column = column;
-       }
-
-       public int getLastColumn()
-       {
-               return field_5_last_column & 0xFF;
-       }
-
-       public int getLastColumnRaw()
-       {
-               return field_5_last_column;
-       }
-
-       public boolean isLastRowRelative()
-       {
-               return rowRelative.isSet( field_5_last_column );
-       }
-
-       public boolean isLastColRelative()
-       {
-               return colRelative.isSet( field_5_last_column );
-       }
-
-       public void setLastColumn( short column )
-       {
-               field_5_last_column &= 0xFF00;
-               field_5_last_column |= column & 0xFF;
-       }
-
-       public void setLastColumnRaw( short column )
-       {
-               field_5_last_column = column;
-       }
-
-       /**
-        * sets the first row to relative or not
-        * @param rel FIXME: Document this!
-        */
-       public void setFirstRowRelative( boolean rel )
-       {
-               field_4_first_column = rowRelative.setBoolean( field_4_first_column, rel );
-       }
-
-       /**
-        * set whether the first column is relative
-        */
-       public void setFirstColRelative( boolean rel )
-       {
-               field_4_first_column = colRelative.setBoolean( field_4_first_column, rel );
-       }
-
-       /**
-        * set whether the last row is relative or not
-        * @param rel FIXME: Document this!
-        */
-       public void setLastRowRelative( boolean rel )
-       {
-               field_5_last_column = rowRelative.setBoolean( field_5_last_column, rel );
-       }
-
-       /**
-        * set whether the last column should be relative or not
-        */
-       public void setLastColRelative( boolean rel )
-       {
-               field_5_last_column = colRelative.setBoolean( field_5_last_column, rel );
-       }
-
-
-       /*public String getArea(){
-               RangeAddress ra = new RangeAddress( getFirstColumn(),getFirstRow() + 1, getLastColumn(), getLastRow() + 1);
-               String result = ra.getAddress();
-
-               return result;
-       }*/
-
-       public void setArea( String ref )
-       {
-               AreaReference ar = new AreaReference( ref );
-               
-               CellReference frstCell = ar.getFirstCell();
-               CellReference lastCell = ar.getLastCell();
-
-               setFirstRow(    (short) frstCell.getRow() );
-               setFirstColumn( (short) frstCell.getCol() );
-               setLastRow(     (short) lastCell.getRow() );
-               setLastColumn(  (short) lastCell.getCol() );
-               setFirstColRelative( !frstCell.isColAbsolute() );
-               setLastColRelative(  !lastCell.isColAbsolute() );
-               setFirstRowRelative( !frstCell.isRowAbsolute() );
-               setLastRowRelative(  !lastCell.isRowAbsolute() );
-       }
-
        /**
         * @return text representation of this area reference that can be used in text
         *  formulas. The sheet name will get properly delimited if required.
         */
-       public String toFormulaString(Workbook book)
-       {
+       public String toFormulaString(Workbook book) {
                // First do the sheet name
                StringBuffer retval = new StringBuffer();
                String sheetName = Ref3DPtg.getSheetName(book, field_1_index_extern_sheet);
@@ -282,29 +105,8 @@ public final class Area3DPtg extends OperandPtg implements AreaI {
                }
                
                // Now the normal area bit
-               retval.append(AreaReference.formatAsString(this));
+               retval.append(formatReferenceAsString());
                
-               // All done
                return retval.toString();
        }
-
-       public byte getDefaultOperandClass() {
-               return Ptg.CLASS_REF;
-       }
-       // TODO - one junit relies on this. remove
-       public boolean equals( Object o )
-       {
-               if ( this == o ) return true;
-               if ( !( o instanceof Area3DPtg ) ) return false;
-
-               final Area3DPtg area3DPtg = (Area3DPtg) o;
-
-               if ( field_1_index_extern_sheet != area3DPtg.field_1_index_extern_sheet ) return false;
-               if ( field_2_first_row != area3DPtg.field_2_first_row ) return false;
-               if ( field_3_last_row != area3DPtg.field_3_last_row ) return false;
-               if ( field_4_first_column != area3DPtg.field_4_first_column ) return false;
-               if ( field_5_last_column != area3DPtg.field_5_last_column ) return false;
-
-               return true;
-       }
 }
index 5a0a21e861501abb318d144929c72e94e344cea7..477d32f677c4f472cc86557da70b0301a9bf9db0 100644 (file)
    See the License for the specific language governing permissions and
    limitations under the License.
 ==================================================================== */
+
 package org.apache.poi.hssf.record.formula;
 
 /**
- * Common interface for AreaPtg and Area3DPtg, and their
- *  child classes.
+ * Common interface for AreaPtg and Area3DPtg, and their child classes.
  */
 public interface AreaI {
-    /**
-     * @return the first row in the area
-     */
-    public int getFirstRow();
-
-    /**
-     * @return last row in the range (x2 in x1,y1-x2,y2)
-     */
-    public int getLastRow();
-    
-    /**
-     * @return the first column number in the area.
-     */
-    public int getFirstColumn();
-    
-    /**
-     * @return lastcolumn in the area
-     */
-    public int getLastColumn();
-    
-    /**
-     * @return isrelative first column to relative or not
-     */
-    public boolean isFirstColRelative();
-    /**
-     * @return lastcol relative or not
-     */
-    public boolean isLastColRelative();
-    /**
-     * @return whether or not the first row is a relative reference or not.
-     */
-    public boolean isFirstRowRelative();
-    /**
-     * @return last row relative or not
-     */
-    public boolean isLastRowRelative();
+       /**
+        * @return the first row in the area
+        */
+       public int getFirstRow();
+
+       /**
+        * @return last row in the range (x2 in x1,y1-x2,y2)
+        */
+       public int getLastRow();
+
+       /**
+        * @return the first column number in the area.
+        */
+       public int getFirstColumn();
+
+       /**
+        * @return lastcolumn in the area
+        */
+       public int getLastColumn();
+
+       class OffsetArea implements AreaI {
+
+               private final int _firstColumn;
+               private final int _firstRow;
+               private final int _lastColumn;
+               private final int _lastRow;
+
+               public OffsetArea(int baseRow, int baseColumn, int relFirstRowIx, int relLastRowIx,
+                               int relFirstColIx, int relLastColIx) {
+                       _firstRow = baseRow + relFirstRowIx;
+                       _lastRow = baseRow + relLastRowIx;
+                       _firstColumn = baseColumn + relFirstColIx;
+                       _lastColumn = baseColumn + relLastColIx;
+               }
+
+               public int getFirstColumn() {
+                       return _firstColumn;
+               }
+
+               public int getFirstRow() {
+                       return _firstRow;
+               }
+
+               public int getLastColumn() {
+                       return _lastColumn;
+               }
+
+               public int getLastRow() {
+                       return _lastRow;
+               }
+       }
+
 }
\ No newline at end of file
index bf013838b2c0213b3245fbb3e79de400a5ca28e9..fc391b801d03829393b37c5d782431ce6b621244 100644 (file)
@@ -23,7 +23,7 @@ import org.apache.poi.hssf.record.RecordInputStream;
  * Specifies a rectangular area of cells A1:A4 for instance.
  * @author Jason Height (jheight at chariot dot net dot au)
  */
-public final class AreaNPtg extends AreaPtgBase {
+public final class AreaNPtg extends Area2DPtgBase {
        public final static short sid = 0x2D;
 
        public AreaNPtg(RecordInputStream in) {
index 0839e5570aa74989d7a797161d9b4f9c3e29736b..77e9fa0b5e67759cfa1a1b85de0748d27306f2bd 100755 (executable)
@@ -23,16 +23,16 @@ import org.apache.poi.hssf.record.RecordInputStream;
  * Specifies a rectangular area of cells A1:A4 for instance.
  * @author Jason Height (jheight at chariot dot net dot au)
  */
-public final class AreaPtg extends AreaPtgBase {
-    public final static short sid  = 0x25;
+public final class AreaPtg extends Area2DPtgBase {
+       public final static short sid  = 0x25;
 
-    public AreaPtg(int firstRow, int lastRow, int firstColumn, int lastColumn, boolean firstRowRelative, boolean lastRowRelative, boolean firstColRelative, boolean lastColRelative) {
-      super(firstRow, lastRow, firstColumn, lastColumn, firstRowRelative, lastRowRelative, firstColRelative, lastColRelative);
-    }
-    public AreaPtg(RecordInputStream in) {
-      super(in);
-    }
-    public AreaPtg(String arearef) {
+       public AreaPtg(int firstRow, int lastRow, int firstColumn, int lastColumn, boolean firstRowRelative, boolean lastRowRelative, boolean firstColRelative, boolean lastColRelative) {
+               super(firstRow, lastRow, firstColumn, lastColumn, firstRowRelative, lastRowRelative, firstColRelative, lastColRelative);
+       }
+       public AreaPtg(RecordInputStream in) {
+               super(in);
+       }
+       public AreaPtg(String arearef) {
                super(arearef);
        }
        protected byte getSid() {
index 9ac406b319787dd8a77056d81edad7481e414570..cf3d82cacf9c06bd2811bcb55d61b3f829de1aac 100644 (file)
@@ -23,7 +23,7 @@ import org.apache.poi.util.BitFieldFactory;
 
 import org.apache.poi.ss.util.CellReference;
 import org.apache.poi.ss.usermodel.Workbook;
-import org.apache.poi.hssf.util.AreaReference;
+import org.apache.poi.ss.util.AreaReference;
 import org.apache.poi.hssf.record.RecordInputStream;
 
 /**
@@ -37,11 +37,9 @@ public abstract class AreaPtgBase extends OperandPtg implements AreaI {
      * see similar comment in ReferencePtg
      */
     protected final RuntimeException notImplemented() {
-          return new RuntimeException("Coding Error: This method should never be called. This ptg should be converted");
+        return new RuntimeException("Coding Error: This method should never be called. This ptg should be converted");
     }
 
-    public final static short sid  = 0x25;
-    private final static int  SIZE = 9;
     /** zero based, unsigned 16 bit */
     private int             field_1_first_row;
     /** zero based, unsigned 16 bit */
@@ -55,6 +53,10 @@ public abstract class AreaPtgBase extends OperandPtg implements AreaI {
     private final static BitField   colRelative = BitFieldFactory.getInstance(0x4000);
     private final static BitField   columnMask      = BitFieldFactory.getInstance(0x3FFF);
 
+    protected AreaPtgBase() {
+        // do nothing
+    }
+    
     protected AreaPtgBase(String arearef) {
         AreaReference ar = new AreaReference(arearef);
         CellReference firstCell = ar.getFirstCell();
@@ -97,35 +99,17 @@ public abstract class AreaPtgBase extends OperandPtg implements AreaI {
         }
     }
 
-    protected AreaPtgBase(RecordInputStream in)
-    {
-        field_1_first_row    = in.readUShort();
-        field_2_last_row     = in.readUShort();
+    protected final void readCoordinates(RecordInputStream in) {
+        field_1_first_row = in.readUShort();
+        field_2_last_row = in.readUShort();
         field_3_first_column = in.readUShort();
-        field_4_last_column  = in.readUShort();
-    }
-
-    public final String toString() {
-        StringBuffer sb = new StringBuffer();
-        sb.append(getClass().getName());
-        sb.append(" [");
-        sb.append(AreaReference.formatAsString(this));
-        sb.append("]");
-        return sb.toString();
+        field_4_last_column = in.readUShort();
     }
-    protected abstract byte getSid();
-
-    public final void writeBytes(byte [] array, int offset) {
-        array[offset] = (byte) (getSid() + getPtgClass());
-        LittleEndian.putShort(array,offset+1,(short)field_1_first_row);
-        LittleEndian.putShort(array,offset+3,(short)field_2_last_row);
-        LittleEndian.putShort(array,offset+5,(short)field_3_first_column);
-        LittleEndian.putShort(array,offset+7,(short)field_4_last_column);        
-    }
-
-    
-    public final int getSize() {
-        return SIZE;
+    protected final void writeCoordinates(byte[] array, int offset) {
+        LittleEndian.putUShort(array, offset + 0, field_1_first_row);
+        LittleEndian.putUShort(array, offset + 2, field_2_last_row);
+        LittleEndian.putUShort(array, offset + 4, field_3_first_column);
+        LittleEndian.putUShort(array, offset + 6, field_4_last_column);        
     }
 
     /**
@@ -207,7 +191,7 @@ public abstract class AreaPtgBase extends OperandPtg implements AreaI {
      */
     public final void setFirstColumn(int colIx) {
         checkColumnBounds(colIx);
-       field_3_first_column=columnMask.setValue(field_3_first_column, colIx);
+        field_3_first_column=columnMask.setValue(field_3_first_column, colIx);
     }
 
     /**
@@ -266,7 +250,7 @@ public abstract class AreaPtgBase extends OperandPtg implements AreaI {
      */
     public final void setLastColumn(int colIx) {
         checkColumnBounds(colIx);
-       field_4_last_column=columnMask.setValue(field_4_last_column, colIx);
+        field_4_last_column=columnMask.setValue(field_4_last_column, colIx);
     }
 
     /**
@@ -275,9 +259,18 @@ public abstract class AreaPtgBase extends OperandPtg implements AreaI {
     public final void setLastColumnRaw(short column) {
         field_4_last_column = column;
     }
+    protected final String formatReferenceAsString() {
+        CellReference topLeft = new CellReference(getFirstRow(),getFirstColumn(),!isFirstRowRelative(),!isFirstColRelative());
+        CellReference botRight = new CellReference(getLastRow(),getLastColumn(),!isLastRowRelative(),!isLastColRelative());
+        
+        if(AreaReference.isWholeColumnReference(topLeft, botRight)) {
+            return (new AreaReference(topLeft, botRight)).formatAsString();
+        }
+        return topLeft.formatAsString() + ":" + botRight.formatAsString(); 
+    }
     
     public String toFormulaString(Workbook book) {
-        return AreaReference.formatAsString(this);
+        return formatReferenceAsString();
     }
 
     public byte getDefaultOperandClass() {
index 87207f6a07435459405909a00ea28c324d443807..33dff9ec04af1d56f292f05b7c13d41be06ee01f 100644 (file)
@@ -131,14 +131,6 @@ public abstract class RefPtgBase extends OperandPtg {
         field_2_col=colRelative.setBoolean(field_2_col,rel);
     }
 
-    public final void setColumnRawX(int col) { // TODO
-        field_2_col = col;
-    }
-
-    public int getColumnRawX() { // TODO
-        return field_2_col;
-    }
-
     public final void setColumn(int col) {
         if(col < 0 || col >= 0x100) {
             throw new IllegalArgumentException("Specified colIx (" + col + ") is out of range");
diff --git a/src/java/org/apache/poi/hssf/record/formula/eval/Area2DEval.java b/src/java/org/apache/poi/hssf/record/formula/eval/Area2DEval.java
deleted file mode 100644 (file)
index 5ae98b3..0000000
+++ /dev/null
@@ -1,32 +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.formula.eval;
-
-import org.apache.poi.hssf.record.formula.AreaPtg;
-import org.apache.poi.hssf.record.formula.Ptg;
-
-/**
- * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
- * 
- */
-public final class Area2DEval extends AreaEvalBase {
-
-       public Area2DEval(Ptg ptg, ValueEval[] values) {
-               super((AreaPtg) ptg, values);
-       }
-}
\ No newline at end of file
diff --git a/src/java/org/apache/poi/hssf/record/formula/eval/Area3DEval.java b/src/java/org/apache/poi/hssf/record/formula/eval/Area3DEval.java
deleted file mode 100644 (file)
index 89209e2..0000000
+++ /dev/null
@@ -1,39 +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.formula.eval;
-
-import org.apache.poi.hssf.record.formula.Area3DPtg;
-import org.apache.poi.hssf.record.formula.Ptg;
-
-/**
- * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
- * 
- */
-public final class Area3DEval extends AreaEvalBase {
-
-       private final int _externSheetIndex;
-
-       public Area3DEval(Ptg ptg, ValueEval[] values) {
-               super((Area3DPtg) ptg, values);
-               _externSheetIndex = ((Area3DPtg) ptg).getExternSheetIndex();
-       }
-
-       public int getExternSheetIndex() {
-               return _externSheetIndex;
-       }
-}
index 182b9b618b458587d6adc666930f02476a9a4e4b..b528eb784e0e39940174aa3dcbe95a242ddb4507 100644 (file)
@@ -61,13 +61,6 @@ public interface AreaEval extends ValueEval {
      */
     boolean isColumn();
 
-    /**
-     * The array of values  in this area. Although the area
-     * maybe 1D (ie. isRow() or isColumn() returns true) or 2D
-     * the returned array is 1D.
-     */
-    ValueEval[] getValues();
-
     /**
      * @return the ValueEval from within this area at the specified row and col index. Never 
      * <code>null</code> (possibly {@link BlankEval}).  The specified indexes should be absolute 
@@ -104,4 +97,10 @@ public interface AreaEval extends ValueEval {
      * specified indexes should relative to the top left corner of this area.  
      */
     ValueEval getRelativeValue(int relativeRowIndex, int relativeColumnIndex);
+
+    /**
+     * Creates an {@link AreaEval} offset by a relative amount from from the upper left cell
+     * of this area
+     */
+    AreaEval offset(int relFirstRowIx, int relLastRowIx, int relFirstColIx, int relLastColIx);
 }
index 1686e75f33a4a3f27d501162cd5726a892f66de3..94f6c9fe4a16e973a794d04b0e55bd120768e76d 100644 (file)
@@ -22,20 +22,16 @@ import org.apache.poi.hssf.record.formula.AreaI;
 /**
  * @author Josh Micich
  */
-abstract class AreaEvalBase implements AreaEval {
+public abstract class AreaEvalBase implements AreaEval {
 
        private final int _firstColumn;
        private final int _firstRow;
        private final int _lastColumn;
        private final int _lastRow;
-       private final ValueEval[] _values;
        private final int _nColumns;
        private final int _nRows;
 
-       protected AreaEvalBase(AreaI ptg, ValueEval[] values) {
-               if (values == null) {
-                       throw new IllegalArgumentException("values must not be null");
-               }
+       protected AreaEvalBase(AreaI ptg) {
                _firstRow = ptg.getFirstRow();
                _firstColumn = ptg.getFirstColumn();
                _lastRow = ptg.getLastRow();
@@ -43,22 +39,6 @@ abstract class AreaEvalBase implements AreaEval {
                
                _nColumns = _lastColumn - _firstColumn + 1;
                _nRows = _lastRow - _firstRow + 1;
-               
-               int expectedItemCount = _nRows * _nColumns;
-               if ((values.length != expectedItemCount)) {
-                       // Note - this math may need alteration when POI starts to support full column or full row refs
-                       throw new IllegalArgumentException("Array size should be (" + expectedItemCount
-                                       + ") but was (" + values.length + ")");
-               }
-               
-
-
-               for (int i = values.length - 1; i >= 0; i--) {
-                       if (values[i] == null) {
-                               throw new IllegalArgumentException("value array elements must not be null");
-                       }
-               }
-               _values = values;
        }
 
        public final int getFirstColumn() {
@@ -77,11 +57,6 @@ abstract class AreaEvalBase implements AreaEval {
                return _lastRow;
        }
 
-       public final ValueEval[] getValues() {
-               // TODO - clone() - but some junits rely on not cloning at the moment
-               return _values;
-       }
-
        public final ValueEval getValueAt(int row, int col) {
                int rowOffsetIx = row - _firstRow;
                int colOffsetIx = col - _firstColumn;
@@ -121,14 +96,7 @@ abstract class AreaEvalBase implements AreaEval {
                return _lastRow-_firstRow+1;
        }
 
-       public ValueEval getRelativeValue(int relativeRowIndex, int relativeColumnIndex) {
-               int index = relativeRowIndex * _nColumns + relativeColumnIndex;
-               ValueEval result = _values[index];
-               if (result == null) {
-                       return BlankEval.INSTANCE;
-               }
-               return result;
-       }
+       public abstract ValueEval getRelativeValue(int relativeRowIndex, int relativeColumnIndex);
 
        public int getWidth() {
                return _lastColumn-_firstColumn+1;
index 533c604a0c77fec760dd5cb033825d2a8d9402af..fe58c69c095013fee76cecc18b9fa4c9b4c932ca 100644 (file)
@@ -50,7 +50,6 @@ public abstract class FunctionEval implements OperationEval {
      
     static {
         Map m = new HashMap();
-        addMapping(m, ID.OFFSET, new Offset());
         addMapping(m, ID.INDIRECT, new Indirect());
         addMapping(m, ID.EXTERNAL_FUNC, new ExternalFunction());
         freeRefFunctionsByIdMap = m;
@@ -155,7 +154,7 @@ public abstract class FunctionEval implements OperationEval {
         retval[75] = new Areas(); // AREAS
         retval[76] = new Rows(); // ROWS
         retval[77] = new Columns(); // COLUMNS
-        retval[ID.OFFSET] = null; // Offset.evaluate has a different signature
+        retval[ID.OFFSET] = new Offset(); // OFFSET
         retval[79] = new Absref(); // ABSREF
         retval[80] = new Relref(); // RELREF
         retval[81] = new Argument(); // ARGUMENT
diff --git a/src/java/org/apache/poi/hssf/record/formula/eval/LazyAreaEval.java b/src/java/org/apache/poi/hssf/record/formula/eval/LazyAreaEval.java
new file mode 100644 (file)
index 0000000..b5c6336
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements.  See the NOTICE file distributed with
+* this work for additional information regarding copyright ownership.
+* The ASF licenses this file to You under the Apache License, Version 2.0
+* (the "License"); you may not use this file except in compliance with
+* the License.  You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package org.apache.poi.hssf.record.formula.eval;
+
+import org.apache.poi.hssf.record.formula.AreaI;
+import org.apache.poi.hssf.record.formula.AreaI.OffsetArea;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.FormulaEvaluator;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+
+/**
+ * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
+ * 
+ */
+public final class LazyAreaEval extends AreaEvalBase {
+
+       private final Sheet _sheet;
+       private Workbook _workbook;
+
+       public LazyAreaEval(AreaI ptg, Sheet sheet, Workbook workbook) {
+               super(ptg);
+               _sheet = sheet;
+               _workbook = workbook;
+       }
+
+       public ValueEval getRelativeValue(int relativeRowIndex, int relativeColumnIndex) { 
+               
+               int rowIx = (relativeRowIndex + getFirstRow() ) & 0xFFFF;
+               int colIx = (relativeColumnIndex + getFirstColumn() ) & 0x00FF;
+               
+               Row row = _sheet.getRow(rowIx);
+               if (row == null) {
+                       return BlankEval.INSTANCE;
+               }
+               Cell cell = row.getCell(colIx);
+               if (cell == null) {
+                       return BlankEval.INSTANCE;
+               }
+               return FormulaEvaluator.getEvalForCell(cell, _sheet, _workbook);
+       }
+
+       public AreaEval offset(int relFirstRowIx, int relLastRowIx, int relFirstColIx, int relLastColIx) {
+               AreaI area = new OffsetArea(getFirstRow(), getFirstColumn(),
+                               relFirstRowIx, relLastRowIx, relFirstColIx, relLastColIx);
+
+               return new LazyAreaEval(area, _sheet, _workbook);
+       }
+}
diff --git a/src/java/org/apache/poi/hssf/record/formula/eval/LazyRefEval.java b/src/java/org/apache/poi/hssf/record/formula/eval/LazyRefEval.java
new file mode 100644 (file)
index 0000000..7daf964
--- /dev/null
@@ -0,0 +1,52 @@
+package org.apache.poi.hssf.record.formula.eval;\r
+\r
+import org.apache.poi.hssf.record.formula.AreaI;\r
+import org.apache.poi.hssf.record.formula.AreaI.OffsetArea;\r
+import org.apache.poi.hssf.record.formula.Ref3DPtg;\r
+import org.apache.poi.hssf.record.formula.RefPtg;\r
+import org.apache.poi.ss.usermodel.Cell;\r
+import org.apache.poi.ss.usermodel.FormulaEvaluator;\r
+import org.apache.poi.ss.usermodel.Row;\r
+import org.apache.poi.ss.usermodel.Sheet;\r
+import org.apache.poi.ss.usermodel.Workbook;\r
+\r
+public final class LazyRefEval extends RefEvalBase {\r
+\r
+       private final Sheet _sheet;\r
+       private final Workbook _workbook;\r
+\r
+\r
+       public LazyRefEval(RefPtg ptg, Sheet sheet, Workbook workbook) {\r
+               super(ptg.getRow(), ptg.getColumn());\r
+               _sheet = sheet;\r
+               _workbook = workbook;\r
+       }\r
+       public LazyRefEval(Ref3DPtg ptg, Sheet sheet, Workbook workbook) {\r
+               super(ptg.getRow(), ptg.getColumn());\r
+               _sheet = sheet;\r
+               _workbook = workbook;\r
+       }\r
+\r
+       public ValueEval getInnerValueEval() {\r
+               int rowIx = getRow();\r
+               int colIx = getColumn();\r
+               \r
+               Row row = _sheet.getRow(rowIx);\r
+               if (row == null) {\r
+                       return BlankEval.INSTANCE;\r
+               }\r
+               Cell cell = row.getCell(colIx);\r
+               if (cell == null) {\r
+                       return BlankEval.INSTANCE;\r
+               }\r
+               return FormulaEvaluator.getEvalForCell(cell, _sheet, _workbook);\r
+       }\r
+       \r
+       public AreaEval offset(int relFirstRowIx, int relLastRowIx, int relFirstColIx, int relLastColIx) {\r
+               \r
+               AreaI area = new OffsetArea(getRow(), getColumn(),\r
+                               relFirstRowIx, relLastRowIx, relFirstColIx, relLastColIx);\r
+\r
+               return new LazyAreaEval(area, _sheet, _workbook);\r
+       }\r
+}\r
index 44a017f631d98347b8ab43b0f316f72362ef1bf7..e22957bd4ab14642d18ac44264ce4001f60f6082 100644 (file)
@@ -69,5 +69,11 @@ public class NumberEval implements NumericValueEval, StringValueEval {
             }
         }
     }
-    
+    public final String toString() {
+        StringBuffer sb = new StringBuffer(64);
+        sb.append(getClass().getName()).append(" [");
+        sb.append(getStringValue());
+        sb.append("]");
+        return sb.toString();
+    }
 }
index 033ecc1f862cef5068e3bc3bc76aa89e0922376b..e4bb47a43df535a041d8f8d0278616a4ab068a1c 100644 (file)
@@ -47,4 +47,7 @@ public final class Ref2DEval implements RefEval {
     public int getColumn() {
         return delegate.getColumn();
     }
+    public AreaEval offset(int relFirstRowIx, int relLastRowIx, int relFirstColIx, int relLastColIx) {
+        throw new RuntimeException("should not be called"); // TODO - delete this whole class
+    }
 }
diff --git a/src/java/org/apache/poi/hssf/record/formula/eval/Ref3DEval.java b/src/java/org/apache/poi/hssf/record/formula/eval/Ref3DEval.java
deleted file mode 100644 (file)
index 622d686..0000000
+++ /dev/null
@@ -1,53 +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.formula.eval;
-
-import org.apache.poi.hssf.record.formula.Ref3DPtg;
-
-/**
- * @author Amol S. Deshmukh
- *  
- */
-public final class Ref3DEval implements RefEval {
-
-    private final ValueEval value;
-    private final Ref3DPtg delegate;
-
-    public Ref3DEval(Ref3DPtg ptg, ValueEval ve) {
-        if(ve == null) {
-            throw new IllegalArgumentException("ve must not be null");
-        }
-        if(ptg == null) {
-            throw new IllegalArgumentException("ptg must not be null");
-        }
-        value = ve;
-        delegate = ptg;
-    }
-    public ValueEval getInnerValueEval() {
-        return value;
-    }
-    public int getRow() {
-        return delegate.getRow();
-    }
-    public int getColumn() {
-        return delegate.getColumn();
-    }
-    public int getExternSheetIndex() {
-        return delegate.getExternSheetIndex();
-    }
-}
index e462586d72480e1c3cdc31482fe05428e4028e0a..397d1f1c94160545afa86b5702b362e4a5b11b06 100644 (file)
@@ -1,19 +1,19 @@
-/*
-* 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.
-*/
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
 
 package org.apache.poi.hssf.record.formula.eval;
 
@@ -30,22 +30,22 @@ package org.apache.poi.hssf.record.formula.eval;
 public interface RefEval extends ValueEval {
 
     /**
-     * The (possibly evaluated) ValueEval contained
-     * in this RefEval. eg. if cell A1 contains "test"
-     * then in a formula referring to cell A1 
-     * the RefEval representing
-     * A1 will return as the getInnerValueEval() the
-     * object of concrete type StringEval
+     * @return the evaluated value of the cell referred to by this RefEval.
      */
-    public ValueEval getInnerValueEval();
+    ValueEval getInnerValueEval();
 
     /**
      * returns the zero based column index.
      */
-    public int getColumn();
+    int getColumn();
 
     /**
      * returns the zero based row index.
      */
-    public int getRow();
+    int getRow();
+
+    /**
+     * Creates an {@link AreaEval} offset by a relative amount from this RefEval
+     */
+    AreaEval offset(int relFirstRowIx, int relLastRowIx, int relFirstColIx, int relLastColIx);
 }
diff --git a/src/java/org/apache/poi/hssf/record/formula/eval/RefEvalBase.java b/src/java/org/apache/poi/hssf/record/formula/eval/RefEvalBase.java
new file mode 100644 (file)
index 0000000..37d20f8
--- /dev/null
@@ -0,0 +1,18 @@
+package org.apache.poi.hssf.record.formula.eval;\r
+\r
+public abstract class RefEvalBase implements RefEval {\r
+\r
+       private final int _rowIndex;\r
+       private final int _columnIndex;\r
+\r
+       protected RefEvalBase(int rowIndex, int columnIndex) {\r
+               _rowIndex = rowIndex;\r
+               _columnIndex = columnIndex;\r
+       }\r
+       public final int getRow() {\r
+               return _rowIndex;\r
+       }\r
+       public final int getColumn() {\r
+               return _columnIndex;\r
+       }\r
+}\r
index f8d88838257383e723c95afa57201711ad348288..27dfcc1b64500dca97206e1efddc574432dce97f 100644 (file)
@@ -50,9 +50,9 @@ final class CountUtils {
                for (int rrIx=0; rrIx<height; rrIx++) {
                        for (int rcIx=0; rcIx<width; rcIx++) {
                                ValueEval ve = areaEval.getRelativeValue(rrIx, rcIx);
-                       if(criteriaPredicate.matches(ve)) {
-                               result++;
-                       }
+                               if(criteriaPredicate.matches(ve)) {
+                                       result++;
+                               }
                        }
                }
                return result;
@@ -67,6 +67,9 @@ final class CountUtils {
                return 0;
        }
        public static int countArg(Eval eval, I_MatchPredicate criteriaPredicate) {
+               if (eval == null) {
+                       throw new IllegalArgumentException("eval must not be null");
+               }
                if (eval instanceof AreaEval) {
                        return CountUtils.countMatchingCellsInArea((AreaEval) eval, criteriaPredicate);
                }
index 7aba5db72af837f8b7b355927669c6cf13553e19..4b066b8226ae88031a16c22e8f19433ad998d66d 100644 (file)
@@ -1,28 +1,28 @@
-/*
-* 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.
-*/
-/*
- * Created on Nov 25, 2006
- *
- */
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
 package org.apache.poi.hssf.record.formula.functions;
 
 import org.apache.poi.hssf.record.formula.eval.BoolEval;
 import org.apache.poi.hssf.record.formula.eval.ErrorEval;
 import org.apache.poi.hssf.record.formula.eval.Eval;
+import org.apache.poi.hssf.record.formula.eval.EvaluationException;
+import org.apache.poi.hssf.record.formula.eval.OperandResolver;
+import org.apache.poi.hssf.record.formula.eval.ValueEval;
 
 /**
  * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
@@ -30,20 +30,37 @@ import org.apache.poi.hssf.record.formula.eval.Eval;
  */
 public final class If implements Function {
 
-    public Eval evaluate(Eval[] args, int srcCellRow, short srcCellCol) {
+       public Eval evaluate(Eval[] args, int srcCellRow, short srcCellCol) {
+               Eval falseResult;
+               switch (args.length) {
+                       case 3:
+                               falseResult = args[2];
+                               break;
+                       case 2:
+                               falseResult = BoolEval.FALSE;
+                               break;
+                       default:
+                               return ErrorEval.VALUE_INVALID;
+               }
+               boolean b;
+               try {
+                       b = evaluateFirstArg(args[0], srcCellRow, srcCellCol);
+               } catch (EvaluationException e) {
+                       return e.getErrorEval();
+               }
+               if (b) {
+                       return args[1];
+               }
+               return falseResult;
+       }
 
-        Eval evalWhenFalse = BoolEval.FALSE;
-        switch (args.length) {
-        case 3:
-            evalWhenFalse = args[2];
-        case 2:
-            BoolEval beval = (BoolEval) args[0]; // TODO - class cast exception
-            if (beval.getBooleanValue()) {
-                return args[1];
-            }
-            return evalWhenFalse;
-        default:
-            return ErrorEval.VALUE_INVALID;
-        }
-    }
+       private static boolean evaluateFirstArg(Eval arg, int srcCellRow, short srcCellCol)
+                       throws EvaluationException {
+               ValueEval ve = OperandResolver.getSingleValue(arg, srcCellRow, srcCellCol);
+               Boolean b = OperandResolver.coerceValueToBoolean(ve, false);
+               if (b == null) {
+                       return false;
+               }
+               return b.booleanValue();
+       }
 }
index aebf6aab0d4843ab3b0b88f7aa1b2238e163123a..3c93c0846bdab7b908876774d4d8fde4a2fd4d80 100644 (file)
@@ -1,28 +1,28 @@
-/*
-* 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.
-*/
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
 
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
 
 package org.apache.poi.hssf.record.formula.functions;
 
 import org.apache.poi.hssf.record.formula.eval.AreaEval;
 import org.apache.poi.hssf.record.formula.eval.ErrorEval;
 import org.apache.poi.hssf.record.formula.eval.Eval;
-import org.apache.poi.hssf.record.formula.eval.NumberEval;
-import org.apache.poi.hssf.record.formula.eval.RefEval;
+import org.apache.poi.hssf.record.formula.eval.EvaluationException;
+import org.apache.poi.hssf.record.formula.eval.OperandResolver;
+import org.apache.poi.hssf.record.formula.eval.ValueEval;
 
 /**
  * Implementation for the Excel function INDEX<p/>
@@ -51,15 +51,23 @@ public final class Index implements Function {
                        return ErrorEval.VALUE_INVALID;
                }
                Eval firstArg = args[0];
-               if(firstArg instanceof AreaEval) {
-                       AreaEval reference = (AreaEval) firstArg;
+               if(!(firstArg instanceof AreaEval)) {
+                       
+                       // else the other variation of this function takes an array as the first argument
+                       // it seems like interface 'ArrayEval' does not even exist yet
                        
-                       int rowIx = 0;
-                       int columnIx = 0;
-                       int areaIx = 0;
+                       throw new RuntimeException("Incomplete code - cannot handle first arg of type ("
+                                       + firstArg.getClass().getName() + ")");
+               }
+               AreaEval reference = (AreaEval) firstArg;
+               
+               int rowIx = 0;
+               int columnIx = 0;
+               int areaIx = 0;
+               try {   
                        switch(nArgs) {
                                case 4:
-                                       areaIx = convertIndexArgToZeroBase(args[3]);
+                                       areaIx = convertIndexArgToZeroBase(args[3], srcCellRow, srcCellCol);
                                        throw new RuntimeException("Incomplete code" +
                                                        " - don't know how to support the 'area_num' parameter yet)");
                                        // Excel expression might look like this "INDEX( (A1:B4, C3:D6, D2:E5 ), 1, 2, 3)
@@ -68,41 +76,41 @@ public final class Index implements Function {
                                        // The formula parser doesn't seem to support this yet. Not sure if the evaluator does either
                                        
                                case 3:
-                                       columnIx = convertIndexArgToZeroBase(args[2]);
+                                       columnIx = convertIndexArgToZeroBase(args[2], srcCellRow, srcCellCol);
                                case 2:
-                                       rowIx = convertIndexArgToZeroBase(args[1]);
+                                       rowIx = convertIndexArgToZeroBase(args[1], srcCellRow, srcCellCol);
                                        break;
                                default:
                                        // too many arguments
                                        return ErrorEval.VALUE_INVALID;
                        }
-                       
-               int nColumns = reference.getLastColumn()-reference.getFirstColumn()+1;
-                       int index = rowIx * nColumns + columnIx;
-                       
-                       return reference.getValues()[index];
+                       return getValueFromArea(reference, rowIx, columnIx);
+               } catch (EvaluationException e) {
+                       return e.getErrorEval();
                }
-               
-               // else the other variation of this function takes an array as the first argument
-               // it seems like interface 'ArrayEval' does not even exist yet
-               
-               throw new RuntimeException("Incomplete code - cannot handle first arg of type ("
-                               + firstArg.getClass().getName() + ")");
        }
        
+       private static ValueEval getValueFromArea(AreaEval ae, int rowIx, int columnIx) throws EvaluationException {
+               int width = ae.getWidth();
+               int height = ae.getHeight();
+               
+               // Slightly irregular logic for bounds checking errors
+               if (rowIx >= height || columnIx >= width) {
+                       throw new EvaluationException(ErrorEval.REF_INVALID);
+               }
+               if (rowIx < 0 || columnIx < 0) {
+                       throw new EvaluationException(ErrorEval.VALUE_INVALID);
+               }
+               return ae.getRelativeValue(rowIx, columnIx);
+       }
+
        /**
         * takes a NumberEval representing a 1-based index and returns the zero-based int value
         */
-       private static int convertIndexArgToZeroBase(Eval ev) {
-               NumberEval ne;
-               if(ev instanceof RefEval) {
-                       // TODO - write junit to justify this
-                       RefEval re = (RefEval) ev;
-                       ne = (NumberEval) re.getInnerValueEval();
-               } else {
-                       ne = (NumberEval)ev;
-               }
+       private static int convertIndexArgToZeroBase(Eval arg, int srcCellRow, short srcCellCol) throws EvaluationException {
                
-               return (int)ne.getNumberValue() - 1;
+               ValueEval ev = OperandResolver.getSingleValue(arg, srcCellRow, srcCellCol);
+               int oneBasedVal = OperandResolver.coerceValueToInt(ev);
+               return oneBasedVal - 1;
        }
 }
index e8c083dc5a65ece2c1332bd93d50cf37fdc75570..e6a3ec81c2f23edd79186b13d8ccbe0869ba031f 100644 (file)
@@ -17,8 +17,6 @@
 
 package org.apache.poi.hssf.record.formula.functions;
 
-import org.apache.poi.hssf.record.formula.AreaPtg;
-import org.apache.poi.hssf.record.formula.eval.Area2DEval;
 import org.apache.poi.hssf.record.formula.eval.AreaEval;
 import org.apache.poi.hssf.record.formula.eval.BlankEval;
 import org.apache.poi.hssf.record.formula.eval.BoolEval;
@@ -366,13 +364,7 @@ final class LookupUtils {
                        // Make this cell ref look like a 1x1 area ref.
 
                        // It doesn't matter if eval is a 2D or 3D ref, because that detail is never asked of AreaEval.
-                       // This code only requires the value array item.
-                       // anything would be ok for rowIx and colIx, but may as well get it right.
-                       int rowIx = refEval.getRow();
-                       int colIx = refEval.getColumn();
-                       AreaPtg ap = new AreaPtg(rowIx, rowIx, colIx, colIx, false, false, false, false);
-                       ValueEval value = refEval.getInnerValueEval();
-                       return new Area2DEval(ap, new ValueEval[] { value, });
+                       return refEval.offset(0, 0, 0, 0);
                }
                throw EvaluationException.invalidValue();
        }
index 593998f1e9da19d62a7d3eb25e90f0725cdfcec9..311707665ea7e07e433426bde3e21bb733352ada 100644 (file)
@@ -455,85 +455,6 @@ public final class MathX {
         return d;
     }
     
-    /**
-     * returns the sum of difference of squares of corresponding double 
-     * value in each subarray: ie. sigma (xarr[i]^2-yarr[i]^2) 
-     * <br/>
-     * It is the responsibility of the caller 
-     * to ensure that the two subarrays are of equal length. If the 
-     * subarrays are not of equal length, the return value can be 
-     * unpredictable.
-     * @param xarr
-     * @param yarr
-     */
-    public static double sumx2my2(double[] xarr, double[] yarr) {
-        double d = 0;
-        
-        try {
-            for (int i=0, iSize=xarr.length; i<iSize; i++) {
-                d += (xarr[i] + yarr[i]) * (xarr[i] - yarr[i]);
-            }            
-        }
-        catch (ArrayIndexOutOfBoundsException ae) {
-            d = Double.NaN;
-        }
-        
-        return d;
-    }
-    
-    /**
-     * returns the sum of sum of squares of corresponding double 
-     * value in each subarray: ie. sigma (xarr[i]^2 + yarr[i]^2) 
-     * <br/>
-     * It is the responsibility of the caller 
-     * to ensure that the two subarrays are of equal length. If the 
-     * subarrays are not of equal length, the return value can be 
-     * unpredictable.
-     * @param xarr
-     * @param yarr
-     */
-    public static double sumx2py2(double[] xarr, double[] yarr) {
-        double d = 0;
-        
-        try {
-            for (int i=0, iSize=xarr.length; i<iSize; i++) {
-                d += (xarr[i] * xarr[i]) + (yarr[i] * yarr[i]);
-            }            
-        }
-        catch (ArrayIndexOutOfBoundsException ae) {
-            d = Double.NaN;
-        }
-        
-        return d;
-    }
-    
-
-    /**
-     * returns the sum of squares of difference of corresponding double 
-     * value in each subarray: ie. sigma ( (xarr[i]-yarr[i])^2 ) 
-     * <br/>
-     * It is the responsibility of the caller 
-     * to ensure that the two subarrays are of equal length. If the 
-     * subarrays are not of equal length, the return value can be 
-     * unpredictable.
-     * @param xarr
-     * @param yarr
-     */
-    public static double sumxmy2(double[] xarr, double[] yarr) {
-        double d = 0;
-        
-        try {
-            for (int i=0, iSize=xarr.length; i<iSize; i++) {
-                double t = (xarr[i] - yarr[i]);
-                d += t * t;
-            }            
-        }
-        catch (ArrayIndexOutOfBoundsException ae) {
-            d = Double.NaN;
-        }
-        
-        return d;
-    }
     
     /**
      * returns the total number of combinations possible when
index 0e7cce217e2ebc04e07c99e891ade018e83afb6e..a9e98ae313087f229d2b05da82d58b3b64ff84b8 100644 (file)
@@ -126,30 +126,34 @@ public abstract class MultiOperandNumericFunction extends NumericFunction {
         
         if (operand instanceof AreaEval) {
             AreaEval ae = (AreaEval) operand;
-            ValueEval[] values = ae.getValues();
             DoubleList retval = new DoubleList();
-            for (int j=0, jSize=values.length; j<jSize; j++) {
-                /*
-                 * TODO: For an AreaEval, we are constructing a RefEval
-                 * per element.
-                 * For now this is a tempfix solution since this may
-                 * require a more generic fix at the level of
-                 * HSSFFormulaEvaluator where we store an array
-                 * of RefEvals as the "values" array. 
-                 */
-                RefEval re = new Ref2DEval(null, values[j]);
-                ValueEval ve = singleOperandEvaluate(re, srcRow, srcCol);
-                
-                if (ve instanceof NumericValueEval) {
-                    NumericValueEval nve = (NumericValueEval) ve;
-                    retval.add(nve.getNumberValue());
-                }
-                else if (ve instanceof BlankEval) {
-                    // note - blanks are ignored, so returned array will be smaller.
-                } 
-                else {
-                    return null; // indicate to calling subclass that error occurred
-                }
+            int width = ae.getWidth();
+               int height = ae.getHeight();
+               for (int rrIx=0; rrIx<height; rrIx++) {
+                       for (int rcIx=0; rcIx<width; rcIx++) {
+                               ValueEval ve1 = ae.getRelativeValue(rrIx, rcIx);
+                     /*
+                     * TODO: For an AreaEval, we are constructing a RefEval
+                     * per element.
+                     * For now this is a tempfix solution since this may
+                     * require a more generic fix at the level of
+                     * HSSFFormulaEvaluator where we store an array
+                     * of RefEvals as the "values" array. 
+                     */
+                    RefEval re = new Ref2DEval(null, ve1);
+                    ValueEval ve = singleOperandEvaluate(re, srcRow, srcCol);
+                    
+                    if (ve instanceof NumericValueEval) {
+                        NumericValueEval nve = (NumericValueEval) ve;
+                        retval.add(nve.getNumberValue());
+                    }
+                    else if (ve instanceof BlankEval) {
+                        // note - blanks are ignored, so returned array will be smaller.
+                    } 
+                    else {
+                        return null; // indicate to calling subclass that error occurred
+                    }
+                       }
             }
             return retval.toArray();
         }
index 08bdf3d64c12b0c7495657aec2ab9cdab3f2b8fc..086596ae21ac83543ca87436fb46f121cdf4b160 100644 (file)
@@ -1,26 +1,22 @@
-/*
-* 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.
-*/
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
 
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
 
 package org.apache.poi.hssf.record.formula.functions;
 
-import org.apache.poi.hssf.record.formula.Area3DPtg;
-import org.apache.poi.hssf.record.formula.AreaPtg;
-import org.apache.poi.hssf.record.formula.eval.Area3DEval;
 import org.apache.poi.hssf.record.formula.eval.AreaEval;
 import org.apache.poi.hssf.record.formula.eval.BoolEval;
 import org.apache.poi.hssf.record.formula.eval.ErrorEval;
@@ -28,13 +24,9 @@ import org.apache.poi.hssf.record.formula.eval.Eval;
 import org.apache.poi.hssf.record.formula.eval.EvaluationException;
 import org.apache.poi.hssf.record.formula.eval.NumericValueEval;
 import org.apache.poi.hssf.record.formula.eval.OperandResolver;
-import org.apache.poi.hssf.record.formula.eval.Ref3DEval;
 import org.apache.poi.hssf.record.formula.eval.RefEval;
 import org.apache.poi.hssf.record.formula.eval.StringEval;
 import org.apache.poi.hssf.record.formula.eval.ValueEval;
-import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
-import org.apache.poi.ss.usermodel.Sheet;
-import org.apache.poi.ss.usermodel.Workbook;
 /**
  * Implementation for Excel function OFFSET()<p/>
  * 
@@ -51,7 +43,7 @@ import org.apache.poi.ss.usermodel.Workbook;
  * 
  * @author Josh Micich
  */
-public final class Offset implements FreeRefFunction {
+public final class Offset implements Function {
        // These values are specific to BIFF8
        private static final int LAST_VALID_ROW_INDEX = 0xFFFF;
        private static final int LAST_VALID_COLUMN_INDEX = 0xFF;
@@ -125,37 +117,29 @@ public final class Offset implements FreeRefFunction {
         * Encapsulates either an area or cell reference which may be 2d or 3d.
         */
        private static final class BaseRef {
-               private static final int INVALID_SHEET_INDEX = -1;
                private final int _firstRowIndex;
                private final int _firstColumnIndex;
                private final int _width;
                private final int _height;
-               private final int _externalSheetIndex;
+               private final RefEval _refEval;
+               private final AreaEval _areaEval;
                
                public BaseRef(RefEval re) {
+                       _refEval = re;
+                       _areaEval = null;
                        _firstRowIndex = re.getRow();
                        _firstColumnIndex = re.getColumn();
                        _height = 1;
                        _width = 1;
-                       if (re instanceof Ref3DEval) {
-                               Ref3DEval r3e = (Ref3DEval) re;
-                               _externalSheetIndex = r3e.getExternSheetIndex();
-                       } else {
-                               _externalSheetIndex = INVALID_SHEET_INDEX;
-                       }
                }
 
                public BaseRef(AreaEval ae) {
+                       _refEval = null;
+                       _areaEval = ae;
                        _firstRowIndex = ae.getFirstRow();
                        _firstColumnIndex = ae.getFirstColumn();
                        _height = ae.getLastRow() - ae.getFirstRow() + 1;
                        _width = ae.getLastColumn() - ae.getFirstColumn() + 1;
-                       if (ae instanceof Area3DEval) {
-                               Area3DEval a3e = (Area3DEval) ae;
-                               _externalSheetIndex = a3e.getExternSheetIndex();
-                       } else {
-                               _externalSheetIndex = INVALID_SHEET_INDEX;
-                       }
                }
 
                public int getWidth() {
@@ -170,20 +154,17 @@ public final class Offset implements FreeRefFunction {
                public int getFirstColumnIndex() {
                        return _firstColumnIndex;
                }
-               public boolean isIs3d() {
-                       return _externalSheetIndex > 0;
-               }
 
-               public short getExternalSheetIndex() {
-                       if(_externalSheetIndex < 0) {
-                               throw new IllegalStateException("external sheet index only available for 3d refs");
+               public AreaEval offset(int relFirstRowIx, int relLastRowIx, 
+                               int relFirstColIx, int relLastColIx) {
+                       if (_refEval == null) {
+                               return _areaEval.offset(relFirstRowIx, relLastRowIx, relFirstColIx, relLastColIx);
                        }
-                       return (short) _externalSheetIndex;
+                       return _refEval.offset(relFirstRowIx, relLastRowIx, relFirstColIx, relLastColIx);
                }
        }
        
-       public ValueEval evaluate(Eval[] args, int srcCellRow, short srcCellCol, Workbook workbook, Sheet sheet) {
-               
+       public Eval evaluate(Eval[] args, int srcCellRow, short srcCellCol) {
                if(args.length < 3 || args.length > 5) {
                        return ErrorEval.VALUE_INVALID;
                }
@@ -206,37 +187,24 @@ public final class Offset implements FreeRefFunction {
                        }
                        LinearOffsetRange rowOffsetRange = new LinearOffsetRange(rowOffset, height);
                        LinearOffsetRange colOffsetRange = new LinearOffsetRange(columnOffset, width);
-                       return createOffset(baseRef, rowOffsetRange, colOffsetRange, workbook, sheet);
+                       return createOffset(baseRef, rowOffsetRange, colOffsetRange);
                } catch (EvaluationException e) {
                        return e.getErrorEval();
                }
        }
 
        private static AreaEval createOffset(BaseRef baseRef, 
-                       LinearOffsetRange rowOffsetRange, LinearOffsetRange colOffsetRange, 
-                       Workbook workbook, Sheet sheet) throws EvaluationException {
-
-               LinearOffsetRange rows = rowOffsetRange.normaliseAndTranslate(baseRef.getFirstRowIndex());
-               LinearOffsetRange cols = colOffsetRange.normaliseAndTranslate(baseRef.getFirstColumnIndex());
+                       LinearOffsetRange orRow, LinearOffsetRange orCol) throws EvaluationException {
+               LinearOffsetRange absRows = orRow.normaliseAndTranslate(baseRef.getFirstRowIndex());
+               LinearOffsetRange absCols = orCol.normaliseAndTranslate(baseRef.getFirstColumnIndex());
                
-               if(rows.isOutOfBounds(0, LAST_VALID_ROW_INDEX)) {
+               if(absRows.isOutOfBounds(0, LAST_VALID_ROW_INDEX)) {
                        throw new EvaluationException(ErrorEval.REF_INVALID);
                }
-               if(cols.isOutOfBounds(0, LAST_VALID_COLUMN_INDEX)) {
+               if(absCols.isOutOfBounds(0, LAST_VALID_COLUMN_INDEX)) {
                        throw new EvaluationException(ErrorEval.REF_INVALID);
                }
-               if(baseRef.isIs3d()) {
-                       Area3DPtg a3dp = new Area3DPtg(rows.getFirstIndex(), rows.getLastIndex(), 
-                                       cols.getFirstIndex(), cols.getLastIndex(),
-                                       false, false, false, false,
-                                       baseRef.getExternalSheetIndex());
-                       return HSSFFormulaEvaluator.evaluateArea3dPtg(workbook, a3dp);
-               }
-               
-               AreaPtg ap = new AreaPtg(rows.getFirstIndex(), rows.getLastIndex(), 
-                               cols.getFirstIndex(), cols.getLastIndex(),
-                               false, false, false, false);
-               return HSSFFormulaEvaluator.evaluateAreaPtg(sheet, workbook, ap);
+               return baseRef.offset(orRow.getFirstIndex(), orRow.getLastIndex(), orCol.getFirstIndex(), orCol.getLastIndex());
        }
 
        private static BaseRef evaluateBaseRef(Eval eval) throws EvaluationException {
index 30ad5ec2303ee70347d5da2cd219d97a2bc17884..4dedf26574859fdef3f26b4a0c5138f4ff685aa7 100644 (file)
@@ -1,22 +1,23 @@
-/*
-* 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.
-*/
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
 
 package org.apache.poi.hssf.record.formula.functions;
 
+
 /**
  * Implementation of Excel function SUMX2MY2()<p/>
  * 
@@ -30,7 +31,13 @@ package org.apache.poi.hssf.record.formula.functions;
  */
 public final class Sumx2my2 extends XYNumericFunction {
 
-    protected double evaluate(double[] xArray, double[] yArray) {
-       return MathX.sumx2my2(xArray, yArray);
-    }
+       private static final Accumulator XSquaredMinusYSquaredAccumulator = new Accumulator() {
+               public double accumulate(double x, double y) {
+                       return x * x - y * y;
+               }
+       };
+
+       protected Accumulator createAccumulator() {
+               return XSquaredMinusYSquaredAccumulator;
+       }
 }
index dfd730d12cd347b378de777bef046097f7888d94..c3af0bd3802b8b71c0b1f8277bf64f453fb1cfed 100644 (file)
@@ -1,22 +1,23 @@
-/*
-* 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.
-*/
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
 
 package org.apache.poi.hssf.record.formula.functions;
 
+
 /**
  * Implementation of Excel function SUMX2PY2()<p/>
  * 
@@ -30,7 +31,13 @@ package org.apache.poi.hssf.record.formula.functions;
  */
 public final class Sumx2py2 extends XYNumericFunction {
 
-    protected double evaluate(double[] xArray, double[] yArray) {
-       return MathX.sumx2py2(xArray, yArray);
-    }
+       private static final Accumulator XSquaredPlusYSquaredAccumulator = new Accumulator() {
+               public double accumulate(double x, double y) {
+                       return x * x + y * y;
+               }
+       };
+
+       protected Accumulator createAccumulator() {
+               return XSquaredPlusYSquaredAccumulator;
+       }
 }
index a1b2fec9b2854ebd5910db2e3d1bad7ca9b09f6a..4fa11e36ba77ab9f658abc71fb9f1f5bc38cb9dc 100644 (file)
@@ -1,19 +1,19 @@
-/*
-* 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.
-*/
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
 
 package org.apache.poi.hssf.record.formula.functions;
 
@@ -30,7 +30,14 @@ package org.apache.poi.hssf.record.formula.functions;
  */
 public final class Sumxmy2 extends XYNumericFunction {
 
-    protected double evaluate(double[] xArray, double[] yArray) {
-       return MathX.sumxmy2(xArray, yArray);
-    }
+       private static final Accumulator XMinusYSquaredAccumulator = new Accumulator() {
+               public double accumulate(double x, double y) {
+                       double xmy = x - y;
+                       return xmy * xmy;
+               }
+       };
+
+       protected Accumulator createAccumulator() {
+               return XMinusYSquaredAccumulator;
+       }
 }
index b989c33a26790fdbdab30d815aaf7bcd614009f3..1d83b363fda3fe5169a409f2cdc8c4a4c5f94481 100644 (file)
@@ -1,19 +1,19 @@
-/*
-* 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.
-*/
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
 
 package org.apache.poi.hssf.record.formula.functions;
 
@@ -24,180 +24,162 @@ import org.apache.poi.hssf.record.formula.eval.EvaluationException;
 import org.apache.poi.hssf.record.formula.eval.NumberEval;
 import org.apache.poi.hssf.record.formula.eval.RefEval;
 import org.apache.poi.hssf.record.formula.eval.ValueEval;
+import org.apache.poi.hssf.record.formula.functions.LookupUtils.ValueVector;
 
 /**
  * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
- *
+ * 
  */
 public abstract class XYNumericFunction implements Function {
-    protected static final int X = 0;
-    protected static final int Y = 1;
-    
-    protected static final class DoubleArrayPair {
 
-               private final double[] _xArray;
-               private final double[] _yArray;
+       private static abstract class ValueArray implements ValueVector {
+               private final int _size;
+               protected ValueArray(int size) {
+                       _size = size;
+               }
+               public ValueEval getItem(int index) {
+                       if (index < 0 || index > _size) {
+                               throw new IllegalArgumentException("Specified index " + index
+                                               + " is outside range (0.." + (_size - 1) + ")");
+                       }
+                       return getItemInternal(index);
+               }
+               protected abstract ValueEval getItemInternal(int index);
+               public final int getSize() {
+                       return _size;
+               }
+       }
 
-               public DoubleArrayPair(double[] xArray, double[] yArray) {
-                       _xArray = xArray;
-                       _yArray = yArray;
+       private static final class SingleCellValueArray extends ValueArray {
+               private final ValueEval _value;
+               public SingleCellValueArray(ValueEval value) {
+                       super(1);
+                       _value = value;
                }
-               public double[] getXArray() {
-                       return _xArray;
+               protected ValueEval getItemInternal(int index) {
+                       return _value;
+               }
+       }
+
+       private static final class RefValueArray extends ValueArray {
+               private final RefEval _ref;
+               public RefValueArray(RefEval ref) {
+                       super(1);
+                       _ref = ref;
                }
-               public double[] getYArray() {
-                       return _yArray;
+               protected ValueEval getItemInternal(int index) {
+                       return _ref.getInnerValueEval();
                }
-    }
+       }
 
+       private static final class AreaValueArray extends ValueArray {
+               private final AreaEval _ae;
+               private final int _width;
+
+               public AreaValueArray(AreaEval ae) {
+                       super(ae.getWidth() * ae.getHeight());
+                       _ae = ae;
+                       _width = ae.getWidth();
+               }
+               protected ValueEval getItemInternal(int index) {
+                       int rowIx = index / _width;
+                       int colIx = index % _width;
+                       return _ae.getRelativeValue(rowIx, colIx);
+               }
+       }
+
+       protected static interface Accumulator {
+               double accumulate(double x, double y);
+       }
+
+       /**
+        * Constructs a new instance of the Accumulator used to calculated this function
+        */
+       protected abstract Accumulator createAccumulator();
+
+       public final Eval evaluate(Eval[] args, int srcCellRow, short srcCellCol) {
+               if (args.length != 2) {
+                       return ErrorEval.VALUE_INVALID;
+               }
 
-    public final Eval evaluate(Eval[] args, int srcCellRow, short srcCellCol) {
-       if(args.length != 2) {
-               return ErrorEval.VALUE_INVALID;
-       }
-       
-        double[][] values;
+               double result;
                try {
-                       values = getValues(args[0], args[1]);
+                       ValueVector vvX = createValueVector(args[0]);
+                       ValueVector vvY = createValueVector(args[1]);
+                       int size = vvX.getSize();
+                       if (size == 0 || vvY.getSize() != size) {
+                               return ErrorEval.NA;
+                       }
+                       result = evaluateInternal(vvX, vvY, size);
                } catch (EvaluationException e) {
                        return e.getErrorEval();
                }
-        if (values==null 
-                || values[X] == null || values[Y] == null
-                || values[X].length == 0 || values[Y].length == 0
-                || values[X].length != values[Y].length) {
-            return ErrorEval.VALUE_INVALID;
-        }
-        
-        double d = evaluate(values[X], values[Y]);
-        if (Double.isNaN(d) || Double.isInfinite(d)) {
+               if (Double.isNaN(result) || Double.isInfinite(result)) {
                        return ErrorEval.NUM_ERROR;
                }
-               return new NumberEval(d);
-    }    
-    protected abstract double evaluate(double[] xArray, double[] yArray);
-
-    /**
-     * Returns a double array that contains values for the numeric cells
-     * from among the list of operands. Blanks and Blank equivalent cells
-     * are ignored. Error operands or cells containing operands of type
-     * that are considered invalid and would result in #VALUE! error in 
-     * excel cause this function to return null.
-     */
-    private static double[][] getNumberArray(Eval[] xops, Eval[] yops) throws EvaluationException {
-       
-       // check for errors first: size mismatch, value errors in x, value errors in y
-       
-       int nArrayItems = xops.length;
-               if(nArrayItems != yops.length) {
-               throw new EvaluationException(ErrorEval.NA);
-       }
-               for (int i = 0; i < xops.length; i++) {
-                       Eval eval = xops[i];
-                       if (eval instanceof ErrorEval) {
-                               throw new EvaluationException((ErrorEval) eval);
+               return new NumberEval(result);
+       }
+
+       private double evaluateInternal(ValueVector x, ValueVector y, int size)
+                       throws EvaluationException {
+               Accumulator acc = createAccumulator();
+
+               // error handling is as if the x is fully evaluated before y
+               ErrorEval firstXerr = null;
+               ErrorEval firstYerr = null;
+               boolean accumlatedSome = false;
+               double result = 0.0;
+
+               for (int i = 0; i < size; i++) {
+                       ValueEval vx = x.getItem(i);
+                       ValueEval vy = y.getItem(i);
+                       if (vx instanceof ErrorEval) {
+                               if (firstXerr == null) {
+                                       firstXerr = (ErrorEval) vx;
+                                       continue;
+                               }
                        }
-               }
-               for (int i = 0; i < yops.length; i++) {
-                       Eval eval = yops[i];
-                       if (eval instanceof ErrorEval) {
-                               throw new EvaluationException((ErrorEval) eval);
+                       if (vy instanceof ErrorEval) {
+                               if (firstYerr == null) {
+                                       firstYerr = (ErrorEval) vy;
+                                       continue;
+                               }
+                       }
+                       // only count pairs if both elements are numbers
+                       if (vx instanceof NumberEval && vy instanceof NumberEval) {
+                               accumlatedSome = true;
+                               NumberEval nx = (NumberEval) vx;
+                               NumberEval ny = (NumberEval) vy;
+                               result += acc.accumulate(nx.getNumberValue(), ny.getNumberValue());
+                       } else {
+                               // all other combinations of value types are silently ignored
                        }
                }
-               
-        double[] xResult = new double[nArrayItems];
-        double[] yResult = new double[nArrayItems];
-       
-        int count = 0;
-        
-               for (int i=0, iSize=nArrayItems; i<iSize; i++) {
-                   Eval xEval = xops[i];
-                   Eval yEval = yops[i];
-                   
-                   if (isNumberEval(xEval) && isNumberEval(yEval)) {
-                       xResult[count] = getDoubleValue(xEval);
-                       yResult[count] = getDoubleValue(yEval);
-                       if (Double.isNaN(xResult[count]) || Double.isNaN(xResult[count])) {
-                           throw new EvaluationException(ErrorEval.NUM_ERROR);
-                       }
-                       count++;
-                   }
-               }
-        
-               return new double[][] {
-               trimToSize(xResult, count),
-            trimToSize(yResult, count),
-               };
-    }
-    
-    private static double[][] getValues(Eval argX, Eval argY) throws EvaluationException {
-       
-       if (argX instanceof ErrorEval) {
-                       throw new EvaluationException((ErrorEval) argX);
-               }
-       if (argY instanceof ErrorEval) {
-                       throw new EvaluationException((ErrorEval) argY);
-               }
-       
-        Eval[] xEvals;
-               Eval[] yEvals;
-               if (argX instanceof AreaEval) {
-                   AreaEval ae = (AreaEval) argX;
-                   xEvals = ae.getValues();
-               } else {
-                   xEvals = new Eval[] { argX, };
-               }
-               
-               if (argY instanceof AreaEval) {
-                   AreaEval ae = (AreaEval) argY;
-                   yEvals = ae.getValues();
-               } else {
-                   yEvals = new Eval[] { argY, };
-               }
-               
-               return getNumberArray(xEvals, yEvals);
-    }
-    
-    private static double[] trimToSize(double[] arr, int len) {
-        double[] tarr = arr;
-        if (arr.length > len) {
-            tarr = new double[len];
-            System.arraycopy(arr, 0, tarr, 0, len);
-        }
-        return tarr;
-    }
-    
-    private static boolean isNumberEval(Eval eval) {
-        boolean retval = false;
-        
-        if (eval instanceof NumberEval) {
-            retval = true;
-        }
-        else if (eval instanceof RefEval) {
-            RefEval re = (RefEval) eval;
-            ValueEval ve = re.getInnerValueEval();
-            retval = (ve instanceof NumberEval);
-        }
-        
-        return retval;
-    }
-    
-    private static double getDoubleValue(Eval eval) {
-        double retval = 0;
-        if (eval instanceof NumberEval) {
-            NumberEval ne = (NumberEval) eval;
-            retval = ne.getNumberValue();
-        }
-        else if (eval instanceof RefEval) {
-            RefEval re = (RefEval) eval;
-            ValueEval ve = re.getInnerValueEval();
-                retval = (ve instanceof NumberEval)
-                    ? ((NumberEval) ve).getNumberValue()
-                    : Double.NaN;
-        }
-        else if (eval instanceof ErrorEval) {
-            retval = Double.NaN;
-        }
-        return retval;
-    }
+               if (firstXerr != null) {
+                       throw new EvaluationException(firstXerr);
+               }
+               if (firstYerr != null) {
+                       throw new EvaluationException(firstYerr);
+               }
+               if (!accumlatedSome) {
+                       throw new EvaluationException(ErrorEval.DIV_ZERO);
+               }
+               return result;
+       }
+
+       private static ValueVector createValueVector(Eval arg) throws EvaluationException {
+               if (arg instanceof ErrorEval) {
+                       throw new EvaluationException((ErrorEval) arg);
+               }
+               if (arg instanceof AreaEval) {
+                       return new AreaValueArray((AreaEval) arg);
+               }
+               if (arg instanceof RefEval) {
+                       return new RefValueArray((RefEval) arg);
+               }
+               if (arg instanceof ValueEval) {
+                       return new SingleCellValueArray((ValueEval) arg);
+               }
+               throw new RuntimeException("Unexpected eval class (" + arg.getClass().getName() + ")");
+       }
 }
index 97e605928dc75b0a299c7445f2c5a6b498b0a5f1..4fb31606eaf9c8a51dbf1dd87357d7a959c3ce28 100644 (file)
@@ -43,19 +43,11 @@ public class HSSFFormulaEvaluator extends FormulaEvaluator {
         return new FormulaParser(formula, workbook);
     }
     
-
     /**
      * debug method
-     * 
-     * @param formula
-     * @param sheet
-     * @param workbook
      */
     void inspectPtgs(String formula) {
-       HSSFWorkbook hssfWb = (HSSFWorkbook)_workbook;
-        FormulaParser fp = new FormulaParser(formula, hssfWb);
-        fp.parse();
-        Ptg[] ptgs = fp.getRPNPtg();
+        Ptg[] ptgs = FormulaParser.parse(formula, _workbook);
         System.out.println("<ptg-group>");
         for (int i = 0, iSize = ptgs.length; i < iSize; i++) {
             System.out.println("<ptg>");
index 280284439b267b6b70762cd985be2a3e47824386..6670b20414c7651064f38231a5d118544042743b 100644 (file)
@@ -35,17 +35,11 @@ import org.apache.poi.hssf.model.FormulaParser;
 import org.apache.poi.hssf.model.Sheet;
 import org.apache.poi.hssf.model.Workbook;
 import org.apache.poi.hssf.record.CellValueRecordInterface;
-import org.apache.poi.hssf.record.CFRuleRecord;
-import org.apache.poi.hssf.record.DVALRecord;
 import org.apache.poi.hssf.record.DVRecord;
-import org.apache.poi.hssf.record.EOFRecord;
 import org.apache.poi.hssf.record.EscherAggregate;
-import org.apache.poi.hssf.record.HCenterRecord;
-import org.apache.poi.hssf.record.PageBreakRecord;
 import org.apache.poi.hssf.record.Record;
 import org.apache.poi.hssf.record.RowRecord;
 import org.apache.poi.hssf.record.SCLRecord;
-import org.apache.poi.hssf.record.VCenterRecord;
 import org.apache.poi.hssf.record.WSBoolRecord;
 import org.apache.poi.hssf.record.WindowTwoRecord;
 import org.apache.poi.hssf.record.aggregates.DataValidityTable;
@@ -385,6 +379,22 @@ public class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet
        DVRecord dvRecord = dataValidation.createDVRecord(workbook);
        dvt.addDataValidation(dvRecord);
     }
+    
+    /**
+     * Get the DVRecords objects that are associated to this sheet
+     * @return a list of DVRecord instances
+     */
+    public List getDVRecords() {
+        List dvRecords = new ArrayList();
+        List records = sheet.getRecords();
+        
+        for(int index=0; index<records.size(); index++) {
+           if(records.get(index) instanceof DVRecord) {
+                  dvRecords.add(records.get(index));
+           }
+        }
+        return dvRecords;
+    }
 
 
     /**
@@ -1273,11 +1283,9 @@ public class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet
                     // Since it's a formula cell, process the
                     //  formula string, and look to see if
                     //  it contains any references
-                    FormulaParser fp = new FormulaParser(c.getCellFormula(), workbook);
-                    fp.parse();
 
                     // Look for references, and update if needed
-                    Ptg[] ptgs = fp.getRPNPtg();
+                    Ptg[] ptgs = FormulaParser.parse(c.getCellFormula(), workbook);
                     boolean changed = false;
                     for(int i=0; i<ptgs.length; i++) {
                         if(ptgs[i] instanceof RefPtg) {
@@ -1294,7 +1302,7 @@ public class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet
                     //  re-create the formula string
                     if(changed) {
                         c.setCellFormula(
-                                fp.toFormulaString(ptgs)
+                             FormulaParser.toFormulaString(workbook, ptgs)
                         );
                     }
                 }
index eb1546ade914384c0b24b89d06934ef378584278..801b29878323b6dc8bf19fb64db3a02eb6a6a9a9 100644 (file)
@@ -931,35 +931,17 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
         Stack ptgs = new Stack();
 
         if (settingRowAndColumn) {
-            final int exprsSize = 2 * 11 + 1; // Area3DPtg.SIZE + UnionPtg.SIZE
+            final int exprsSize = 2 * 11 + 1; // 2 * Area3DPtg.SIZE + UnionPtg.SIZE
             ptgs.add(new MemFuncPtg(exprsSize));
         }
-        if (startColumn >= 0)
-        {
-            Area3DPtg colArea = new Area3DPtg();
-            colArea.setExternSheetIndex(externSheetIndex);
-            colArea.setFirstColumn((short)startColumn);
-            colArea.setLastColumn((short)endColumn);
-            colArea.setFirstRow(0);
-            colArea.setLastRow(MAX_ROW);
-            colArea.setFirstColRelative(false);
-            colArea.setLastColRelative(false);
-            colArea.setFirstRowRelative(false);
-            colArea.setLastRowRelative(false);
+        if (startColumn >= 0) {
+            Area3DPtg colArea = new Area3DPtg(0, MAX_ROW, startColumn, endColumn, 
+                    false, false, false, false, externSheetIndex);
             ptgs.add(colArea);
         }
-        if (startRow >= 0)
-        {
-            Area3DPtg rowArea = new Area3DPtg();
-            rowArea.setExternSheetIndex(externSheetIndex);
-            rowArea.setFirstColumn((short)0);
-            rowArea.setLastColumn(MAX_COLUMN);
-            rowArea.setFirstRow(startRow);
-            rowArea.setLastRow(endRow);
-            rowArea.setFirstColRelative(false);
-            rowArea.setLastColRelative(false);
-            rowArea.setFirstRowRelative(false);
-            rowArea.setLastRowRelative(false);
+        if (startRow >= 0) {
+            Area3DPtg rowArea = new Area3DPtg(startRow, endRow, 0, MAX_COLUMN, 
+                    false, false, false, false, externSheetIndex);
             ptgs.add(rowArea);
         }
         if (settingRowAndColumn)
index a10b9976aa50e19fcb037b56bcaaf055754743fa..d6575642ee2a363be5ed2c3877a08d86ccec345a 100644 (file)
 
 package org.apache.poi.hssf.util;
 
-import java.util.ArrayList;
-import java.util.StringTokenizer;
-
-import org.apache.poi.hssf.record.formula.AreaI;
-
-public final class AreaReference {
-
-    /** The character (!) that separates sheet names from cell references */ 
-    private static final char SHEET_NAME_DELIMITER = '!';
-    /** The character (:) that separates the two cell references in a multi-cell area reference */
-    private static final char CELL_DELIMITER = ':';
-    /** The character (') used to quote sheet names when they contain special characters */
-    private static final char SPECIAL_NAME_DELIMITER = '\'';
-    
-    private final CellReference _firstCell;
-    private final CellReference _lastCell;
-    private final boolean _isSingleCell;
 
+public final class AreaReference extends org.apache.poi.ss.util.AreaReference {
     /**
      * Create an area ref from a string representation.  Sheet names containing special characters should be
      * delimited and escaped as per normal syntax rules for formulas.<br/> 
      * The area reference must be contiguous (i.e. represent a single rectangle, not a union of rectangles)
      */
     public AreaReference(String reference) {
-        if(! isContiguous(reference)) {
-            throw new IllegalArgumentException(
-                    "References passed to the AreaReference must be contiguous, " +
-                    "use generateContiguous(ref) if you have non-contiguous references");
-        }
-
-        String[] parts = separateAreaRefs(reference);
-        
-        // Special handling for whole-column references
-        if(parts.length == 2 && parts[0].length() == 1 &&
-                parts[1].length() == 1 && 
-                parts[0].charAt(0) >= 'A' && parts[0].charAt(0) <= 'Z' &&
-                parts[1].charAt(0) >= 'A' && parts[1].charAt(0) <= 'Z') {
-            // Represented internally as x$1 to x$65536
-            //  which is the maximum range of rows
-            parts[0] = parts[0] + "$1";
-            parts[1] = parts[1] + "$65536";
-        }
-        
-        _firstCell = new CellReference(parts[0]);
-        
-        if(parts.length == 2) {
-            _lastCell = new CellReference(parts[1]);
-            _isSingleCell = false;
-        } else {
-            _lastCell = _firstCell;
-            _isSingleCell = true;
-        }
+               super(reference);
     }
     
     /**
      * Creates an area ref from a pair of Cell References.
      */
     public AreaReference(CellReference topLeft, CellReference botRight) {
-        _firstCell = topLeft;
-        _lastCell = botRight;
-        _isSingleCell = false;
-    }
-
-    /**
-     * Is the reference for a contiguous (i.e.
-     *  unbroken) area, or is it made up of
-     *  several different parts?
-     * (If it is, you will need to call
-     *  ....
-     */
-    public static boolean isContiguous(String reference) {
-        if(reference.indexOf(',') == -1) {
-            return true;
-        }
-        return false;
-    }
-    
-    /**
-     * Is the reference for a whole-column reference,
-     *  such as C:C or D:G ?
-     */
-    public static boolean isWholeColumnReference(CellReference topLeft, CellReference botRight) {
-        // These are represented as something like
-        //   C$1:C$65535 or D$1:F$0
-        // i.e. absolute from 1st row to 0th one
-        if(topLeft.getRow() == 0 && topLeft.isRowAbsolute() &&
-            botRight.getRow() == 65535 && botRight.isRowAbsolute()) {
-            return true;
-        }
-        return false;
-    }
-    public boolean isWholeColumnReference() {
-        return isWholeColumnReference(_firstCell, _lastCell);
-    }
-
-    /**
-     * Takes a non-contiguous area reference, and
-     *  returns an array of contiguous area references.
-     */
-    public static AreaReference[] generateContiguous(String reference) {
-        ArrayList refs = new ArrayList();
-        StringTokenizer st = new StringTokenizer(reference, ",");
-        while(st.hasMoreTokens()) {
-            refs.add(
-                    new AreaReference(st.nextToken())
-            );
-        }
-        return (AreaReference[])refs.toArray(new AreaReference[refs.size()]);
-    }
-
-    /**
-     * @return <code>false</code> if this area reference involves more than one cell
-     */
-    public boolean isSingleCell() {
-        return _isSingleCell;
-    }
-    
-    /**
-     * @return the first cell reference which defines this area. Usually this cell is in the upper
-     * left corner of the area (but this is not a requirement).
-     */
-   public CellReference getFirstCell() {
-        return _firstCell;
-    }
-    
-    /**
-     * Note - if this area reference refers to a single cell, the return value of this method will
-     * be identical to that of <tt>getFirstCell()</tt>
-     * @return the second cell reference which defines this area.  For multi-cell areas, this is 
-     * cell diagonally opposite the 'first cell'.  Usually this cell is in the lower right corner 
-     * of the area (but this is not a requirement).
-     */
-    public CellReference getLastCell() {
-        return _lastCell;
-    }
-    /**
-     * Returns a reference to every cell covered by this area
-     */
-    public CellReference[] getAllReferencedCells() {
-        // Special case for single cell reference
-        if(_isSingleCell) {
-            return  new CellReference[] { _firstCell, };
-        }
-        // Interpolate between the two
-        int minRow = Math.min(_firstCell.getRow(), _lastCell.getRow());
-        int maxRow = Math.max(_firstCell.getRow(), _lastCell.getRow());
-        int minCol = Math.min(_firstCell.getCol(), _lastCell.getCol());
-        int maxCol = Math.max(_firstCell.getCol(), _lastCell.getCol());
-        String sheetName = _firstCell.getSheetName();
-        
-        ArrayList refs = new ArrayList();
-        for(int row=minRow; row<=maxRow; row++) {
-            for(int col=minCol; col<=maxCol; col++) {
-                CellReference ref = new CellReference(sheetName, row, col, _firstCell.isRowAbsolute(), _firstCell.isColAbsolute());
-                refs.add(ref);
-            }
-        }
-        return (CellReference[])refs.toArray(new CellReference[refs.size()]);
-    }
-
-    /**
-     *  Example return values:
-     *    <table border="0" cellpadding="1" cellspacing="0" summary="Example return values">
-     *      <tr><th align='left'>Result</th><th align='left'>Comment</th></tr>
-     *      <tr><td>A1:A1</td><td>Single cell area reference without sheet</td></tr>
-     *      <tr><td>A1:$C$1</td><td>Multi-cell area reference without sheet</td></tr>
-     *      <tr><td>Sheet1!A$1:B4</td><td>Standard sheet name</td></tr>
-     *      <tr><td>'O''Brien''s Sales'!B5:C6'&nbsp;</td><td>Sheet name with special characters</td></tr>
-     *    </table>
-     * @return the text representation of this area reference as it would appear in a formula.
-     */
-    public String formatAsString() {
-        // Special handling for whole-column references
-        if(isWholeColumnReference()) {
-            return
-                CellReference.convertNumToColString(_firstCell.getCol())
-                + ":" +
-                CellReference.convertNumToColString(_lastCell.getCol());
-        }
-        
-        StringBuffer sb = new StringBuffer(32);
-        sb.append(_firstCell.formatAsString());
-        if(!_isSingleCell) {
-            sb.append(CELL_DELIMITER);
-            if(_lastCell.getSheetName() == null) {
-                sb.append(_lastCell.formatAsString());
-            } else {
-                // don't want to include the sheet name twice
-                _lastCell.appendCellReference(sb);
-            }
-        }
-        return sb.toString();
-    }
-    /**
-     * Formats a 2-D area as it would appear in a formula.  See formatAsString() (no-arg)
-     */
-    public static String formatAsString(AreaI area) {
-        CellReference topLeft = new CellReference(area.getFirstRow(),area.getFirstColumn(),!area.isFirstRowRelative(),!area.isFirstColRelative());
-        CellReference botRight = new CellReference(area.getLastRow(),area.getLastColumn(),!area.isLastRowRelative(),!area.isLastColRelative());
-        
-        if(isWholeColumnReference(topLeft, botRight)) {
-            return (new AreaReference(topLeft, botRight)).formatAsString();
-        }
-        return topLeft.formatAsString() + ":" + botRight.formatAsString(); 
-    }
-    public String toString() {
-        StringBuffer sb = new StringBuffer(64);
-        sb.append(getClass().getName()).append(" [");
-        sb.append(formatAsString());
-        sb.append("]");
-        return sb.toString();
-    }
-
-    /**
-     * Separates Area refs in two parts and returns them as separate elements in a String array,
-     * each qualified with the sheet name (if present)
-     * 
-     * @return array with one or two elements. never <code>null</code>
-     */
-    private static String[] separateAreaRefs(String reference) {
-        // TODO - refactor cell reference parsing logic to one place.
-        // Current known incarnations: 
-        //   FormulaParser.GetName()
-        //   CellReference.separateRefParts() 
-        //   AreaReference.separateAreaRefs() (here)
-        //   SheetNameFormatter.format() (inverse)
-        
-        
-        int len = reference.length();
-        int delimiterPos = -1;
-        boolean insideDelimitedName = false;
-        for(int i=0; i<len; i++) {
-            switch(reference.charAt(i)) {
-                case CELL_DELIMITER:
-                    if(!insideDelimitedName) {
-                        if(delimiterPos >=0) {
-                            throw new IllegalArgumentException("More than one cell delimiter '" 
-                                    + CELL_DELIMITER + "' appears in area reference '" + reference + "'");
-                        }
-                        delimiterPos = i;
-                    }
-                default:
-                    continue;
-                case SPECIAL_NAME_DELIMITER:
-                    // fall through
-            }
-            if(!insideDelimitedName) {
-                insideDelimitedName = true;
-                continue;
-            }
-            
-            if(i >= len-1) {
-                // reference ends with the delimited name. 
-                // Assume names like: "Sheet1!'A1'" are never legal.
-                throw new IllegalArgumentException("Area reference '" + reference 
-                        + "' ends with special name delimiter '"  + SPECIAL_NAME_DELIMITER + "'");
-            }
-            if(reference.charAt(i+1) == SPECIAL_NAME_DELIMITER) {
-                // two consecutive quotes is the escape sequence for a single one
-                i++; // skip this and keep parsing the special name
-            } else {
-                // this is the end of the delimited name
-                insideDelimitedName = false;
-            }
-        }
-        if(delimiterPos < 0) {
-            return new String[] { reference, };
-        }
-
-        String partA = reference.substring(0, delimiterPos);
-        String partB = reference.substring(delimiterPos+1);
-        if(partB.indexOf(SHEET_NAME_DELIMITER) >=0) {
-            // TODO - are references like "Sheet1!A1:Sheet1:B2" ever valid?  
-            // FormulaParser has code to handle that.
-            
-            throw new RuntimeException("Unexpected " + SHEET_NAME_DELIMITER 
-                    + " in second cell reference of '" + reference + "'");
-        }
-        
-        int plingPos = partA.lastIndexOf(SHEET_NAME_DELIMITER);
-        if(plingPos < 0) {
-            return new String [] { partA, partB, };
-        }
-        
-        String sheetName = partA.substring(0, plingPos + 1); // +1 to include delimiter
-        
-        return new String [] { partA, sheetName + partB, };
+               super(topLeft, botRight);
     }
-}
\ No newline at end of file
+}
index 74e92b0a8dafb74fa5ad8a67b929a0347720b3b6..aa71c68c54877cbf901d3119d38985256415c7f7 100644 (file)
@@ -1,26 +1,23 @@
-/*
-* 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.
-*/
+/* ====================================================================
+   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.ss.usermodel;
 
-import java.lang.reflect.Constructor;
-import java.util.HashMap;
 import java.util.Iterator;
-import java.util.Map;
 import java.util.Stack;
 
 import org.apache.poi.hssf.model.FormulaParser;
@@ -28,6 +25,7 @@ import org.apache.poi.hssf.record.formula.Area3DPtg;
 import org.apache.poi.hssf.record.formula.AreaPtg;
 import org.apache.poi.hssf.record.formula.BoolPtg;
 import org.apache.poi.hssf.record.formula.ControlPtg;
+import org.apache.poi.hssf.record.formula.ErrPtg;
 import org.apache.poi.hssf.record.formula.IntPtg;
 import org.apache.poi.hssf.record.formula.MemErrPtg;
 import org.apache.poi.hssf.record.formula.MissingArgPtg;
@@ -41,77 +39,51 @@ import org.apache.poi.hssf.record.formula.RefPtg;
 import org.apache.poi.hssf.record.formula.StringPtg;
 import org.apache.poi.hssf.record.formula.UnionPtg;
 import org.apache.poi.hssf.record.formula.UnknownPtg;
-import org.apache.poi.hssf.record.formula.eval.Area2DEval;
-import org.apache.poi.hssf.record.formula.eval.Area3DEval;
 import org.apache.poi.hssf.record.formula.eval.AreaEval;
 import org.apache.poi.hssf.record.formula.eval.BlankEval;
 import org.apache.poi.hssf.record.formula.eval.BoolEval;
 import org.apache.poi.hssf.record.formula.eval.ErrorEval;
 import org.apache.poi.hssf.record.formula.eval.Eval;
 import org.apache.poi.hssf.record.formula.eval.FunctionEval;
+import org.apache.poi.hssf.record.formula.eval.LazyAreaEval;
+import org.apache.poi.hssf.record.formula.eval.LazyRefEval;
 import org.apache.poi.hssf.record.formula.eval.NameEval;
 import org.apache.poi.hssf.record.formula.eval.NameXEval;
 import org.apache.poi.hssf.record.formula.eval.NumberEval;
 import org.apache.poi.hssf.record.formula.eval.OperationEval;
-import org.apache.poi.hssf.record.formula.eval.Ref2DEval;
-import org.apache.poi.hssf.record.formula.eval.Ref3DEval;
 import org.apache.poi.hssf.record.formula.eval.RefEval;
 import org.apache.poi.hssf.record.formula.eval.StringEval;
 import org.apache.poi.hssf.record.formula.eval.ValueEval;
-import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
 
 /**
  * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
- * 
+ *
  */
 public class FormulaEvaluator {
-                
-    // params to lookup the right constructor using reflection
-    private static final Class[] VALUE_CONTRUCTOR_CLASS_ARRAY = new Class[] { Ptg.class };
 
-    private static final Class[] AREA3D_CONSTRUCTOR_CLASS_ARRAY = new Class[] { Ptg.class, ValueEval[].class };
-
-    private static final Class[] REFERENCE_CONSTRUCTOR_CLASS_ARRAY = new Class[] { Ptg.class, ValueEval.class };
-
-    private static final Class[] REF3D_CONSTRUCTOR_CLASS_ARRAY = new Class[] { Ptg.class, ValueEval.class };
-
-    // Maps for mapping *Eval to *Ptg
-    private static final Map VALUE_EVALS_MAP = new HashMap();
-
-    /*
-     * Following is the mapping between the Ptg tokens returned 
-     * by the FormulaParser and the *Eval classes that are used 
-     * by the FormulaEvaluator
-     */
-    static {
-        VALUE_EVALS_MAP.put(BoolPtg.class, BoolEval.class);
-        VALUE_EVALS_MAP.put(IntPtg.class, NumberEval.class);
-        VALUE_EVALS_MAP.put(NumberPtg.class, NumberEval.class);
-        VALUE_EVALS_MAP.put(StringPtg.class, StringEval.class);
-
-    }
-
-    
     protected Sheet _sheet;
     protected Workbook _workbook;
-    
+
     public FormulaEvaluator(Sheet sheet, Workbook workbook) {
-        this._sheet = sheet;
-        this._workbook = workbook;
+        _sheet = sheet;
+        _workbook = workbook;
     }
-    
+
     /**
      * Does nothing
      * @deprecated (Aug 2008) - not needed, since the current row can be derived from the cell
      */
-    public void setCurrentRow(Row row) {}
+    public void setCurrentRow(Row row) {
+        // do nothing
+    }
+
 
     /**
      * If cell contains a formula, the formula is evaluated and returned,
      * else the CellValue simply copies the appropriate cell value from
      * the cell and also its cell type. This method should be preferred over
      * evaluateInCell() when the call should not modify the contents of the
-     * original cell. 
+     * original cell.
      * @param cell
      */
     public CellValue evaluate(Cell cell) {
@@ -144,25 +116,25 @@ public class FormulaEvaluator {
         }
         return retval;
     }
-    
-    
+
+
     /**
      * If cell contains formula, it evaluates the formula,
      *  and saves the result of the formula. The cell
      *  remains as a formula cell.
      * Else if cell does not contain formula, this method leaves
-     *  the cell unchanged. 
+     *  the cell unchanged.
      * Note that the type of the formula result is returned,
      *  so you know what kind of value is also stored with
-     *  the formula. 
+     *  the formula.
      * <pre>
      * int evaluatedCellType = evaluator.evaluateFormulaCell(cell);
      * </pre>
      * Be aware that your cell will hold both the formula,
      *  and the result. If you want the cell replaced with
-     *  the result of the formula, use {@link #evaluateInCell(HSSFCell)}
+     *  the result of the formula, use {@link #evaluateInCell(Cell)}
      * @param cell The cell to evaluate
-     * @return The type of the formula result (the cell's type remains as HSSFCell.CELL_TYPE_FORMULA however)
+     * @return The type of the formula result (the cell's type remains as Cell.CELL_TYPE_FORMULA however)
      */
     public int evaluateFormulaCell(Cell cell) {
         if (cell != null) {
@@ -192,21 +164,21 @@ public class FormulaEvaluator {
         }
         return -1;
     }
-        
+
     /**
      * If cell contains formula, it evaluates the formula, and
      *  puts the formula result back into the cell, in place
      *  of the old formula.
      * Else if cell does not contain formula, this method leaves
-     *  the cell unchanged. 
-     * Note that the same instance of HSSFCell is returned to 
+     *  the cell unchanged.
+     * Note that the same instance of Cell is returned to
      * allow chained calls like:
      * <pre>
      * int evaluatedCellType = evaluator.evaluateInCell(cell).getCellType();
      * </pre>
      * Be aware that your cell value will be changed to hold the
      *  result of the formula. If you simply want the formula
-     *  value computed for you, use {@link #evaluateFormulaCell(HSSFCell)}
+     *  value computed for you, use {@link #evaluateFormulaCell(Cell)}
      * @param cell
      */
     public Cell evaluateInCell(Cell cell) {
@@ -239,7 +211,7 @@ public class FormulaEvaluator {
         }
         return cell;
     }
-    
+
     /**
      * Loops over all cells in all sheets of the supplied
      *  workbook.
@@ -248,32 +220,32 @@ public class FormulaEvaluator {
      *  remain as formula cells.
      * For cells that do not contain formulas, no changes
      *  are made.
-     * This is a helpful wrapper around looping over all 
+     * This is a helpful wrapper around looping over all
      *  cells, and calling evaluateFormulaCell on each one.
      */
-       public static void evaluateAllFormulaCells(Workbook wb) {
-               for(int i=0; i<wb.getNumberOfSheets(); i++) {
-                       Sheet sheet = wb.getSheetAt(i);
-                       FormulaEvaluator evaluator = new FormulaEvaluator(sheet, wb);
-
-                       for (Iterator rit = sheet.rowIterator(); rit.hasNext();) {
-                               Row r = (Row)rit.next();
-
-                               for (Iterator cit = r.cellIterator(); cit.hasNext();) {
-                                       Cell c = (Cell)cit.next();
-                                       if (c.getCellType() == Cell.CELL_TYPE_FORMULA)
-                                               evaluator.evaluateFormulaCell(c);
-                               }
-                       }
-               }
-       }
-        
-    
+    public static void evaluateAllFormulaCells(Workbook wb) {
+        for(int i=0; i<wb.getNumberOfSheets(); i++) {
+            Sheet sheet = wb.getSheetAt(i);
+            FormulaEvaluator evaluator = new FormulaEvaluator(sheet, wb);
+
+            for (Iterator rit = sheet.rowIterator(); rit.hasNext();) {
+                Row r = (Row)rit.next();
+
+                for (Iterator cit = r.cellIterator(); cit.hasNext();) {
+                    Cell c = (Cell)cit.next();
+                    if (c.getCellType() == Cell.CELL_TYPE_FORMULA)
+                        evaluator.evaluateFormulaCell(c);
+                }
+            }
+        }
+    }
+
+
     /**
      * Returns a CellValue wrapper around the supplied ValueEval instance.
      * @param eval
      */
-    protected static CellValue getCellValueForEval(ValueEval eval, CreationHelper cHelper) {
+    private static CellValue getCellValueForEval(ValueEval eval, CreationHelper cHelper) {
         CellValue retval = null;
         if (eval != null) {
             if (eval instanceof NumberEval) {
@@ -297,7 +269,7 @@ public class FormulaEvaluator {
             else if (eval instanceof ErrorEval) {
                 retval = new CellValue(Cell.CELL_TYPE_ERROR, cHelper);
                 retval.setErrorValue((byte)((ErrorEval)eval).getErrorCode());
-//                retval.setRichTextStringValue(new HSSFRichTextString("#An error occurred. check cell.getErrorCode()"));
+//                retval.setRichTextStringValue(new RichTextString("#An error occurred. check cell.getErrorCode()"));
             }
             else {
                 retval = new CellValue(Cell.CELL_TYPE_ERROR, cHelper);
@@ -305,19 +277,19 @@ public class FormulaEvaluator {
         }
         return retval;
     }
-    
+
     /**
-     * Dev. Note: Internal evaluate must be passed only a formula cell 
+     * Dev. Note: Internal evaluate must be passed only a formula cell
      * else a runtime exception will be thrown somewhere inside the method.
      * (Hence this is a private method.)
      */
     private static ValueEval internalEvaluate(Cell srcCell, Sheet sheet, Workbook workbook) {
         int srcRowNum = srcCell.getRowIndex();
         short srcColNum = srcCell.getCellNum();
-        
-        
+
+
         EvaluationCycleDetector tracker = EvaluationCycleDetectorManager.getTracker();
-        
+
         if(!tracker.startEvaluate(workbook, sheet, srcRowNum, srcColNum)) {
             return ErrorEval.CIRCULAR_REF_ERROR;
         }
@@ -327,8 +299,9 @@ public class FormulaEvaluator {
             tracker.endEvaluate(workbook, sheet, srcRowNum, srcColNum);
         }
     }
-    private static ValueEval evaluateCell(Workbook workbook, Sheet sheet, 
+    private static ValueEval evaluateCell(Workbook workbook, Sheet sheet,
             int srcRowNum, short srcColNum, String cellFormulaText) {
+
         Ptg[] ptgs = FormulaParser.parse(cellFormulaText, workbook);
 
         Stack stack = new Stack();
@@ -337,16 +310,16 @@ public class FormulaEvaluator {
             // since we don't know how to handle these yet :(
             Ptg ptg = ptgs[i];
             if (ptg instanceof ControlPtg) {
-               // skip Parentheses, Attr, etc
-               continue;
-                       }
+                // skip Parentheses, Attr, etc
+                continue;
+            }
             if (ptg instanceof MemErrPtg) { continue; }
             if (ptg instanceof MissingArgPtg) { continue; }
-            if (ptg instanceof NamePtg) { 
+            if (ptg instanceof NamePtg) {
                 // named ranges, macro functions
                 NamePtg namePtg = (NamePtg) ptg;
                 stack.push(new NameEval(namePtg.getIndex()));
-                continue; 
+                continue;
             }
             if (ptg instanceof NameXPtg) {
                 NameXPtg nameXPtg = (NameXPtg) ptg;
@@ -354,7 +327,7 @@ public class FormulaEvaluator {
                 continue;
             }
             if (ptg instanceof UnknownPtg) { continue; }
-
+            Eval opResult;
             if (ptg instanceof OperationPtg) {
                 OperationPtg optg = (OperationPtg) ptg;
 
@@ -370,42 +343,11 @@ public class FormulaEvaluator {
                     Eval p = (Eval) stack.pop();
                     ops[j] = p;
                 }
-                Eval opresult = invokeOperation(operation, ops, srcRowNum, srcColNum, workbook, sheet);
-                stack.push(opresult);
-            }
-            else if (ptg instanceof RefPtg) {
-                RefPtg refPtg = (RefPtg) ptg;
-                int colIx = refPtg.getColumn();
-                int rowIx = refPtg.getRow();
-                Row row = sheet.getRow(rowIx);
-                Cell cell = (row != null) ? row.getCell(colIx) : null;
-                stack.push(createRef2DEval(refPtg, cell, sheet, workbook));
-            }
-            else if (ptg instanceof Ref3DPtg) {
-                Ref3DPtg refPtg = (Ref3DPtg) ptg;
-                int colIx = refPtg.getColumn();
-                int rowIx = refPtg.getRow();
-                Sheet xsheet = workbook.getSheetAt(
-                               workbook.getSheetIndexFromExternSheetIndex(refPtg.getExternSheetIndex())
-                );
-                Row row = xsheet.getRow(rowIx);
-                Cell cell = (row != null) ? row.getCell(colIx) : null;
-                stack.push(createRef3DEval(refPtg, cell, xsheet, workbook));
-            }
-            else if (ptg instanceof AreaPtg) {
-                AreaPtg ap = (AreaPtg) ptg;
-                AreaEval ae = evaluateAreaPtg(sheet, workbook, ap);
-                stack.push(ae);
-            }
-            else if (ptg instanceof Area3DPtg) {
-                Area3DPtg a3dp = (Area3DPtg) ptg;
-                AreaEval ae = evaluateArea3dPtg(workbook, a3dp);
-                stack.push(ae);
-            }
-            else {
-                Eval ptgEval = getEvalForPtg(ptg);
-                stack.push(ptgEval);
+                opResult = invokeOperation(operation, ops, srcRowNum, srcColNum, workbook, sheet);
+            } else {
+                opResult = getEvalForPtg(ptg, sheet, workbook);
             }
+            stack.push(opResult);
         }
 
         ValueEval value = ((ValueEval) stack.pop());
@@ -414,9 +356,9 @@ public class FormulaEvaluator {
         }
         value = dereferenceValue(value, srcRowNum, srcColNum);
         if (value instanceof BlankEval) {
-               // Note Excel behaviour here. A blank final final value is converted to zero.  
+            // Note Excel behaviour here. A blank final final value is converted to zero.
             return NumberEval.ZERO;
-            // Formulas _never_ evaluate to blank.  If a formula appears to have evaluated to 
+            // Formulas _never_ evaluate to blank.  If a formula appears to have evaluated to
             // blank, the actual value is empty string. This can be verified with ISBLANK().
         }
         return value;
@@ -425,8 +367,8 @@ public class FormulaEvaluator {
     /**
      * Dereferences a single value from any AreaEval or RefEval evaluation result.
      * If the supplied evaluationResult is just a plain value, it is returned as-is.
-        * @return a <tt>NumberEval</tt>, <tt>StringEval</tt>, <tt>BoolEval</tt>,
-        *  <tt>BlankEval</tt> or <tt>ErrorEval</tt>. Never <code>null</code>.
+     * @return a <tt>NumberEval</tt>, <tt>StringEval</tt>, <tt>BoolEval</tt>,
+     *  <tt>BlankEval</tt> or <tt>ErrorEval</tt>. Never <code>null</code>.
      */
     private static ValueEval dereferenceValue(ValueEval evaluationResult, int srcRowNum, short srcColNum) {
         if (evaluationResult instanceof RefEval) {
@@ -460,107 +402,48 @@ public class FormulaEvaluator {
         }
         return operation.evaluate(ops, srcRowNum, srcColNum);
     }
-    
-    public static AreaEval evaluateAreaPtg(Sheet sheet, Workbook workbook, AreaPtg ap) {
-        int row0 = ap.getFirstRow();
-        int col0 = ap.getFirstColumn();
-        int row1 = ap.getLastRow();
-        int col1 = ap.getLastColumn();
-        
-        // If the last row is -1, then the
-        //  reference is for the rest of the column
-        // (eg C:C)
-        // TODO: Handle whole column ranges properly
-        if(row1 == -1 && row0 >= 0) {
-            row1 = (short)sheet.getLastRowNum();
-        }
-        ValueEval[] values = evalArea(workbook, sheet, row0, col0, row1, col1);
-        return new Area2DEval(ap, values);
-    }
-
-    public static AreaEval evaluateArea3dPtg(Workbook workbook, Area3DPtg a3dp) {
-       int row0 = a3dp.getFirstRow();
-       int col0 = a3dp.getFirstColumn();
-       int row1 = a3dp.getLastRow();
-       int col1 = a3dp.getLastColumn();
-        Sheet xsheet = workbook.getSheetAt(
-                       workbook.getSheetIndexFromExternSheetIndex(a3dp.getExternSheetIndex())
-        );
-        
-        // If the last row is -1, then the
-        //  reference is for the rest of the column
-        // (eg C:C)
-        // TODO: Handle whole column ranges properly
-        if(row1 == -1 && row0 >= 0) {
-            row1 = (short)xsheet.getLastRowNum();
-        }
-        
-        ValueEval[] values = evalArea(workbook, xsheet, row0, col0, row1, col1);
-        return new Area3DEval(a3dp, values);
-    }
-    
-    private static ValueEval[] evalArea(Workbook workbook, Sheet sheet, 
-               int row0, int col0, int row1, int col1) {
-        ValueEval[] values = new ValueEval[(row1 - row0 + 1) * (col1 - col0 + 1)];
-        for (int x = row0; sheet != null && x < row1 + 1; x++) {
-            Row row = sheet.getRow(x);
-            for (int y = col0; y < col1 + 1; y++) {
-                ValueEval cellEval;
-                if(row == null) {
-                       cellEval = BlankEval.INSTANCE;
-                } else {
-                       cellEval = getEvalForCell(row.getCell(y), row, sheet, workbook);
-                }
-                               values[(x - row0) * (col1 - col0 + 1) + (y - col0)] = cellEval;
-            }
-        }
-        return values;
-    }
 
     /**
      * returns an appropriate Eval impl instance for the Ptg. The Ptg must be
-     * one of: Area3DPtg, AreaPtg, RefPtg, Ref3DPtg, IntPtg, NumberPtg,
+     * one of: Area3DPtg, AreaPtg, ReferencePtg, Ref3DPtg, IntPtg, NumberPtg,
      * StringPtg, BoolPtg <br/>special Note: OperationPtg subtypes cannot be
      * passed here!
-     * 
-     * @param ptg
      */
-    protected static Eval getEvalForPtg(Ptg ptg) {
-        Eval retval = null;
-
-        Class clazz = (Class) VALUE_EVALS_MAP.get(ptg.getClass());
-        try {
-            if (ptg instanceof Area3DPtg) {
-                Constructor constructor = clazz.getConstructor(AREA3D_CONSTRUCTOR_CLASS_ARRAY);
-                retval = (OperationEval) constructor.newInstance(new Ptg[] { ptg });
-            }
-            else if (ptg instanceof AreaPtg) {
-                Constructor constructor = clazz.getConstructor(AREA3D_CONSTRUCTOR_CLASS_ARRAY);
-                retval = (OperationEval) constructor.newInstance(new Ptg[] { ptg });
-            }
-            else if (ptg instanceof RefPtg) {
-                Constructor constructor = clazz.getConstructor(REFERENCE_CONSTRUCTOR_CLASS_ARRAY);
-                retval = (OperationEval) constructor.newInstance(new Ptg[] { ptg });
-            }
-            else if (ptg instanceof Ref3DPtg) {
-                Constructor constructor = clazz.getConstructor(REF3D_CONSTRUCTOR_CLASS_ARRAY);
-                retval = (OperationEval) constructor.newInstance(new Ptg[] { ptg });
-            }
-            else {
-                if (ptg instanceof IntPtg || ptg instanceof NumberPtg || ptg instanceof StringPtg
-                        || ptg instanceof BoolPtg) {
-                    Constructor constructor = clazz.getConstructor(VALUE_CONTRUCTOR_CLASS_ARRAY);
-                    retval = (ValueEval) constructor.newInstance(new Ptg[] { ptg });
-                }
-            }
+    private static Eval getEvalForPtg(Ptg ptg, Sheet sheet, Workbook workbook) {
+        if (ptg instanceof RefPtg) {
+            return new LazyRefEval(((RefPtg) ptg), sheet, workbook);
         }
-        catch (Exception e) {
-            throw new RuntimeException("Fatal Error: ", e);
+        if (ptg instanceof Ref3DPtg) {
+            Ref3DPtg refPtg = (Ref3DPtg) ptg;
+            Sheet xsheet = workbook.getSheetAt(workbook.getSheetIndexFromExternSheetIndex(refPtg.getExternSheetIndex()));
+            return new LazyRefEval(refPtg, xsheet, workbook);
+        }
+        if (ptg instanceof AreaPtg) {
+            return new LazyAreaEval(((AreaPtg) ptg), sheet, workbook);
+        }
+        if (ptg instanceof Area3DPtg) {
+            Area3DPtg a3dp = (Area3DPtg) ptg;
+            Sheet xsheet = workbook.getSheetAt(workbook.getSheetIndexFromExternSheetIndex(a3dp.getExternSheetIndex()));
+            return new LazyAreaEval(a3dp, xsheet, workbook);
         }
-        return retval;
 
+        if (ptg instanceof IntPtg) {
+            return new NumberEval(((IntPtg)ptg).getValue());
+        }
+        if (ptg instanceof NumberPtg) {
+            return new NumberEval(((NumberPtg)ptg).getValue());
+        }
+        if (ptg instanceof StringPtg) {
+            return new StringEval(((StringPtg) ptg).getValue());
+        }
+        if (ptg instanceof BoolPtg) {
+            return BoolEval.valueOf(((BoolPtg) ptg).getValue());
+        }
+        if (ptg instanceof ErrPtg) {
+            return ErrorEval.valueOf(((ErrPtg) ptg).getErrorCode());
+        }
+        throw new RuntimeException("Unexpected ptg class (" + ptg.getClass().getName() + ")");
     }
-
     /**
      * Given a cell, find its type and from that create an appropriate ValueEval
      * impl instance and return that. Since the cell could be an external
@@ -570,7 +453,7 @@ public class FormulaEvaluator {
      * @param sheet
      * @param workbook
      */
-    protected static ValueEval getEvalForCell(Cell cell, Row row, Sheet sheet, Workbook workbook) {
+    public static ValueEval getEvalForCell(Cell cell, Sheet sheet, Workbook workbook) {
 
         if (cell == null) {
             return BlankEval.INSTANCE;
@@ -593,73 +476,21 @@ public class FormulaEvaluator {
     }
 
     /**
-     * Creates a Ref2DEval for RefPtg.
-     * Non existent cells are treated as RefEvals containing BlankEval.
-     */
-    private static Ref2DEval createRef2DEval(RefPtg ptg, Cell cell, 
-            Sheet sheet, Workbook workbook) {
-        if (cell == null) {
-            return new Ref2DEval(ptg, BlankEval.INSTANCE);
-        }
-        
-        switch (cell.getCellType()) {
-            case Cell.CELL_TYPE_NUMERIC:
-                return new Ref2DEval(ptg, new NumberEval(cell.getNumericCellValue()));
-            case Cell.CELL_TYPE_STRING:
-                return new Ref2DEval(ptg, new StringEval(cell.getRichStringCellValue().getString()));
-            case Cell.CELL_TYPE_FORMULA:
-                return new Ref2DEval(ptg, internalEvaluate(cell, sheet, workbook));
-            case Cell.CELL_TYPE_BOOLEAN:
-                return new Ref2DEval(ptg, BoolEval.valueOf(cell.getBooleanCellValue()));
-            case Cell.CELL_TYPE_BLANK:
-                return new Ref2DEval(ptg, BlankEval.INSTANCE);
-            case Cell.CELL_TYPE_ERROR:
-                return new  Ref2DEval(ptg, ErrorEval.valueOf(cell.getErrorCellValue()));
-        }
-        throw new RuntimeException("Unexpected cell type (" + cell.getCellType() + ")");
-    }
-
-    /**
-     * create a Ref3DEval for Ref3DPtg.
-     */
-    private static Ref3DEval createRef3DEval(Ref3DPtg ptg, Cell cell, 
-            Sheet sheet, Workbook workbook) {
-        if (cell == null) {
-            return new Ref3DEval(ptg, BlankEval.INSTANCE);
-        }
-        switch (cell.getCellType()) {
-            case Cell.CELL_TYPE_NUMERIC:
-                return new Ref3DEval(ptg, new NumberEval(cell.getNumericCellValue()));
-            case Cell.CELL_TYPE_STRING:
-                return new Ref3DEval(ptg, new StringEval(cell.getRichStringCellValue().getString()));
-            case Cell.CELL_TYPE_FORMULA:
-                return new Ref3DEval(ptg, internalEvaluate(cell, sheet, workbook));
-            case Cell.CELL_TYPE_BOOLEAN:
-                return new Ref3DEval(ptg, BoolEval.valueOf(cell.getBooleanCellValue()));
-            case Cell.CELL_TYPE_BLANK:
-                return new Ref3DEval(ptg, BlankEval.INSTANCE);
-            case Cell.CELL_TYPE_ERROR:
-                return new Ref3DEval(ptg, ErrorEval.valueOf(cell.getErrorCellValue()));
-        }
-        throw new RuntimeException("Unexpected cell type (" + cell.getCellType() + ")");
-    }
-    
-    /**
-     * Mimics the 'data view' of a cell. This allows formula evaluator 
+     * Mimics the 'data view' of a cell. This allows formula evaluator
      * to return a CellValue instead of precasting the value to String
      * or Number or boolean type.
      * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
      */
     public static class CellValue {
-       private CreationHelper creationHelper;
+        private CreationHelper creationHelper;
         private int cellType;
         private RichTextString richTextStringValue;
         private double numberValue;
         private boolean booleanValue;
         private byte errorValue;
-        
+
         /**
-         * CellType should be one of the types defined in HSSFCell
+         * CellType should be one of the types defined in Cell
          * @param cellType
          */
         public CellValue(int cellType, CreationHelper creationHelper) {
@@ -705,8 +536,8 @@ public class FormulaEvaluator {
          * @deprecated
          */
         public void setStringValue(String stringValue) {
-            this.richTextStringValue =
-               creationHelper.createRichTextString(stringValue);
+            this.richTextStringValue = 
+                  creationHelper.createRichTextString(stringValue);
         }
         /**
          * @return Returns the cellType.
diff --git a/src/java/org/apache/poi/ss/util/AreaReference.java b/src/java/org/apache/poi/ss/util/AreaReference.java
new file mode 100644 (file)
index 0000000..b5e06b9
--- /dev/null
@@ -0,0 +1,296 @@
+/* ====================================================================
+   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.ss.util;
+
+import java.util.ArrayList;
+import java.util.StringTokenizer;
+
+public class AreaReference {
+
+    /** The character (!) that separates sheet names from cell references */ 
+    private static final char SHEET_NAME_DELIMITER = '!';
+    /** The character (:) that separates the two cell references in a multi-cell area reference */
+    private static final char CELL_DELIMITER = ':';
+    /** The character (') used to quote sheet names when they contain special characters */
+    private static final char SPECIAL_NAME_DELIMITER = '\'';
+    
+    private final CellReference _firstCell;
+    private final CellReference _lastCell;
+    private final boolean _isSingleCell;
+
+    /**
+     * Create an area ref from a string representation.  Sheet names containing special characters should be
+     * delimited and escaped as per normal syntax rules for formulas.<br/> 
+     * The area reference must be contiguous (i.e. represent a single rectangle, not a union of rectangles)
+     */
+    public AreaReference(String reference) {
+        if(! isContiguous(reference)) {
+            throw new IllegalArgumentException(
+                    "References passed to the AreaReference must be contiguous, " +
+                    "use generateContiguous(ref) if you have non-contiguous references");
+        }
+
+        String[] parts = separateAreaRefs(reference);
+        
+        // Special handling for whole-column references
+        if(parts.length == 2 && parts[0].length() == 1 &&
+                parts[1].length() == 1 && 
+                parts[0].charAt(0) >= 'A' && parts[0].charAt(0) <= 'Z' &&
+                parts[1].charAt(0) >= 'A' && parts[1].charAt(0) <= 'Z') {
+            // Represented internally as x$1 to x$65536
+            //  which is the maximum range of rows
+            parts[0] = parts[0] + "$1";
+            parts[1] = parts[1] + "$65536";
+        }
+        
+        _firstCell = new CellReference(parts[0]);
+        
+        if(parts.length == 2) {
+            _lastCell = new CellReference(parts[1]);
+            _isSingleCell = false;
+        } else {
+            _lastCell = _firstCell;
+            _isSingleCell = true;
+        }
+    }
+    
+    /**
+     * Creates an area ref from a pair of Cell References.
+     */
+    public AreaReference(CellReference topLeft, CellReference botRight) {
+        _firstCell = topLeft;
+        _lastCell = botRight;
+        _isSingleCell = false;
+    }
+
+    /**
+     * Is the reference for a contiguous (i.e.
+     *  unbroken) area, or is it made up of
+     *  several different parts?
+     * (If it is, you will need to call
+     *  ....
+     */
+    public static boolean isContiguous(String reference) {
+        if(reference.indexOf(',') == -1) {
+            return true;
+        }
+        return false;
+    }
+    
+    /**
+     * Is the reference for a whole-column reference,
+     *  such as C:C or D:G ?
+     */
+    public static boolean isWholeColumnReference(CellReference topLeft, CellReference botRight) {
+        // These are represented as something like
+        //   C$1:C$65535 or D$1:F$0
+        // i.e. absolute from 1st row to 0th one
+        if(topLeft.getRow() == 0 && topLeft.isRowAbsolute() &&
+            botRight.getRow() == 65535 && botRight.isRowAbsolute()) {
+            return true;
+        }
+        return false;
+    }
+    public boolean isWholeColumnReference() {
+        return isWholeColumnReference(_firstCell, _lastCell);
+    }
+
+    /**
+     * Takes a non-contiguous area reference, and
+     *  returns an array of contiguous area references.
+     */
+    public static AreaReference[] generateContiguous(String reference) {
+        ArrayList refs = new ArrayList();
+        StringTokenizer st = new StringTokenizer(reference, ",");
+        while(st.hasMoreTokens()) {
+            refs.add(
+                    new AreaReference(st.nextToken())
+            );
+        }
+        return (AreaReference[])refs.toArray(new AreaReference[refs.size()]);
+    }
+
+    /**
+     * @return <code>false</code> if this area reference involves more than one cell
+     */
+    public boolean isSingleCell() {
+        return _isSingleCell;
+    }
+    
+    /**
+     * @return the first cell reference which defines this area. Usually this cell is in the upper
+     * left corner of the area (but this is not a requirement).
+     */
+   public CellReference getFirstCell() {
+        return _firstCell;
+    }
+    
+    /**
+     * Note - if this area reference refers to a single cell, the return value of this method will
+     * be identical to that of <tt>getFirstCell()</tt>
+     * @return the second cell reference which defines this area.  For multi-cell areas, this is 
+     * cell diagonally opposite the 'first cell'.  Usually this cell is in the lower right corner 
+     * of the area (but this is not a requirement).
+     */
+    public CellReference getLastCell() {
+        return _lastCell;
+    }
+    /**
+     * Returns a reference to every cell covered by this area
+     */
+    public CellReference[] getAllReferencedCells() {
+        // Special case for single cell reference
+        if(_isSingleCell) {
+            return  new CellReference[] { _firstCell, };
+        }
+        // Interpolate between the two
+        int minRow = Math.min(_firstCell.getRow(), _lastCell.getRow());
+        int maxRow = Math.max(_firstCell.getRow(), _lastCell.getRow());
+        int minCol = Math.min(_firstCell.getCol(), _lastCell.getCol());
+        int maxCol = Math.max(_firstCell.getCol(), _lastCell.getCol());
+        String sheetName = _firstCell.getSheetName();
+        
+        ArrayList refs = new ArrayList();
+        for(int row=minRow; row<=maxRow; row++) {
+            for(int col=minCol; col<=maxCol; col++) {
+                CellReference ref = new CellReference(sheetName, row, col, _firstCell.isRowAbsolute(), _firstCell.isColAbsolute());
+                refs.add(ref);
+            }
+        }
+        return (CellReference[])refs.toArray(new CellReference[refs.size()]);
+    }
+
+    /**
+     *  Example return values:
+     *    <table border="0" cellpadding="1" cellspacing="0" summary="Example return values">
+     *      <tr><th align='left'>Result</th><th align='left'>Comment</th></tr>
+     *      <tr><td>A1:A1</td><td>Single cell area reference without sheet</td></tr>
+     *      <tr><td>A1:$C$1</td><td>Multi-cell area reference without sheet</td></tr>
+     *      <tr><td>Sheet1!A$1:B4</td><td>Standard sheet name</td></tr>
+     *      <tr><td>'O''Brien''s Sales'!B5:C6'&nbsp;</td><td>Sheet name with special characters</td></tr>
+     *    </table>
+     * @return the text representation of this area reference as it would appear in a formula.
+     */
+    public String formatAsString() {
+        // Special handling for whole-column references
+        if(isWholeColumnReference()) {
+            return
+                CellReference.convertNumToColString(_firstCell.getCol())
+                + ":" +
+                CellReference.convertNumToColString(_lastCell.getCol());
+        }
+        
+        StringBuffer sb = new StringBuffer(32);
+        sb.append(_firstCell.formatAsString());
+        if(!_isSingleCell) {
+            sb.append(CELL_DELIMITER);
+            if(_lastCell.getSheetName() == null) {
+                sb.append(_lastCell.formatAsString());
+            } else {
+                // don't want to include the sheet name twice
+                _lastCell.appendCellReference(sb);
+            }
+        }
+        return sb.toString();
+    }
+
+    public String toString() {
+        StringBuffer sb = new StringBuffer(64);
+        sb.append(getClass().getName()).append(" [");
+        sb.append(formatAsString());
+        sb.append("]");
+        return sb.toString();
+    }
+
+    /**
+     * Separates Area refs in two parts and returns them as separate elements in a String array,
+     * each qualified with the sheet name (if present)
+     * 
+     * @return array with one or two elements. never <code>null</code>
+     */
+    private static String[] separateAreaRefs(String reference) {
+        // TODO - refactor cell reference parsing logic to one place.
+        // Current known incarnations: 
+        //   FormulaParser.GetName()
+        //   CellReference.separateRefParts() 
+        //   AreaReference.separateAreaRefs() (here)
+        //   SheetNameFormatter.format() (inverse)
+        
+        
+        int len = reference.length();
+        int delimiterPos = -1;
+        boolean insideDelimitedName = false;
+        for(int i=0; i<len; i++) {
+            switch(reference.charAt(i)) {
+                case CELL_DELIMITER:
+                    if(!insideDelimitedName) {
+                        if(delimiterPos >=0) {
+                            throw new IllegalArgumentException("More than one cell delimiter '" 
+                                    + CELL_DELIMITER + "' appears in area reference '" + reference + "'");
+                        }
+                        delimiterPos = i;
+                    }
+                default:
+                    continue;
+                case SPECIAL_NAME_DELIMITER:
+                    // fall through
+            }
+            if(!insideDelimitedName) {
+                insideDelimitedName = true;
+                continue;
+            }
+            
+            if(i >= len-1) {
+                // reference ends with the delimited name. 
+                // Assume names like: "Sheet1!'A1'" are never legal.
+                throw new IllegalArgumentException("Area reference '" + reference 
+                        + "' ends with special name delimiter '"  + SPECIAL_NAME_DELIMITER + "'");
+            }
+            if(reference.charAt(i+1) == SPECIAL_NAME_DELIMITER) {
+                // two consecutive quotes is the escape sequence for a single one
+                i++; // skip this and keep parsing the special name
+            } else {
+                // this is the end of the delimited name
+                insideDelimitedName = false;
+            }
+        }
+        if(delimiterPos < 0) {
+            return new String[] { reference, };
+        }
+
+        String partA = reference.substring(0, delimiterPos);
+        String partB = reference.substring(delimiterPos+1);
+        if(partB.indexOf(SHEET_NAME_DELIMITER) >=0) {
+            // TODO - are references like "Sheet1!A1:Sheet1:B2" ever valid?  
+            // FormulaParser has code to handle that.
+            
+            throw new RuntimeException("Unexpected " + SHEET_NAME_DELIMITER 
+                    + " in second cell reference of '" + reference + "'");
+        }
+        
+        int plingPos = partA.lastIndexOf(SHEET_NAME_DELIMITER);
+        if(plingPos < 0) {
+            return new String [] { partA, partB, };
+        }
+        
+        String sheetName = partA.substring(0, plingPos + 1); // +1 to include delimiter
+        
+        return new String [] { partA, sheetName + partB, };
+    }
+}
index d02c4928ebad0b496d5c42d904b8911746ae2205..8a68f8b37bd9c1e1ea9c37c5a840d75fef1cbb71 100644 (file)
@@ -125,7 +125,7 @@ public class PPTXMLDump {
                 dump(data, pos, size, padding);
             } else {
                 //dump first 100 bytes of the atom data
-                dump(out, data, pos, size, padding, true);
+                dump(out, data, pos, Math.min(size, data.length-pos), padding, true);
             }
                        padding--;
             write(out, "</"+recname + ">" + CR, padding);
index 21a4dc59c425d2968921c022aff3d9b4fe87eea8..f0691c45c799fc73d207f4b251be941bed31eb1e 100644 (file)
@@ -34,7 +34,14 @@ import java.util.Iterator;
  * @author Yegor Kozlov\r
  */\r
 public class Hyperlink {\r
-\r
+    public static final byte LINK_NEXTSLIDE = InteractiveInfoAtom.LINK_NextSlide;\r
+    public static final byte LINK_PREVIOUSSLIDE = InteractiveInfoAtom.LINK_PreviousSlide;\r
+    public static final byte LINK_FIRSTSLIDE = InteractiveInfoAtom.LINK_FirstSlide;\r
+    public static final byte LINK_LASTSLIDE = InteractiveInfoAtom.LINK_LastSlide;\r
+    public static final byte LINK_URL = InteractiveInfoAtom.LINK_Url;\r
+    public static final byte LINK_NULL = InteractiveInfoAtom.LINK_NULL;\r
+\r
+    private int id=-1;\r
     private int type;\r
     private String address;\r
     private String title;\r
@@ -42,7 +49,7 @@ public class Hyperlink {
 \r
     /**\r
      * Gets the type of the hyperlink action.\r
-     * Must be a <code>ACTION_*</code>  constant defined in <code>InteractiveInfoAtom</code>\r
+     * Must be a <code>LINK_*</code>  constant</code>\r
      *\r
      * @return the hyperlink URL\r
      * @see InteractiveInfoAtom\r
@@ -51,6 +58,32 @@ public class Hyperlink {
         return type;\r
     }\r
 \r
+    public void setType(int val) {\r
+        type = val;\r
+        switch(type){\r
+            case LINK_NEXTSLIDE:\r
+                title = "NEXT";\r
+                address = "1,-1,NEXT";\r
+                break;\r
+            case LINK_PREVIOUSSLIDE:\r
+                title = "PREV";\r
+                address = "1,-1,PREV";\r
+                break;\r
+            case LINK_FIRSTSLIDE:\r
+                title = "FIRST";\r
+                address = "1,-1,FIRST";\r
+                break;\r
+            case LINK_LASTSLIDE:\r
+                title = "LAST";\r
+                address = "1,-1,LAST";\r
+                break;\r
+            default:\r
+                title = "";\r
+                address = "";\r
+                break;\r
+        }\r
+    }\r
+\r
     /**\r
      * Gets the hyperlink URL\r
      *\r
@@ -60,6 +93,18 @@ public class Hyperlink {
         return address;\r
     }\r
 \r
+    public void setAddress(String str) {\r
+        address = str;\r
+    }\r
+\r
+    public int getId() {\r
+        return id;\r
+    }\r
+\r
+    public void setId(int id) {\r
+        this.id = id;\r
+    }\r
+\r
     /**\r
      * Gets the hyperlink user-friendly title (if different from URL)\r
      *\r
@@ -69,6 +114,10 @@ public class Hyperlink {
         return title;\r
     }\r
 \r
+    public void setTitle(String str) {\r
+        title = str;\r
+    }\r
+\r
     /**\r
      * Gets the beginning character position\r
      *\r
index 71d10948c5bc52f236758cc5b6b3d73b30a5071a..d5816b0aad09ee2a78d6167fde741c85ae50fbb1 100644 (file)
@@ -21,6 +21,8 @@ import org.apache.poi.ddf.*;
 import org.apache.poi.util.LittleEndian;
 import org.apache.poi.hslf.record.ColorSchemeAtom;
 import org.apache.poi.hslf.record.Record;
+import org.apache.poi.hslf.record.InteractiveInfo;
+import org.apache.poi.hslf.record.InteractiveInfoAtom;
 import org.apache.poi.hslf.exceptions.HSLFException;
 
 import java.awt.*;
@@ -343,4 +345,57 @@ public class SimpleShape extends Shape {
             _clientData.setRemainingData(out.toByteArray());
         }
     }
+
+    public void setHyperlink(Hyperlink link){
+        if(link.getId() == -1){
+            throw new HSLFException("You must call SlideShow.addHyperlink(Hyperlink link) first");
+        }
+
+        EscherClientDataRecord cldata = new EscherClientDataRecord();
+        cldata.setOptions((short)0xF);
+        getSpContainer().getChildRecords().add(cldata);
+
+        InteractiveInfo info = new InteractiveInfo();
+        InteractiveInfoAtom infoAtom = info.getInteractiveInfoAtom();
+
+        switch(link.getType()){
+            case Hyperlink.LINK_FIRSTSLIDE:
+                infoAtom.setAction(InteractiveInfoAtom.ACTION_JUMP);
+                infoAtom.setJump(InteractiveInfoAtom.JUMP_FIRSTSLIDE);
+                infoAtom.setHyperlinkType(InteractiveInfoAtom.LINK_FirstSlide);
+                break;
+            case Hyperlink.LINK_LASTSLIDE:
+                infoAtom.setAction(InteractiveInfoAtom.ACTION_JUMP);
+                infoAtom.setJump(InteractiveInfoAtom.JUMP_LASTSLIDE);
+                infoAtom.setHyperlinkType(InteractiveInfoAtom.LINK_LastSlide);
+                break;
+            case Hyperlink.LINK_NEXTSLIDE:
+                infoAtom.setAction(InteractiveInfoAtom.ACTION_JUMP);
+                infoAtom.setJump(InteractiveInfoAtom.JUMP_NEXTSLIDE);
+                infoAtom.setHyperlinkType(InteractiveInfoAtom.LINK_NextSlide);
+                break;
+            case Hyperlink.LINK_PREVIOUSSLIDE:
+                infoAtom.setAction(InteractiveInfoAtom.ACTION_JUMP);
+                infoAtom.setJump(InteractiveInfoAtom.JUMP_PREVIOUSSLIDE);
+                infoAtom.setHyperlinkType(InteractiveInfoAtom.LINK_PreviousSlide);
+                break;
+            case Hyperlink.LINK_URL:
+                infoAtom.setAction(InteractiveInfoAtom.ACTION_HYPERLINK);
+                infoAtom.setJump(InteractiveInfoAtom.JUMP_NONE);
+                infoAtom.setHyperlinkType(InteractiveInfoAtom.LINK_Url);
+                break;
+          }
+
+        infoAtom.setHyperlinkID(link.getId());
+
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        try {
+            info.writeOut(out);
+        } catch(Exception e){
+            throw new HSLFException(e);
+        }
+        cldata.setRemainingData(out.toByteArray());
+
+    }
+
 }
index a78c2c27e531d813aab91fe00a1b075f68221f31..f038781534b92c7ddad72861ef0b71294aeec6cb 100644 (file)
@@ -35,19 +35,19 @@ public class CharFlagsTextProp extends BitMaskTextProp {
     public static String NAME = "char_flags";
        public CharFlagsTextProp() {
                super(2,0xffff, NAME, new String[] {
-                               "bold",          // 0x0001
-                               "italic",        // 0x0002
-                               "underline",     // 0x0004
-                               "char_unknown_1",// 0x0008
-                               "shadow",        // 0x0010
-                               "char_unknown_2",// 0x0020
-                               "char_unknown_3",// 0x0040
-                               "char_unknown_4",// 0x0080
-                               "strikethrough", // 0x0100
-                               "relief",        // 0x0200
-                               "reset_numbering",    // 0x0400
-                               "enable_numbering_1", // 0x0800
-                               "enable_numbering_2", // 0x1000
+                               "bold",                 // 0x0001  A bit that specifies whether the characters are bold.
+                               "italic",               // 0x0002  A bit that specifies whether the characters are italicized.
+                               "underline",            // 0x0004  A bit that specifies whether the characters are underlined.
+                               "char_unknown_1",       // 0x0008  Undefined and MUST be ignored.
+                               "shadow",               // 0x0010  A bit that specifies whether the characters have a shadow effect.
+                               "fehint",               // 0x0020  A bit that specifies whether characters originated from double-byte input.
+                               "char_unknown_2",       // 0x0040  Undefined and MUST be ignored.
+                               "kumi",                 // 0x0080  A bit that specifies whether Kumimoji are used for vertical text.
+                               "strikethrough",        // 0x0100  Undefined and MUST be ignored.
+                               "emboss",               // 0x0200  A bit that specifies whether the characters are embossed.
+                "char_unknown_3",       // 0x0400  Undefined and MUST be ignored.
+                "char_unknown_4",       // 0x0800  Undefined and MUST be ignored.
+                "char_unknown_5",       // 0x1000  Undefined and MUST be ignored.
                        }
                );
        }
index bcf4b997c428d63edae4a4c010e8b0d816eca231..f876c7d389413cc05954ec20b8aece96d6d8be18 100644 (file)
@@ -34,6 +34,7 @@ public class TextPropCollection {
        private int charactersCovered;
        private short reservedField;
        private LinkedList textPropList;
+    private int maskSpecial = 0;
 
        /** Fetch the number of characters this styling applies to */
        public int getCharactersCovered() { return charactersCovered; }
@@ -94,21 +95,28 @@ public class TextPropCollection {
                // If we do, decode that, save it, and shuffle on
                for(int i=0; i<potentialProperties.length; i++) {
                        // Check there's still data left to read
-                       if(dataOffset+bytesPassed >= data.length) {
-                               // Out of data, can't be any more properties to go
-                               return bytesPassed;
-                       }
-                       
+
                        // Check if this property is found in the mask
                        if((containsField & potentialProperties[i].getMask()) != 0) {
+                if(dataOffset+bytesPassed >= data.length) {
+                    // Out of data, can't be any more properties to go
+                    // remember the mask and return
+                    maskSpecial |= potentialProperties[i].getMask();
+                    return bytesPassed;
+                }
+
                                // Bingo, data contains this property
                                TextProp prop = (TextProp)potentialProperties[i].clone();
                                int val = 0;
                                if(prop.getSize() == 2) {
                                        val = LittleEndian.getShort(data,dataOffset+bytesPassed);
-                               } else {
+                               } else if(prop.getSize() == 4){
                                        val = LittleEndian.getInt(data,dataOffset+bytesPassed);
-                               }
+                               } else if (prop.getSize() == 0){
+                    //remember "special" bits.
+                    maskSpecial |= potentialProperties[i].getMask();
+                    continue;
+                }
                                prop.setValue(val);
                                bytesPassed += prop.getSize();
                                textPropList.add(prop);
@@ -161,15 +169,18 @@ public class TextPropCollection {
                }
 
                // Then the mask field
-               int mask = 0;
+               int mask = maskSpecial;
                for(int i=0; i<textPropList.size(); i++) {
                        TextProp textProp = (TextProp)textPropList.get(i);
             //sometimes header indicates that the bitmask is present but its value is 0
-            if (textProp instanceof BitMaskTextProp)
-                mask |= (textProp.getWriteMask() == 0 ? 1 : textProp.getWriteMask());
-            else
+
+            if (textProp instanceof BitMaskTextProp) {
+                if(mask == 0) mask |=  textProp.getWriteMask();
+            }
+            else {
                 mask |= textProp.getWriteMask();
-               }
+            }
+        }
                StyleTextPropAtom.writeLittleEndian(mask,o);
 
                // Then the contents of all the properties
@@ -178,7 +189,7 @@ public class TextPropCollection {
                        int val = textProp.getValue();
                        if(textProp.getSize() == 2) {
                                StyleTextPropAtom.writeLittleEndian((short)val,o);
-                       } else {
+                       } else if(textProp.getSize() == 4){
                                StyleTextPropAtom.writeLittleEndian(val,o);
                        }
                }
index b0bc1e191fbc6b5d583ab4c0ffd2fe4bbda8ea30..3ea5b0159ded8ddb63a7eea205429119e9579484 100644 (file)
@@ -63,14 +63,16 @@ public class ExHyperlink extends RecordContainer {
         * TODO: Figure out if we should always set both
         */
        public void setLinkURL(String url) {
-               linkDetailsA.setText(url);
-
-               // linkDetailsB isn't present in all PPT versions
                if(linkDetailsB != null) {
                        linkDetailsB.setText(url);
                }
        }
-       
+    public void setLinkTitle(String title) {
+        if(linkDetailsA != null) {
+            linkDetailsA.setText(title);
+        }
+    }
+
        /**
         * Get the link details (field A)
         */
index 7b2304074f02dab8a323dc98ff8f6289876432ec..1207c68b3b72f4245a16e0c1869dcbd90aa35814 100644 (file)
@@ -124,47 +124,54 @@ public class StyleTextPropAtom extends RecordAtom
 
        /** All the different kinds of paragraph properties we might handle */
        public static TextProp[] paragraphTextPropTypes = new TextProp[] {
-                               new ParagraphFlagsTextProp(),
+                new TextProp(0, 0x1, "hasBullet"),
+                new TextProp(0, 0x2, "hasBulletFont"),
+                new TextProp(0, 0x4, "hasBulletColor"),
+                new TextProp(0, 0x8, "hasBulletSize"),
+                new ParagraphFlagsTextProp(),
                 new TextProp(2, 0x80, "bullet.char"),
                                new TextProp(2, 0x10, "bullet.font"),
                 new TextProp(2, 0x40, "bullet.size"),
                                new TextProp(4, 0x20, "bullet.color"),
                 new AlignmentTextProp(),
                 new TextProp(2, 0x100, "text.offset"),
-                               new TextProp(2, 0x200, "para_unknown_2"),
                 new TextProp(2, 0x400, "bullet.offset"),
-                               new TextProp(2, 0x1000, "linespacing"),
-                               new TextProp(2, 0x2000, "spacebefore"),
-                               new TextProp(2, 0x4000, "spaceafter"),
-                               new TextProp(2, 0x8000, "para_unknown_4"),
-                               new TextProp(2, 0x10000, "para_unknown_5"),
-                               new TextProp(2, 0xA0000, "para_unknown_6"),
-                               new TextProp(2, 0x200000, "para_unknown_7")
+                new TextProp(2, 0x1000, "linespacing"),
+                new TextProp(2, 0x2000, "spacebefore"),
+                new TextProp(2, 0x4000, "spaceafter"),
+                new TextProp(2, 0x8000, "defaultTabSize"),
+                               new TextProp(2, 0x100000, "tabStops"),
+                               new TextProp(2, 0x10000, "fontAlign"),
+                               new TextProp(2, 0xA0000, "wrapFlags"),
+                               new TextProp(2, 0x200000, "textDirection")
        };
        /** All the different kinds of character properties we might handle */
        public static TextProp[] characterTextPropTypes = new TextProp[] {
-                               new CharFlagsTextProp(),
+                new TextProp(0, 0x1, "bold"),
+                new TextProp(0, 0x2, "italic"),
+                new TextProp(0, 0x4, "underline"),
+                new TextProp(0, 0x8, "unused1"),
+                new TextProp(0, 0x10, "shadow"),
+                new TextProp(0, 0x20, "fehint"),
+                new TextProp(0, 0x40, "unused2"),
+                new TextProp(0, 0x80, "kumi"),
+                new TextProp(0, 0x100, "unused3"),
+                new TextProp(0, 0x200, "emboss"),
+                new CharFlagsTextProp(),
                                new TextProp(2, 0x10000, "font.index"),
-                new TextProp(2, 0x200000, "asian_or_complex"),
-                new TextProp(2, 0x400000, "char_unknown_2"),
-                new TextProp(2, 0x800000, "symbol"),
+                new TextProp(0, 0x100000, "pp10ext"),
+                new TextProp(2, 0x200000, "asian.font.index"),
+                new TextProp(2, 0x400000, "ansi.font.index"),
+                new TextProp(2, 0x800000, "symbol.font.index"),
                                new TextProp(2, 0x20000, "font.size"),
                                new TextProp(4, 0x40000, "font.color"),
-                               new TextProp(2, 0x80000, "superscript"),
-                               new TextProp(2, 0x100000, "char_unknown_1"),
-                               new TextProp(2, 0x1000000, "char_unknown_3"),
-                               new TextProp(2, 0x2000000, "char_unknown_4"),
-                               new TextProp(2, 0x4000000, "char_unknown_5"),
-                               new TextProp(2, 0x8000000, "char_unknown_6"),
-                               new TextProp(2, 0x10000000, "char_unknown_7"),
-                               new TextProp(2, 0x20000000, "char_unknown_8"),
-                               new TextProp(2, 0x40000000, "char_unknown_9"),
-                               new TextProp(2, 0x80000000, "char_unknown_10"),
-       };
+                new TextProp(2, 0x80000, "superscript"),
+
+    };
 
        /* *************** record code follows ********************** */
 
-       /** 
+       /**
         * For the Text Style Properties (StyleTextProp) Atom
         */
        public StyleTextPropAtom(byte[] source, int start, int len) {
@@ -192,7 +199,7 @@ public class StyleTextPropAtom extends RecordAtom
        }
 
 
-       /** 
+       /**
         * A new set of text style properties for some text without any.
         */
        public StyleTextPropAtom(int parentTextSize) {
@@ -209,11 +216,11 @@ public class StyleTextPropAtom extends RecordAtom
                paragraphStyles = new LinkedList();
                charStyles = new LinkedList();
 
-               TextPropCollection defaultParagraphTextProps = 
+               TextPropCollection defaultParagraphTextProps =
                        new TextPropCollection(parentTextSize, (short)0);
                paragraphStyles.add(defaultParagraphTextProps);
 
-               TextPropCollection defaultCharacterTextProps = 
+               TextPropCollection defaultCharacterTextProps =
                        new TextPropCollection(parentTextSize);
                charStyles.add(defaultCharacterTextProps);
 
@@ -269,8 +276,7 @@ public class StyleTextPropAtom extends RecordAtom
                        textHandled += textLen;
                        pos += 4;
 
-                       // Fetch the 2 byte value that is safe to ignore as 0
-                       short paraIgn = LittleEndian.getShort(rawContents,pos);
+                       short indent = LittleEndian.getShort(rawContents,pos);
                        pos += 2;
 
                        // Grab the 4 byte value that tells us what properties follow
@@ -278,7 +284,7 @@ public class StyleTextPropAtom extends RecordAtom
                        pos += 4;
 
                        // Now make sense of those properties
-                       TextPropCollection thisCollection = new TextPropCollection(textLen, paraIgn);
+                       TextPropCollection thisCollection = new TextPropCollection(textLen, indent);
                        int plSize = thisCollection.buildTextPropList(
                                        paraFlags, paragraphTextPropTypes, rawContents, pos);
                        pos += plSize;
index f480a30aa5632a053abb9e8e7a2fb0ce2e6a2917..80bc2e855aeaa4add319d34c2567c2ef8a356425 100644 (file)
@@ -920,7 +920,7 @@ public final class SlideShow {
      * @return 0-based index of the control
      */
     public int addControl(String name, String progId) {
-        ExObjList lst = _documentRecord.getExObjList();
+        ExObjList lst = (ExObjList)_documentRecord.findFirstOfType(RecordTypes.ExObjList.typeID);
         if (lst == null) {
             lst = new ExObjList();
             _documentRecord.addChildAfter(lst, _documentRecord.getDocumentAtom());
@@ -943,4 +943,31 @@ public final class SlideShow {
 
         return objectId;
     }
+
+    /**
+     * Add a hyperlink to this presentation
+     *
+     * @return 0-based index of the hyperlink
+     */
+    public int addHyperlink(Hyperlink link) {
+        ExObjList lst = (ExObjList)_documentRecord.findFirstOfType(RecordTypes.ExObjList.typeID);
+        if (lst == null) {
+            lst = new ExObjList();
+            _documentRecord.addChildAfter(lst, _documentRecord.getDocumentAtom());
+        }
+        ExObjListAtom objAtom = lst.getExObjListAtom();
+        //increment the object ID seed
+        int objectId = (int) objAtom.getObjectIDSeed() + 1;
+        objAtom.setObjectIDSeed(objectId);
+
+        ExHyperlink ctrl = new ExHyperlink();
+        ExHyperlinkAtom obj = ctrl.getExHyperlinkAtom();
+        obj.setNumber(objectId);
+        ctrl.setLinkURL(link.getAddress());
+        ctrl.setLinkTitle(link.getTitle());
+        lst.addChildAfter(ctrl, objAtom);
+        link.setId(objectId);
+
+        return objectId;
+    }
 }
index 5f5995afb10582985b1a7dfdecc2abcfe0527060..3a7c5c20e0a555ba42e79d1db470b66d6f8c1ba2 100644 (file)
@@ -760,12 +760,8 @@ public final class HSSFChart {
                r.setIndexNumberFmtRecord( (short) 0 );
                LinkedDataFormulaField formula = new LinkedDataFormulaField();
                Stack tokens = new Stack();
-               Area3DPtg p = new Area3DPtg();
-               p.setExternSheetIndex( (short) 0 );
-               p.setFirstColumn( (short) 1 );
-               p.setLastColumn( (short) 1 );
-               p.setFirstRow( (short) 0 );
-               p.setLastRow( (short) 31 );
+               Area3DPtg p = new Area3DPtg(0, 31, 1, 1,
+                       false, false, false, false, 0);
                tokens.add( p );
                formula.setFormulaTokens( tokens );
                r.setFormulaOfLink( formula );
@@ -781,12 +777,8 @@ public final class HSSFChart {
                r.setIndexNumberFmtRecord( (short) 0 );
                LinkedDataFormulaField formula = new LinkedDataFormulaField();
                Stack tokens = new Stack();
-               Area3DPtg p = new Area3DPtg();
-               p.setExternSheetIndex( (short) 0 );
-               p.setFirstColumn( (short) 0 );
-               p.setLastColumn( (short) 0 );
-               p.setFirstRow( (short) 0 );
-               p.setLastRow( (short) 31 );
+               Area3DPtg p = new Area3DPtg(0, 31, 0, 0,
+                               false, false, false, false, 0);
                tokens.add( p );
                formula.setFormulaTokens( tokens );
                r.setFormulaOfLink( formula );
index 7b1f614ee7e707be56a8ca972f9dc226b86f7c8d..17f9010eb2d4861b95e0cc1d9c341c9edc02a862 100644 (file)
@@ -31,6 +31,7 @@ import org.apache.poi.util.HexDump;
 import junit.framework.TestCase;
 import java.io.ByteArrayOutputStream;
 import java.util.LinkedList;
+import java.util.Arrays;
 
 /**
  * Tests that StyleTextPropAtom works properly
@@ -38,9 +39,9 @@ import java.util.LinkedList;
  * @author Nick Burch (nick at torchbox dot com)
  */
 public class TestStyleTextPropAtom extends TestCase {
-       /** From a real file: a paragraph with 4 different styles */
-       private byte[] data_a = new byte[] { 
-         0, 0, 0xA1-256, 0x0F, 0x2A, 0, 0, 0,
+    /** From a real file: a paragraph with 4 different styles */
+    private byte[] data_a = new byte[] {
+      0, 0, 0xA1-256, 0x0F, 0x2A, 0, 0, 0,
       0x36, 00, 00, 00, // paragraph is 54 long 
       00, 00,           // (paragraph reserved field)
       00, 00, 00, 00,   // it doesn't have any styles
@@ -52,84 +53,84 @@ public class TestStyleTextPropAtom extends TestCase {
       0x10, 00, 00, 00, // third char run is 16 long
       00, 00, 0x04, 00, // font.color only
       0xFF-256, 0x33, 00, 0xFE-256 // red
-       };
-       private int data_a_text_len = 0x36-1;
-
-       /** 
-        * From a real file: 4 paragraphs with text in 4 different styles:
-        * left aligned+bold (30)
-        * centre aligned+italic+blue (28)
-        * right aligned+red (25)
-        * left aligned+underlined+larger font size (96)
-        * left aligned+underlined+larger font size+red (1)
-        */
-       private byte[] data_b = new byte[] { 
-               0, 0, 0xA1-256, 0x0F, 0x80-256, 0, 0, 0, 
-               0x1E, 00, 00, 00,     // paragraph is 30 long 
-               00, 00,               // paragraph reserved field
-               00, 0x18, 00, 00,     // mask is 0x1800
-               00, 00,               // left aligned
-               0x50, 00,             // line spacing 80
-               0x1C, 00, 00, 00,     // paragprah is 28 long 
-               00, 00,               // paragraph reserved field
-               00, 0x10, 00, 00,     // mask is 0x1000
-               0x50, 00,             // line spacing 80
-               0x19, 00, 00, 00,     // paragraph is 25 long
-           00, 00,               // paragraph reserved field
-           00, 0x18, 00, 00,     // mask is 0x1800 
-           02, 00,               // right aligned
-           0x50, 00,             // line spacing 80
-           0x61, 00, 00, 00,     // paragraph is 97 long
-           00, 00,               // paragraph reserved field
-           00, 0x18, 00, 00,     // mask is 0x1800
-           00, 00,               // left aligned
-           0x50, 00,             // line spacing 80
-           
-           0x1E, 00, 00, 00,     // character run is 30 long
-           01, 00, 02, 00,       // mask is 0x020001
-           01, 00,               // char flags 0x0001 = bold
-           0x14, 00,             // font size 20
-           0x1C, 00, 00, 00,     // character run is 28 long
-           02, 00, 06, 00,       // mask is 0x060002
-           02, 00,               // char flags 0x0002 = italic
-           0x14, 00,             // font size 20
-           00, 00, 00, 05,       // colour blue
-           0x19, 00, 00, 00,     // character run is 25 long
-           00, 00, 06, 00,       // char flags 0x060000
-           0x14, 00,             // font size 20
-           0xFF-256, 0x33, 00, 0xFE-256, // colour red
-           0x60, 00, 00, 00,     // character run is 96 long
-           04, 00, 03, 00,       // mask is 0x030004
-           04, 00,               // char flags 0x0004 = underlined
-           01, 00,               // font index is 1
-           0x18, 00,             // font size 24
-           
-           01, 00, 00, 00,       // character run is 1 long
-           04, 00, 07, 00,       // mask is 0x070004
-           04, 00,               // char flags 0x0004 = underlined
-           01, 00,               // font index is 1 
-           0x18, 00,             // font size 24
-           0xFF-256, 0x33, 00, 0xFE-256 // colour red
-       };
-       private int data_b_text_len = 0xB3;
-       
-       /**
-        * From a real file. Has a mask with more bits
-        *  set than it actually has data for. Shouldn't do,
-        *  but some real files do :(
-        */
-       private byte[] data_c = new byte[] {
-               0, 0, -95, 15, 62, 0, 0, 0,
-               123, 0, 0, 0, 0, 0, 48, 8, 
-               10, 0, 1, 0, 0, 0, 0, 0, 
-               1, 0, 2, 0, 1, 0, 0, 0, 
-               0, 0, 48, 0, 10, 0, 1, 0, 
-               0, 0, 0, 0, 2, 0, 123, 0, 
-               0, 0, 0, 0, 3, 0, 1, 0, 
-               28, 0, 1, 0, 0, 0, 0, 0, 
-               3, 0, 1, 0, 24, 0
-       };
-       private int data_c_text_len = 123-1;
+    };
+    private int data_a_text_len = 0x36-1;
+
+    /**
+     * From a real file: 4 paragraphs with text in 4 different styles:
+     * left aligned+bold (30)
+     * centre aligned+italic+blue (28)
+     * right aligned+red (25)
+     * left aligned+underlined+larger font size (96)
+     * left aligned+underlined+larger font size+red (1)
+     */
+    private byte[] data_b = new byte[] {
+        0, 0, 0xA1-256, 0x0F, 0x80-256, 0, 0, 0,
+        0x1E, 00, 00, 00,     // paragraph is 30 long
+        00, 00,               // paragraph reserved field
+        00, 0x18, 00, 00,     // mask is 0x1800
+        00, 00,               // left aligned
+        0x50, 00,             // line spacing 80
+        0x1C, 00, 00, 00,     // paragprah is 28 long
+        00, 00,               // paragraph reserved field
+        00, 0x10, 00, 00,     // mask is 0x1000
+        0x50, 00,             // line spacing 80
+        0x19, 00, 00, 00,     // paragraph is 25 long
+        00, 00,               // paragraph reserved field
+        00, 0x18, 00, 00,     // mask is 0x1800
+        02, 00,               // right aligned
+        0x50, 00,             // line spacing 80
+        0x61, 00, 00, 00,     // paragraph is 97 long
+        00, 00,               // paragraph reserved field
+        00, 0x18, 00, 00,     // mask is 0x1800
+        00, 00,               // left aligned
+        0x50, 00,             // line spacing 80
+
+        0x1E, 00, 00, 00,     // character run is 30 long
+        01, 00, 02, 00,       // mask is 0x020001
+        01, 00,               // char flags 0x0001 = bold
+        0x14, 00,             // font size 20
+        0x1C, 00, 00, 00,     // character run is 28 long
+        02, 00, 06, 00,       // mask is 0x060002
+        02, 00,               // char flags 0x0002 = italic
+        0x14, 00,             // font size 20
+        00, 00, 00, 05,       // colour blue
+        0x19, 00, 00, 00,     // character run is 25 long
+        00, 00, 06, 00,       // char flags 0x060000
+        0x14, 00,             // font size 20
+        0xFF-256, 0x33, 00, 0xFE-256, // colour red
+        0x60, 00, 00, 00,     // character run is 96 long
+        04, 00, 03, 00,       // mask is 0x030004
+        04, 00,               // char flags 0x0004 = underlined
+        01, 00,               // font index is 1
+        0x18, 00,             // font size 24
+
+        01, 00, 00, 00,       // character run is 1 long
+        04, 00, 07, 00,       // mask is 0x070004
+        04, 00,               // char flags 0x0004 = underlined
+        01, 00,               // font index is 1
+        0x18, 00,             // font size 24
+        0xFF-256, 0x33, 00, 0xFE-256 // colour red
+    };
+    private int data_b_text_len = 0xB3;
+
+    /**
+     * From a real file. Has a mask with more bits
+     *  set than it actually has data for. Shouldn't do,
+     *  but some real files do :(
+     */
+    private byte[] data_c = new byte[] {
+        0, 0, -95, 15, 62, 0, 0, 0,
+        123, 0, 0, 0, 0, 0, 48, 8,
+        10, 0, 1, 0, 0, 0, 0, 0,
+        1, 0, 2, 0, 1, 0, 0, 0,
+        0, 0, 48, 0, 10, 0, 1, 0,
+        0, 0, 0, 0, 2, 0, 123, 0,
+        0, 0, 0, 0, 3, 0, 1, 0,
+        28, 0, 1, 0, 0, 0, 0, 0,
+        3, 0, 1, 0, 24, 0
+    };
+    private int data_c_text_len = 123-1;
 
     /**
      * From a real file supplied for Bug 40143 by tales@great.ufc.br
@@ -143,576 +144,563 @@ public class TestStyleTextPropAtom extends TestCase {
     private int data_d_text_len = 0xA0-1;
 
     public void testRecordType() throws Exception {
-               StyleTextPropAtom stpa = new StyleTextPropAtom(data_a,0,data_a.length);
-               StyleTextPropAtom stpb = new StyleTextPropAtom(data_b,0,data_b.length);
-               StyleTextPropAtom stpc = new StyleTextPropAtom(data_c,0,data_c.length);
-               assertEquals(4001l, stpa.getRecordType());
-               assertEquals(4001l, stpb.getRecordType());
-               assertEquals(4001l, stpc.getRecordType());
-       }
-
-
-       public void testCharacterStyleCounts() throws Exception {
-               StyleTextPropAtom stpa = new StyleTextPropAtom(data_a,0,data_a.length);
-               StyleTextPropAtom stpb = new StyleTextPropAtom(data_b,0,data_b.length);
-
-               // Set for the appropriate text sizes
-               stpa.setParentTextSize(data_a_text_len);
-               stpb.setParentTextSize(data_b_text_len);
-
-               // In case A, there is a single styling of the characters
-               assertEquals(3, stpa.getCharacterStyles().size());
-               // In case B, there are 5 different stylings
-               assertEquals(5, stpb.getCharacterStyles().size());
-       }
-
-       public void testParagraphStyleCounts() throws Exception {
-               StyleTextPropAtom stpa = new StyleTextPropAtom(data_a,0,data_a.length);
-               StyleTextPropAtom stpb = new StyleTextPropAtom(data_b,0,data_b.length);
-
-               // Set for the appropriate text sizes
-               stpa.setParentTextSize(data_a_text_len);
-               stpb.setParentTextSize(data_b_text_len);
-
-               // In case A, all has the same spacing and alignment
-               assertEquals(1, stpa.getParagraphStyles().size());
-               // In case B, all 4 sets have different alignments
-               assertEquals(4, stpb.getParagraphStyles().size());
-       }
-
-
-       public void testCharacterStyleLengths() throws Exception {
-               StyleTextPropAtom stpa = new StyleTextPropAtom(data_a,0,data_a.length);
-               StyleTextPropAtom stpb = new StyleTextPropAtom(data_b,0,data_b.length);
-
-               // Set for the appropriate text sizes
-               stpa.setParentTextSize(data_a_text_len);
-               stpb.setParentTextSize(data_b_text_len);
-
-               // 54 chars, 21 + 17 + 16
-               LinkedList a_ch_l = stpa.getCharacterStyles();
-               TextPropCollection a_ch_1 = (TextPropCollection)a_ch_l.get(0);
-               TextPropCollection a_ch_2 = (TextPropCollection)a_ch_l.get(1);
-               TextPropCollection a_ch_3 = (TextPropCollection)a_ch_l.get(2);
-               assertEquals(21, a_ch_1.getCharactersCovered());
-               assertEquals(17, a_ch_2.getCharactersCovered());
-               assertEquals(16, a_ch_3.getCharactersCovered());
-
-               // 179 chars, 30 + 28 + 25
-               LinkedList b_ch_l = stpb.getCharacterStyles();
-               TextPropCollection b_ch_1 = (TextPropCollection)b_ch_l.get(0);
-               TextPropCollection b_ch_2 = (TextPropCollection)b_ch_l.get(1);
-               TextPropCollection b_ch_3 = (TextPropCollection)b_ch_l.get(2);
-               TextPropCollection b_ch_4 = (TextPropCollection)b_ch_l.get(3);
-               assertEquals(30, b_ch_1.getCharactersCovered());
-               assertEquals(28, b_ch_2.getCharactersCovered());
-               assertEquals(25, b_ch_3.getCharactersCovered());
-               assertEquals(96, b_ch_4.getCharactersCovered());
-       }
-
-
-       public void testCharacterPropOrdering() throws Exception {
-               StyleTextPropAtom stpb = new StyleTextPropAtom(data_b,0,data_b.length);
-               stpb.setParentTextSize(data_b_text_len);
-
-               LinkedList b_ch_l = stpb.getCharacterStyles();
-               TextPropCollection b_ch_1 = (TextPropCollection)b_ch_l.get(0);
-               TextPropCollection b_ch_2 = (TextPropCollection)b_ch_l.get(1);
-               TextPropCollection b_ch_3 = (TextPropCollection)b_ch_l.get(2);
-               TextPropCollection b_ch_4 = (TextPropCollection)b_ch_l.get(3);
-               
-               // In first set, we get a CharFlagsTextProp and a font.size
-               assertEquals(2,b_ch_1.getTextPropList().size());
-               TextProp tp_1_1 = (TextProp)b_ch_1.getTextPropList().get(0);
-               TextProp tp_1_2 = (TextProp)b_ch_1.getTextPropList().get(1);
-               assertEquals(true, tp_1_1 instanceof CharFlagsTextProp);
-               assertEquals(true, tp_1_2 instanceof TextProp);
-               assertEquals("font.size", tp_1_2.getName());
-               assertEquals(20, tp_1_2.getValue());
-               
-               // In second set, we get a CharFlagsTextProp and a font.size and a font.color
-               assertEquals(3,b_ch_2.getTextPropList().size());
-               TextProp tp_2_1 = (TextProp)b_ch_2.getTextPropList().get(0);
-               TextProp tp_2_2 = (TextProp)b_ch_2.getTextPropList().get(1);
-               TextProp tp_2_3 = (TextProp)b_ch_2.getTextPropList().get(2);
-               assertEquals(true, tp_2_1 instanceof CharFlagsTextProp);
-               assertEquals(true, tp_2_2 instanceof TextProp);
-               assertEquals(true, tp_2_3 instanceof TextProp);
-               assertEquals("font.size", tp_2_2.getName());
-               assertEquals("font.color", tp_2_3.getName());
-               assertEquals(20, tp_2_2.getValue());
-               
-               // In third set, it's just a font.size and a font.color
-               assertEquals(2,b_ch_3.getTextPropList().size());
-               TextProp tp_3_1 = (TextProp)b_ch_3.getTextPropList().get(0);
-               TextProp tp_3_2 = (TextProp)b_ch_3.getTextPropList().get(1);
-               assertEquals(true, tp_3_1 instanceof TextProp);
-               assertEquals(true, tp_3_2 instanceof TextProp);
-               assertEquals("font.size", tp_3_1.getName());
-               assertEquals("font.color", tp_3_2.getName());
-               assertEquals(20, tp_3_1.getValue());
-               
-               // In fourth set, we get a CharFlagsTextProp and a font.index and a font.size
-               assertEquals(3,b_ch_4.getTextPropList().size());
-               TextProp tp_4_1 = (TextProp)b_ch_4.getTextPropList().get(0);
-               TextProp tp_4_2 = (TextProp)b_ch_4.getTextPropList().get(1);
-               TextProp tp_4_3 = (TextProp)b_ch_4.getTextPropList().get(2);
-               assertEquals(true, tp_4_1 instanceof CharFlagsTextProp);
-               assertEquals(true, tp_4_2 instanceof TextProp);
-               assertEquals(true, tp_4_3 instanceof TextProp);
-               assertEquals("font.index", tp_4_2.getName());
-               assertEquals("font.size", tp_4_3.getName());
-               assertEquals(24, tp_4_3.getValue());
-       }
-
-       public void testParagraphProps() throws Exception {
-               StyleTextPropAtom stpb = new StyleTextPropAtom(data_b,0,data_b.length);
-               stpb.setParentTextSize(data_b_text_len);
-               
-               LinkedList b_p_l = stpb.getParagraphStyles();
-               TextPropCollection b_p_1 = (TextPropCollection)b_p_l.get(0);
-               TextPropCollection b_p_2 = (TextPropCollection)b_p_l.get(1);
-               TextPropCollection b_p_3 = (TextPropCollection)b_p_l.get(2);
-               TextPropCollection b_p_4 = (TextPropCollection)b_p_l.get(3);
-               
-               // 1st is left aligned + normal line spacing
-               assertEquals(2,b_p_1.getTextPropList().size());
-               TextProp tp_1_1 = (TextProp)b_p_1.getTextPropList().get(0);
-               TextProp tp_1_2 = (TextProp)b_p_1.getTextPropList().get(1);
-               assertEquals(true, tp_1_1 instanceof TextProp);
-               assertEquals(true, tp_1_2 instanceof TextProp);
-               assertEquals("alignment", tp_1_1.getName());
-               assertEquals("linespacing", tp_1_2.getName());
-               assertEquals(0, tp_1_1.getValue());
-               assertEquals(80, tp_1_2.getValue());
-               
-               // 2nd is centre aligned (default) + normal line spacing
-               assertEquals(1,b_p_2.getTextPropList().size());
-               TextProp tp_2_1 = (TextProp)b_p_2.getTextPropList().get(0);
-               assertEquals(true, tp_2_1 instanceof TextProp);
-               assertEquals(true, tp_1_2 instanceof TextProp);
-               assertEquals("linespacing", tp_2_1.getName());
-               assertEquals(80, tp_2_1.getValue());
-               
-               // 3rd is right aligned + normal line spacing
-               assertEquals(2,b_p_3.getTextPropList().size());
-               TextProp tp_3_1 = (TextProp)b_p_3.getTextPropList().get(0);
-               TextProp tp_3_2 = (TextProp)b_p_3.getTextPropList().get(1);
-               assertEquals(true, tp_3_1 instanceof TextProp);
-               assertEquals(true, tp_3_2 instanceof TextProp);
-               assertEquals("alignment", tp_3_1.getName());
-               assertEquals("linespacing", tp_3_2.getName());
-               assertEquals(2, tp_3_1.getValue());
-               assertEquals(80, tp_3_2.getValue());
-               
-               // 4st is left aligned + normal line spacing (despite differing font)
-               assertEquals(2,b_p_4.getTextPropList().size());
-               TextProp tp_4_1 = (TextProp)b_p_4.getTextPropList().get(0);
-               TextProp tp_4_2 = (TextProp)b_p_4.getTextPropList().get(1);
-               assertEquals(true, tp_4_1 instanceof TextProp);
-               assertEquals(true, tp_4_2 instanceof TextProp);
-               assertEquals("alignment", tp_4_1.getName());
-               assertEquals("linespacing", tp_4_2.getName());
-               assertEquals(0, tp_4_1.getValue());
-               assertEquals(80, tp_4_2.getValue());
-       }
-
-       public void testCharacterProps() throws Exception {
-               StyleTextPropAtom stpb = new StyleTextPropAtom(data_b,0,data_b.length);
-               stpb.setParentTextSize(data_b_text_len);
-
-               LinkedList b_ch_l = stpb.getCharacterStyles();
-               TextPropCollection b_ch_1 = (TextPropCollection)b_ch_l.get(0);
-               TextPropCollection b_ch_2 = (TextPropCollection)b_ch_l.get(1);
-               TextPropCollection b_ch_3 = (TextPropCollection)b_ch_l.get(2);
-               TextPropCollection b_ch_4 = (TextPropCollection)b_ch_l.get(3);
-
-               // 1st is bold
-               CharFlagsTextProp cf_1_1 = (CharFlagsTextProp)b_ch_1.getTextPropList().get(0);
-               assertEquals(true,cf_1_1.getSubValue(CharFlagsTextProp.BOLD_IDX));
-               assertEquals(false,cf_1_1.getSubValue(CharFlagsTextProp.ITALIC_IDX));
-               assertEquals(false,cf_1_1.getSubValue(CharFlagsTextProp.ENABLE_NUMBERING_1_IDX));
-               assertEquals(false,cf_1_1.getSubValue(CharFlagsTextProp.ENABLE_NUMBERING_2_IDX));
-               assertEquals(false,cf_1_1.getSubValue(CharFlagsTextProp.RELIEF_IDX));
-               assertEquals(false,cf_1_1.getSubValue(CharFlagsTextProp.RESET_NUMBERING_IDX));
-               assertEquals(false,cf_1_1.getSubValue(CharFlagsTextProp.SHADOW_IDX));
-               assertEquals(false,cf_1_1.getSubValue(CharFlagsTextProp.STRIKETHROUGH_IDX));
-               assertEquals(false,cf_1_1.getSubValue(CharFlagsTextProp.UNDERLINE_IDX));
-               
-               // 2nd is italic
-               CharFlagsTextProp cf_2_1 = (CharFlagsTextProp)b_ch_2.getTextPropList().get(0);
-               assertEquals(false,cf_2_1.getSubValue(CharFlagsTextProp.BOLD_IDX));
-               assertEquals(true,cf_2_1.getSubValue(CharFlagsTextProp.ITALIC_IDX));
-               assertEquals(false,cf_2_1.getSubValue(CharFlagsTextProp.ENABLE_NUMBERING_1_IDX));
-               assertEquals(false,cf_2_1.getSubValue(CharFlagsTextProp.ENABLE_NUMBERING_2_IDX));
-               assertEquals(false,cf_2_1.getSubValue(CharFlagsTextProp.RELIEF_IDX));
-               assertEquals(false,cf_2_1.getSubValue(CharFlagsTextProp.RESET_NUMBERING_IDX));
-               assertEquals(false,cf_2_1.getSubValue(CharFlagsTextProp.SHADOW_IDX));
-               assertEquals(false,cf_2_1.getSubValue(CharFlagsTextProp.STRIKETHROUGH_IDX));
-               assertEquals(false,cf_2_1.getSubValue(CharFlagsTextProp.UNDERLINE_IDX));
-
-               // 3rd is normal, so lacks a CharFlagsTextProp
-               assertFalse(b_ch_3.getTextPropList().get(0) instanceof CharFlagsTextProp);
-               
-               // 4th is underlined
-               CharFlagsTextProp cf_4_1 = (CharFlagsTextProp)b_ch_4.getTextPropList().get(0);
-               assertEquals(false,cf_4_1.getSubValue(CharFlagsTextProp.BOLD_IDX));
-               assertEquals(false,cf_4_1.getSubValue(CharFlagsTextProp.ITALIC_IDX));
-               assertEquals(false,cf_4_1.getSubValue(CharFlagsTextProp.ENABLE_NUMBERING_1_IDX));
-               assertEquals(false,cf_4_1.getSubValue(CharFlagsTextProp.ENABLE_NUMBERING_2_IDX));
-               assertEquals(false,cf_4_1.getSubValue(CharFlagsTextProp.RELIEF_IDX));
-               assertEquals(false,cf_4_1.getSubValue(CharFlagsTextProp.RESET_NUMBERING_IDX));
-               assertEquals(false,cf_4_1.getSubValue(CharFlagsTextProp.SHADOW_IDX));
-               assertEquals(false,cf_4_1.getSubValue(CharFlagsTextProp.STRIKETHROUGH_IDX));
-               assertEquals(true,cf_4_1.getSubValue(CharFlagsTextProp.UNDERLINE_IDX));
-               
-               // The value for this should be 4
-               assertEquals(0x0004, cf_4_1.getValue());
-               
-               // Now make the 4th bold, italic and not underlined
-               cf_4_1.setSubValue(true, CharFlagsTextProp.BOLD_IDX);
-               cf_4_1.setSubValue(true, CharFlagsTextProp.ITALIC_IDX);
-               cf_4_1.setSubValue(false, CharFlagsTextProp.UNDERLINE_IDX);
-               
-               assertEquals(true,cf_4_1.getSubValue(CharFlagsTextProp.BOLD_IDX));
-               assertEquals(true,cf_4_1.getSubValue(CharFlagsTextProp.ITALIC_IDX));
-               assertEquals(false,cf_4_1.getSubValue(CharFlagsTextProp.ENABLE_NUMBERING_1_IDX));
-               assertEquals(false,cf_4_1.getSubValue(CharFlagsTextProp.ENABLE_NUMBERING_2_IDX));
-               assertEquals(false,cf_4_1.getSubValue(CharFlagsTextProp.RELIEF_IDX));
-               assertEquals(false,cf_4_1.getSubValue(CharFlagsTextProp.RESET_NUMBERING_IDX));
-               assertEquals(false,cf_4_1.getSubValue(CharFlagsTextProp.SHADOW_IDX));
-               assertEquals(false,cf_4_1.getSubValue(CharFlagsTextProp.STRIKETHROUGH_IDX));
-               assertEquals(false,cf_4_1.getSubValue(CharFlagsTextProp.UNDERLINE_IDX));
-               
-               // The value should now be 3
-               assertEquals(0x0003, cf_4_1.getValue());
-       }
-       
-       public void testFindAddTextProp() {
-               StyleTextPropAtom stpb = new StyleTextPropAtom(data_b,0,data_b.length);
-               stpb.setParentTextSize(data_b_text_len);
-
-               LinkedList b_p_l = stpb.getParagraphStyles();
-               TextPropCollection b_p_1 = (TextPropCollection)b_p_l.get(0);
-               TextPropCollection b_p_2 = (TextPropCollection)b_p_l.get(1);
-               TextPropCollection b_p_3 = (TextPropCollection)b_p_l.get(2);
-               TextPropCollection b_p_4 = (TextPropCollection)b_p_l.get(3);
-               
-               LinkedList b_ch_l = stpb.getCharacterStyles();
-               TextPropCollection b_ch_1 = (TextPropCollection)b_ch_l.get(0);
-               TextPropCollection b_ch_2 = (TextPropCollection)b_ch_l.get(1);
-               TextPropCollection b_ch_3 = (TextPropCollection)b_ch_l.get(2);
-               TextPropCollection b_ch_4 = (TextPropCollection)b_ch_l.get(3);
-
-               // CharFlagsTextProp: 3 doesn't have, 4 does
-               assertNull(b_ch_3.findByName("char_flags"));
-               assertNotNull(b_ch_4.findByName("char_flags"));
-               
-               // Now add in on 3, should go to front
-               assertEquals(2, b_ch_3.getTextPropList().size());
-               TextProp new_cftp = b_ch_3.addWithName("char_flags");
-               assertEquals(3, b_ch_3.getTextPropList().size());
-               assertEquals(new_cftp, b_ch_3.getTextPropList().get(0));
-               
-               // alignment: 1 does have, 2 doesn't
-               assertNotNull(b_p_1.findByName("alignment"));
-               assertNull(b_p_2.findByName("alignment"));
-               
-               // Now add in on 2, should go to the front
-               assertEquals(1, b_p_2.getTextPropList().size());
-               TextProp new_al = b_p_2.addWithName("alignment");
-               assertEquals(2, b_p_2.getTextPropList().size());
-               assertEquals(new_al, b_p_2.getTextPropList().get(0));
-               
-               // This should go at the end
-               TextProp new_sa = b_p_2.addWithName("spaceafter");
-               assertEquals(3, b_p_2.getTextPropList().size());
-               assertEquals(new_sa, b_p_2.getTextPropList().get(2));
-               
-               // Check we get an error with a made up one
-               try {
-                       b_p_2.addWithName("madeUpOne");
-                       fail();
-               } catch(IllegalArgumentException e) {
-                       // Good, as expected
-               }
-       }
-       
-       /**
-        * Try to recreate an existing StyleTextPropAtom (a) from the empty
-        *  constructor, and setting the required properties
-        */
-       public void testCreateAFromScatch() throws Exception {
-               // Start with an empty one
-               StyleTextPropAtom stpa = new StyleTextPropAtom(54);
-               
-               // Don't need to touch the paragraph styles
-               // Add two more character styles
-               LinkedList cs = stpa.getCharacterStyles();
-               
-               // First char style is boring, and 21 long
-               TextPropCollection tpca = (TextPropCollection)cs.get(0);
-               tpca.updateTextSize(21);
-               
-               // Second char style is coloured, 00 00 00 05, and 17 long
-               TextPropCollection tpcb = stpa.addCharacterTextPropCollection(17);
-               TextProp tpb = tpcb.addWithName("font.color");
-               tpb.setValue(0x05000000);
-               
-               // Third char style is coloured, FF 33 00 FE, and 16 long
-               TextPropCollection tpcc = stpa.addCharacterTextPropCollection(16);
-               TextProp tpc = tpcc.addWithName("font.color");
-               tpc.setValue(0xFE0033FF);
-               
-               // Should now be the same as data_a
-               ByteArrayOutputStream baos = new ByteArrayOutputStream();
-               stpa.writeOut(baos);
-               byte[] b = baos.toByteArray();
-
-               assertEquals(data_a.length, b.length);
-               for(int i=0; i<data_a.length; i++) {
-                       assertEquals(data_a[i],b[i]);
-               }
-       }
-
-       /**
-        * Try to recreate an existing StyleTextPropAtom (b) from the empty
-        *  constructor, and setting the required properties
-        */
-       public void testCreateBFromScatch() throws Exception {
-               // Start with an empty one
-               StyleTextPropAtom stpa = new StyleTextPropAtom(data_b_text_len);
-               
-               
-               // Need 4 paragraph styles
-               LinkedList ps = stpa.getParagraphStyles();
-               
-               // First is 30 long, left aligned, normal spacing
-               TextPropCollection tppa = (TextPropCollection)ps.get(0);
-               tppa.updateTextSize(30);
-               
-               TextProp tp = tppa.addWithName("alignment");
-               tp.setValue(0);
-               tp = tppa.addWithName("linespacing");
-               tp.setValue(80);
-
-               // Second is 28 long, centre aligned and normal spacing
-               TextPropCollection tppb = stpa.addParagraphTextPropCollection(28);
-               
-               tp = tppb.addWithName("linespacing");
-               tp.setValue(80);
-               
-               // Third is 25 long, right aligned and normal spacing
-               TextPropCollection tppc = stpa.addParagraphTextPropCollection(25);
-               
-               tp = tppc.addWithName("alignment");
-               tp.setValue(2);
-               tp = tppc.addWithName("linespacing");
-               tp.setValue(80);
-               
-               // Forth is left aligned + normal line spacing (despite differing font)
-               TextPropCollection tppd = stpa.addParagraphTextPropCollection(97);
-               
-               tp = tppd.addWithName("alignment");
-               tp.setValue(0);
-               tp = tppd.addWithName("linespacing");
-               tp.setValue(80);
-               
-               
-               // Now do 4 character styles
-               LinkedList cs = stpa.getCharacterStyles();
-               
-               // First is 30 long, bold and font size
-               TextPropCollection tpca = (TextPropCollection)cs.get(0);
-               tpca.updateTextSize(30);
-               
-               tp = tpca.addWithName("font.size");
-               tp.setValue(20);
-               CharFlagsTextProp cftp = (CharFlagsTextProp)
-                       tpca.addWithName("char_flags");
-               assertEquals(0, cftp.getValue());
-               cftp.setSubValue(true, CharFlagsTextProp.BOLD_IDX);
-               assertEquals(1, cftp.getValue());
-               
-               // Second is 28 long, blue and italic
-               TextPropCollection tpcb = stpa.addCharacterTextPropCollection(28);
-               
-               tp = tpcb.addWithName("font.size");
-               tp.setValue(20);
-               tp = tpcb.addWithName("font.color");
-               tp.setValue(0x05000000);
-               cftp = (CharFlagsTextProp)tpcb.addWithName("char_flags");
-               cftp.setSubValue(true, CharFlagsTextProp.ITALIC_IDX);
-               assertEquals(2, cftp.getValue());
-               
-               // Third is 25 long and red
-               TextPropCollection tpcc = stpa.addCharacterTextPropCollection(25);
-               
-               tp = tpcc.addWithName("font.size");
-               tp.setValue(20);
-               tp = tpcc.addWithName("font.color");
-               tp.setValue(0xfe0033ff);
-               
-               // Fourth is 96 long, underlined and different+bigger font 
-               TextPropCollection tpcd = stpa.addCharacterTextPropCollection(96);
-               
-               tp = tpcd.addWithName("font.size");
-               tp.setValue(24);
-               tp = tpcd.addWithName("font.index");
-               tp.setValue(1);
-               cftp = (CharFlagsTextProp)tpcd.addWithName("char_flags");
-               cftp.setSubValue(true, CharFlagsTextProp.UNDERLINE_IDX);
-               assertEquals(4, cftp.getValue());
-               
-               // Fifth is 1 long, underlined and different+bigger font + red
-               TextPropCollection tpce = stpa.addCharacterTextPropCollection(1);
-               
-               tp = tpce.addWithName("font.size");
-               tp.setValue(24);
-               tp = tpce.addWithName("font.index");
-               tp.setValue(1);
-               tp = tpce.addWithName("font.color");
-               tp.setValue(0xfe0033ff);
-               cftp = (CharFlagsTextProp)tpce.addWithName("char_flags");
-               cftp.setSubValue(true, CharFlagsTextProp.UNDERLINE_IDX);
-               assertEquals(4, cftp.getValue());
-               
-               
-               // Check it's as expected
-               assertEquals(4, stpa.getParagraphStyles().size());
-               assertEquals(5, stpa.getCharacterStyles().size());
-               
-               // Compare in detail to b
-               StyleTextPropAtom stpb = new StyleTextPropAtom(data_b,0,data_b.length);
-               stpb.setParentTextSize(data_b_text_len);
-               LinkedList psb = stpb.getParagraphStyles();
-               LinkedList csb = stpb.getCharacterStyles();
-               
-               assertEquals(psb.size(), ps.size());
-               assertEquals(csb.size(), cs.size());
-               
-               // Ensure Paragraph Character styles match
-               for(int z=0; z<2; z++) {
-                       LinkedList lla = cs; 
-                       LinkedList llb = csb;
-                       int upto = 5;
-                       if(z == 1) {
-                               lla = ps;
-                               llb = psb;
-                               upto = 4;
-                       }
-                       
-                       for(int i=0; i<upto; i++) {
-                               TextPropCollection ca = (TextPropCollection)lla.get(i);
-                               TextPropCollection cb = (TextPropCollection)llb.get(i);
-                               
-                               assertEquals(ca.getCharactersCovered(), cb.getCharactersCovered());
-                               assertEquals(ca.getTextPropList().size(), cb.getTextPropList().size());
-                               
-                               for(int j=0; j<ca.getTextPropList().size(); j++) {
-                                       TextProp tpa = (TextProp)ca.getTextPropList().get(j);
-                                       TextProp tpb = (TextProp)cb.getTextPropList().get(j);
-                                       //System.out.println("TP " + i + " " + j + " " + tpa.getName() + "\t" + tpa.getValue() );
-                                       assertEquals(tpa.getName(), tpb.getName());
-                                       assertEquals(tpa.getMask(), tpb.getMask());
-                                       assertEquals(tpa.getWriteMask(), tpb.getWriteMask());
-                                       assertEquals(tpa.getValue(), tpb.getValue());
-                               }
-                               
-                               ByteArrayOutputStream ba = new ByteArrayOutputStream();
-                               ByteArrayOutputStream bb = new ByteArrayOutputStream();
-                               
-                               ca.writeOut(ba);
-                               cb.writeOut(bb);
-                               byte[] cab = ba.toByteArray(); 
-                               byte[] cbb = bb.toByteArray();
-                               
-                               assertEquals(cbb.length, cab.length);
-                               for(int j=0; j<cab.length; j++) {
-                                       //System.out.println("On tp " + z + " " + i + " " + j + "\t" + cab[j] + "\t" + cbb[j]);
-                                       assertEquals(cbb[j], cab[j]);
-                               }
-                       }
-               }
-               
-
-               
-               // Check byte level with b
-               ByteArrayOutputStream baos = new ByteArrayOutputStream();
-               stpa.writeOut(baos);
-               byte[] b = baos.toByteArray();
-
-               assertEquals(data_b.length, b.length);
-               for(int i=0; i<data_b.length; i++) {
-                       System.out.println(i + "\t" + b[i] + "\t" + data_b[i] + "\t" + Integer.toHexString(b[i]) );
-                       assertEquals(data_b[i],b[i]);
-               }
-       }
-
-       public void testWriteA() throws Exception {
-               StyleTextPropAtom stpa = new StyleTextPropAtom(data_a,0,data_a.length);
-               ByteArrayOutputStream baos = new ByteArrayOutputStream();
-               stpa.writeOut(baos);
-               byte[] b = baos.toByteArray();
-
-               assertEquals(data_a.length, b.length);
-               for(int i=0; i<data_a.length; i++) {
-                       assertEquals(data_a[i],b[i]);
-               }
-       }
-
-       public void testLoadWriteA() throws Exception {
-               StyleTextPropAtom stpa = new StyleTextPropAtom(data_a,0,data_a.length);
-               stpa.setParentTextSize(data_a_text_len);
-
-               ByteArrayOutputStream baos = new ByteArrayOutputStream();
-               stpa.writeOut(baos);
-               byte[] b = baos.toByteArray();
-
-               assertEquals(data_a.length, b.length);
-               for(int i=0; i<data_a.length; i++) {
-                       assertEquals(data_a[i],b[i]);
-               }
-       }
-
-
-       public void testWriteB() throws Exception {
-               StyleTextPropAtom stpb = new StyleTextPropAtom(data_b,0,data_b.length);
-               ByteArrayOutputStream baos = new ByteArrayOutputStream();
-               stpb.writeOut(baos);
-               byte[] b = baos.toByteArray();
-
-               assertEquals(data_b.length, b.length);
-               for(int i=0; i<data_b.length; i++) {
-                       assertEquals(data_b[i],b[i]);
-               }
-       }
-
-       public void testLoadWriteB() throws Exception {
-               StyleTextPropAtom stpb = new StyleTextPropAtom(data_b,0,data_b.length);
-               stpb.setParentTextSize(data_b_text_len);
-
-               ByteArrayOutputStream baos = new ByteArrayOutputStream();
-               stpb.writeOut(baos);
-               byte[] b = baos.toByteArray();
-
-               assertEquals(data_b.length, b.length);
-               for(int i=0; i<data_b.length; i++) {
-                       //System.out.println(i + "\t" + b[i] + "\t" + data_b[i] + "\t" + Integer.toHexString(b[i]) );
-                       assertEquals(data_b[i],b[i]);
-               }
-       }
-       
-       
-       public void testNotEnoughDataProp() throws Exception {
-               // We don't have enough data in the record to cover
-               //  all the properties the mask says we have
-               // Make sure we just do the best we can
-               StyleTextPropAtom stpc = new StyleTextPropAtom(data_c,0,data_c.length);
-               stpc.setParentTextSize(data_c_text_len);
-               
-               // If we get here, we didn't break
-       }
+        StyleTextPropAtom stpa = new StyleTextPropAtom(data_a,0,data_a.length);
+        StyleTextPropAtom stpb = new StyleTextPropAtom(data_b,0,data_b.length);
+        StyleTextPropAtom stpc = new StyleTextPropAtom(data_c,0,data_c.length);
+        assertEquals(4001l, stpa.getRecordType());
+        assertEquals(4001l, stpb.getRecordType());
+        assertEquals(4001l, stpc.getRecordType());
+    }
+
+
+    public void testCharacterStyleCounts() throws Exception {
+        StyleTextPropAtom stpa = new StyleTextPropAtom(data_a,0,data_a.length);
+        StyleTextPropAtom stpb = new StyleTextPropAtom(data_b,0,data_b.length);
+
+        // Set for the appropriate text sizes
+        stpa.setParentTextSize(data_a_text_len);
+        stpb.setParentTextSize(data_b_text_len);
+
+        // In case A, there is a single styling of the characters
+        assertEquals(3, stpa.getCharacterStyles().size());
+        // In case B, there are 5 different stylings
+        assertEquals(5, stpb.getCharacterStyles().size());
+    }
+
+    public void testParagraphStyleCounts() throws Exception {
+        StyleTextPropAtom stpa = new StyleTextPropAtom(data_a,0,data_a.length);
+        StyleTextPropAtom stpb = new StyleTextPropAtom(data_b,0,data_b.length);
+
+        // Set for the appropriate text sizes
+        stpa.setParentTextSize(data_a_text_len);
+        stpb.setParentTextSize(data_b_text_len);
+
+        // In case A, all has the same spacing and alignment
+        assertEquals(1, stpa.getParagraphStyles().size());
+        // In case B, all 4 sets have different alignments
+        assertEquals(4, stpb.getParagraphStyles().size());
+    }
+
+
+    public void testCharacterStyleLengths() throws Exception {
+        StyleTextPropAtom stpa = new StyleTextPropAtom(data_a,0,data_a.length);
+        StyleTextPropAtom stpb = new StyleTextPropAtom(data_b,0,data_b.length);
+
+        // Set for the appropriate text sizes
+        stpa.setParentTextSize(data_a_text_len);
+        stpb.setParentTextSize(data_b_text_len);
+
+        // 54 chars, 21 + 17 + 16
+        LinkedList a_ch_l = stpa.getCharacterStyles();
+        TextPropCollection a_ch_1 = (TextPropCollection)a_ch_l.get(0);
+        TextPropCollection a_ch_2 = (TextPropCollection)a_ch_l.get(1);
+        TextPropCollection a_ch_3 = (TextPropCollection)a_ch_l.get(2);
+        assertEquals(21, a_ch_1.getCharactersCovered());
+        assertEquals(17, a_ch_2.getCharactersCovered());
+        assertEquals(16, a_ch_3.getCharactersCovered());
+
+        // 179 chars, 30 + 28 + 25
+        LinkedList b_ch_l = stpb.getCharacterStyles();
+        TextPropCollection b_ch_1 = (TextPropCollection)b_ch_l.get(0);
+        TextPropCollection b_ch_2 = (TextPropCollection)b_ch_l.get(1);
+        TextPropCollection b_ch_3 = (TextPropCollection)b_ch_l.get(2);
+        TextPropCollection b_ch_4 = (TextPropCollection)b_ch_l.get(3);
+        assertEquals(30, b_ch_1.getCharactersCovered());
+        assertEquals(28, b_ch_2.getCharactersCovered());
+        assertEquals(25, b_ch_3.getCharactersCovered());
+        assertEquals(96, b_ch_4.getCharactersCovered());
+    }
+
+
+    public void testCharacterPropOrdering() throws Exception {
+        StyleTextPropAtom stpb = new StyleTextPropAtom(data_b,0,data_b.length);
+        stpb.setParentTextSize(data_b_text_len);
+
+        LinkedList b_ch_l = stpb.getCharacterStyles();
+        TextPropCollection b_ch_1 = (TextPropCollection)b_ch_l.get(0);
+        TextPropCollection b_ch_2 = (TextPropCollection)b_ch_l.get(1);
+        TextPropCollection b_ch_3 = (TextPropCollection)b_ch_l.get(2);
+        TextPropCollection b_ch_4 = (TextPropCollection)b_ch_l.get(3);
+
+        // In first set, we get a CharFlagsTextProp and a font.size
+        assertEquals(2,b_ch_1.getTextPropList().size());
+        TextProp tp_1_1 = (TextProp)b_ch_1.getTextPropList().get(0);
+        TextProp tp_1_2 = (TextProp)b_ch_1.getTextPropList().get(1);
+        assertEquals(true, tp_1_1 instanceof CharFlagsTextProp);
+        assertEquals(true, tp_1_2 instanceof TextProp);
+        assertEquals("font.size", tp_1_2.getName());
+        assertEquals(20, tp_1_2.getValue());
+
+        // In second set, we get a CharFlagsTextProp and a font.size and a font.color
+        assertEquals(3,b_ch_2.getTextPropList().size());
+        TextProp tp_2_1 = (TextProp)b_ch_2.getTextPropList().get(0);
+        TextProp tp_2_2 = (TextProp)b_ch_2.getTextPropList().get(1);
+        TextProp tp_2_3 = (TextProp)b_ch_2.getTextPropList().get(2);
+        assertEquals(true, tp_2_1 instanceof CharFlagsTextProp);
+        assertEquals(true, tp_2_2 instanceof TextProp);
+        assertEquals(true, tp_2_3 instanceof TextProp);
+        assertEquals("font.size", tp_2_2.getName());
+        assertEquals("font.color", tp_2_3.getName());
+        assertEquals(20, tp_2_2.getValue());
+
+        // In third set, it's just a font.size and a font.color
+        assertEquals(2,b_ch_3.getTextPropList().size());
+        TextProp tp_3_1 = (TextProp)b_ch_3.getTextPropList().get(0);
+        TextProp tp_3_2 = (TextProp)b_ch_3.getTextPropList().get(1);
+        assertEquals(true, tp_3_1 instanceof TextProp);
+        assertEquals(true, tp_3_2 instanceof TextProp);
+        assertEquals("font.size", tp_3_1.getName());
+        assertEquals("font.color", tp_3_2.getName());
+        assertEquals(20, tp_3_1.getValue());
+
+        // In fourth set, we get a CharFlagsTextProp and a font.index and a font.size
+        assertEquals(3,b_ch_4.getTextPropList().size());
+        TextProp tp_4_1 = (TextProp)b_ch_4.getTextPropList().get(0);
+        TextProp tp_4_2 = (TextProp)b_ch_4.getTextPropList().get(1);
+        TextProp tp_4_3 = (TextProp)b_ch_4.getTextPropList().get(2);
+        assertEquals(true, tp_4_1 instanceof CharFlagsTextProp);
+        assertEquals(true, tp_4_2 instanceof TextProp);
+        assertEquals(true, tp_4_3 instanceof TextProp);
+        assertEquals("font.index", tp_4_2.getName());
+        assertEquals("font.size", tp_4_3.getName());
+        assertEquals(24, tp_4_3.getValue());
+    }
+
+    public void testParagraphProps() throws Exception {
+        StyleTextPropAtom stpb = new StyleTextPropAtom(data_b,0,data_b.length);
+        stpb.setParentTextSize(data_b_text_len);
+
+        LinkedList b_p_l = stpb.getParagraphStyles();
+        TextPropCollection b_p_1 = (TextPropCollection)b_p_l.get(0);
+        TextPropCollection b_p_2 = (TextPropCollection)b_p_l.get(1);
+        TextPropCollection b_p_3 = (TextPropCollection)b_p_l.get(2);
+        TextPropCollection b_p_4 = (TextPropCollection)b_p_l.get(3);
+
+        // 1st is left aligned + normal line spacing
+        assertEquals(2,b_p_1.getTextPropList().size());
+        TextProp tp_1_1 = (TextProp)b_p_1.getTextPropList().get(0);
+        TextProp tp_1_2 = (TextProp)b_p_1.getTextPropList().get(1);
+        assertEquals(true, tp_1_1 instanceof TextProp);
+        assertEquals(true, tp_1_2 instanceof TextProp);
+        assertEquals("alignment", tp_1_1.getName());
+        assertEquals("linespacing", tp_1_2.getName());
+        assertEquals(0, tp_1_1.getValue());
+        assertEquals(80, tp_1_2.getValue());
+
+        // 2nd is centre aligned (default) + normal line spacing
+        assertEquals(1,b_p_2.getTextPropList().size());
+        TextProp tp_2_1 = (TextProp)b_p_2.getTextPropList().get(0);
+        assertEquals(true, tp_2_1 instanceof TextProp);
+        assertEquals(true, tp_1_2 instanceof TextProp);
+        assertEquals("linespacing", tp_2_1.getName());
+        assertEquals(80, tp_2_1.getValue());
+
+        // 3rd is right aligned + normal line spacing
+        assertEquals(2,b_p_3.getTextPropList().size());
+        TextProp tp_3_1 = (TextProp)b_p_3.getTextPropList().get(0);
+        TextProp tp_3_2 = (TextProp)b_p_3.getTextPropList().get(1);
+        assertEquals(true, tp_3_1 instanceof TextProp);
+        assertEquals(true, tp_3_2 instanceof TextProp);
+        assertEquals("alignment", tp_3_1.getName());
+        assertEquals("linespacing", tp_3_2.getName());
+        assertEquals(2, tp_3_1.getValue());
+        assertEquals(80, tp_3_2.getValue());
+
+        // 4st is left aligned + normal line spacing (despite differing font)
+        assertEquals(2,b_p_4.getTextPropList().size());
+        TextProp tp_4_1 = (TextProp)b_p_4.getTextPropList().get(0);
+        TextProp tp_4_2 = (TextProp)b_p_4.getTextPropList().get(1);
+        assertEquals(true, tp_4_1 instanceof TextProp);
+        assertEquals(true, tp_4_2 instanceof TextProp);
+        assertEquals("alignment", tp_4_1.getName());
+        assertEquals("linespacing", tp_4_2.getName());
+        assertEquals(0, tp_4_1.getValue());
+        assertEquals(80, tp_4_2.getValue());
+    }
+
+    public void testCharacterProps() throws Exception {
+        StyleTextPropAtom stpb = new StyleTextPropAtom(data_b,0,data_b.length);
+        stpb.setParentTextSize(data_b_text_len);
+
+        LinkedList b_ch_l = stpb.getCharacterStyles();
+        TextPropCollection b_ch_1 = (TextPropCollection)b_ch_l.get(0);
+        TextPropCollection b_ch_2 = (TextPropCollection)b_ch_l.get(1);
+        TextPropCollection b_ch_3 = (TextPropCollection)b_ch_l.get(2);
+        TextPropCollection b_ch_4 = (TextPropCollection)b_ch_l.get(3);
+
+        // 1st is bold
+        CharFlagsTextProp cf_1_1 = (CharFlagsTextProp)b_ch_1.getTextPropList().get(0);
+        assertEquals(true,cf_1_1.getSubValue(CharFlagsTextProp.BOLD_IDX));
+        assertEquals(false,cf_1_1.getSubValue(CharFlagsTextProp.ITALIC_IDX));
+        assertEquals(false,cf_1_1.getSubValue(CharFlagsTextProp.ENABLE_NUMBERING_1_IDX));
+        assertEquals(false,cf_1_1.getSubValue(CharFlagsTextProp.ENABLE_NUMBERING_2_IDX));
+        assertEquals(false,cf_1_1.getSubValue(CharFlagsTextProp.RELIEF_IDX));
+        assertEquals(false,cf_1_1.getSubValue(CharFlagsTextProp.RESET_NUMBERING_IDX));
+        assertEquals(false,cf_1_1.getSubValue(CharFlagsTextProp.SHADOW_IDX));
+        assertEquals(false,cf_1_1.getSubValue(CharFlagsTextProp.STRIKETHROUGH_IDX));
+        assertEquals(false,cf_1_1.getSubValue(CharFlagsTextProp.UNDERLINE_IDX));
+
+        // 2nd is italic
+        CharFlagsTextProp cf_2_1 = (CharFlagsTextProp)b_ch_2.getTextPropList().get(0);
+        assertEquals(false,cf_2_1.getSubValue(CharFlagsTextProp.BOLD_IDX));
+        assertEquals(true,cf_2_1.getSubValue(CharFlagsTextProp.ITALIC_IDX));
+        assertEquals(false,cf_2_1.getSubValue(CharFlagsTextProp.ENABLE_NUMBERING_1_IDX));
+        assertEquals(false,cf_2_1.getSubValue(CharFlagsTextProp.ENABLE_NUMBERING_2_IDX));
+        assertEquals(false,cf_2_1.getSubValue(CharFlagsTextProp.RELIEF_IDX));
+        assertEquals(false,cf_2_1.getSubValue(CharFlagsTextProp.RESET_NUMBERING_IDX));
+        assertEquals(false,cf_2_1.getSubValue(CharFlagsTextProp.SHADOW_IDX));
+        assertEquals(false,cf_2_1.getSubValue(CharFlagsTextProp.STRIKETHROUGH_IDX));
+        assertEquals(false,cf_2_1.getSubValue(CharFlagsTextProp.UNDERLINE_IDX));
+
+        // 3rd is normal, so lacks a CharFlagsTextProp
+        assertFalse(b_ch_3.getTextPropList().get(0) instanceof CharFlagsTextProp);
+
+        // 4th is underlined
+        CharFlagsTextProp cf_4_1 = (CharFlagsTextProp)b_ch_4.getTextPropList().get(0);
+        assertEquals(false,cf_4_1.getSubValue(CharFlagsTextProp.BOLD_IDX));
+        assertEquals(false,cf_4_1.getSubValue(CharFlagsTextProp.ITALIC_IDX));
+        assertEquals(false,cf_4_1.getSubValue(CharFlagsTextProp.ENABLE_NUMBERING_1_IDX));
+        assertEquals(false,cf_4_1.getSubValue(CharFlagsTextProp.ENABLE_NUMBERING_2_IDX));
+        assertEquals(false,cf_4_1.getSubValue(CharFlagsTextProp.RELIEF_IDX));
+        assertEquals(false,cf_4_1.getSubValue(CharFlagsTextProp.RESET_NUMBERING_IDX));
+        assertEquals(false,cf_4_1.getSubValue(CharFlagsTextProp.SHADOW_IDX));
+        assertEquals(false,cf_4_1.getSubValue(CharFlagsTextProp.STRIKETHROUGH_IDX));
+        assertEquals(true,cf_4_1.getSubValue(CharFlagsTextProp.UNDERLINE_IDX));
+
+        // The value for this should be 4
+        assertEquals(0x0004, cf_4_1.getValue());
+
+        // Now make the 4th bold, italic and not underlined
+        cf_4_1.setSubValue(true, CharFlagsTextProp.BOLD_IDX);
+        cf_4_1.setSubValue(true, CharFlagsTextProp.ITALIC_IDX);
+        cf_4_1.setSubValue(false, CharFlagsTextProp.UNDERLINE_IDX);
+
+        assertEquals(true,cf_4_1.getSubValue(CharFlagsTextProp.BOLD_IDX));
+        assertEquals(true,cf_4_1.getSubValue(CharFlagsTextProp.ITALIC_IDX));
+        assertEquals(false,cf_4_1.getSubValue(CharFlagsTextProp.ENABLE_NUMBERING_1_IDX));
+        assertEquals(false,cf_4_1.getSubValue(CharFlagsTextProp.ENABLE_NUMBERING_2_IDX));
+        assertEquals(false,cf_4_1.getSubValue(CharFlagsTextProp.RELIEF_IDX));
+        assertEquals(false,cf_4_1.getSubValue(CharFlagsTextProp.RESET_NUMBERING_IDX));
+        assertEquals(false,cf_4_1.getSubValue(CharFlagsTextProp.SHADOW_IDX));
+        assertEquals(false,cf_4_1.getSubValue(CharFlagsTextProp.STRIKETHROUGH_IDX));
+        assertEquals(false,cf_4_1.getSubValue(CharFlagsTextProp.UNDERLINE_IDX));
+
+        // The value should now be 3
+        assertEquals(0x0003, cf_4_1.getValue());
+    }
+
+    public void testFindAddTextProp() {
+        StyleTextPropAtom stpb = new StyleTextPropAtom(data_b,0,data_b.length);
+        stpb.setParentTextSize(data_b_text_len);
+
+        LinkedList b_p_l = stpb.getParagraphStyles();
+        TextPropCollection b_p_1 = (TextPropCollection)b_p_l.get(0);
+        TextPropCollection b_p_2 = (TextPropCollection)b_p_l.get(1);
+        TextPropCollection b_p_3 = (TextPropCollection)b_p_l.get(2);
+        TextPropCollection b_p_4 = (TextPropCollection)b_p_l.get(3);
+
+        LinkedList b_ch_l = stpb.getCharacterStyles();
+        TextPropCollection b_ch_1 = (TextPropCollection)b_ch_l.get(0);
+        TextPropCollection b_ch_2 = (TextPropCollection)b_ch_l.get(1);
+        TextPropCollection b_ch_3 = (TextPropCollection)b_ch_l.get(2);
+        TextPropCollection b_ch_4 = (TextPropCollection)b_ch_l.get(3);
+
+        // CharFlagsTextProp: 3 doesn't have, 4 does
+        assertNull(b_ch_3.findByName("char_flags"));
+        assertNotNull(b_ch_4.findByName("char_flags"));
+
+        // Now add in on 3, should go to front
+        assertEquals(2, b_ch_3.getTextPropList().size());
+        TextProp new_cftp = b_ch_3.addWithName("char_flags");
+        assertEquals(3, b_ch_3.getTextPropList().size());
+        assertEquals(new_cftp, b_ch_3.getTextPropList().get(0));
+
+        // alignment: 1 does have, 2 doesn't
+        assertNotNull(b_p_1.findByName("alignment"));
+        assertNull(b_p_2.findByName("alignment"));
+
+        // Now add in on 2, should go to the front
+        assertEquals(1, b_p_2.getTextPropList().size());
+        TextProp new_al = b_p_2.addWithName("alignment");
+        assertEquals(2, b_p_2.getTextPropList().size());
+        assertEquals(new_al, b_p_2.getTextPropList().get(0));
+
+        // This should go at the end
+        TextProp new_sa = b_p_2.addWithName("spaceafter");
+        assertEquals(3, b_p_2.getTextPropList().size());
+        assertEquals(new_sa, b_p_2.getTextPropList().get(2));
+
+        // Check we get an error with a made up one
+        try {
+            b_p_2.addWithName("madeUpOne");
+            fail();
+        } catch(IllegalArgumentException e) {
+            // Good, as expected
+        }
+    }
+
+    /**
+     * Try to recreate an existing StyleTextPropAtom (a) from the empty
+     *  constructor, and setting the required properties
+     */
+    public void testCreateAFromScatch() throws Exception {
+        // Start with an empty one
+        StyleTextPropAtom stpa = new StyleTextPropAtom(54);
+
+        // Don't need to touch the paragraph styles
+        // Add two more character styles
+        LinkedList cs = stpa.getCharacterStyles();
+
+        // First char style is boring, and 21 long
+        TextPropCollection tpca = (TextPropCollection)cs.get(0);
+        tpca.updateTextSize(21);
+
+        // Second char style is coloured, 00 00 00 05, and 17 long
+        TextPropCollection tpcb = stpa.addCharacterTextPropCollection(17);
+        TextProp tpb = tpcb.addWithName("font.color");
+        tpb.setValue(0x05000000);
+
+        // Third char style is coloured, FF 33 00 FE, and 16 long
+        TextPropCollection tpcc = stpa.addCharacterTextPropCollection(16);
+        TextProp tpc = tpcc.addWithName("font.color");
+        tpc.setValue(0xFE0033FF);
+
+        // Should now be the same as data_a
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        stpa.writeOut(baos);
+        byte[] b = baos.toByteArray();
+
+        assertEquals(data_a.length, b.length);
+        for(int i=0; i<data_a.length; i++) {
+            assertEquals(data_a[i],b[i]);
+        }
+    }
+
+    /**
+     * Try to recreate an existing StyleTextPropAtom (b) from the empty
+     *  constructor, and setting the required properties
+     */
+    public void testCreateBFromScatch() throws Exception {
+        // Start with an empty one
+        StyleTextPropAtom stpa = new StyleTextPropAtom(data_b_text_len);
+
+
+        // Need 4 paragraph styles
+        LinkedList ps = stpa.getParagraphStyles();
+
+        // First is 30 long, left aligned, normal spacing
+        TextPropCollection tppa = (TextPropCollection)ps.get(0);
+        tppa.updateTextSize(30);
+
+        TextProp tp = tppa.addWithName("alignment");
+        tp.setValue(0);
+        tp = tppa.addWithName("linespacing");
+        tp.setValue(80);
+
+        // Second is 28 long, centre aligned and normal spacing
+        TextPropCollection tppb = stpa.addParagraphTextPropCollection(28);
+
+        tp = tppb.addWithName("linespacing");
+        tp.setValue(80);
+
+        // Third is 25 long, right aligned and normal spacing
+        TextPropCollection tppc = stpa.addParagraphTextPropCollection(25);
+
+        tp = tppc.addWithName("alignment");
+        tp.setValue(2);
+        tp = tppc.addWithName("linespacing");
+        tp.setValue(80);
+
+        // Forth is left aligned + normal line spacing (despite differing font)
+        TextPropCollection tppd = stpa.addParagraphTextPropCollection(97);
+
+        tp = tppd.addWithName("alignment");
+        tp.setValue(0);
+        tp = tppd.addWithName("linespacing");
+        tp.setValue(80);
+
+
+        // Now do 4 character styles
+        LinkedList cs = stpa.getCharacterStyles();
+
+        // First is 30 long, bold and font size
+        TextPropCollection tpca = (TextPropCollection)cs.get(0);
+        tpca.updateTextSize(30);
+
+        tp = tpca.addWithName("font.size");
+        tp.setValue(20);
+        CharFlagsTextProp cftp = (CharFlagsTextProp)
+            tpca.addWithName("char_flags");
+        assertEquals(0, cftp.getValue());
+        cftp.setSubValue(true, CharFlagsTextProp.BOLD_IDX);
+        assertEquals(1, cftp.getValue());
+
+        // Second is 28 long, blue and italic
+        TextPropCollection tpcb = stpa.addCharacterTextPropCollection(28);
+
+        tp = tpcb.addWithName("font.size");
+        tp.setValue(20);
+        tp = tpcb.addWithName("font.color");
+        tp.setValue(0x05000000);
+        cftp = (CharFlagsTextProp)tpcb.addWithName("char_flags");
+        cftp.setSubValue(true, CharFlagsTextProp.ITALIC_IDX);
+        assertEquals(2, cftp.getValue());
+
+        // Third is 25 long and red
+        TextPropCollection tpcc = stpa.addCharacterTextPropCollection(25);
+
+        tp = tpcc.addWithName("font.size");
+        tp.setValue(20);
+        tp = tpcc.addWithName("font.color");
+        tp.setValue(0xfe0033ff);
+
+        // Fourth is 96 long, underlined and different+bigger font
+        TextPropCollection tpcd = stpa.addCharacterTextPropCollection(96);
+
+        tp = tpcd.addWithName("font.size");
+        tp.setValue(24);
+        tp = tpcd.addWithName("font.index");
+        tp.setValue(1);
+        cftp = (CharFlagsTextProp)tpcd.addWithName("char_flags");
+        cftp.setSubValue(true, CharFlagsTextProp.UNDERLINE_IDX);
+        assertEquals(4, cftp.getValue());
+
+        // Fifth is 1 long, underlined and different+bigger font + red
+        TextPropCollection tpce = stpa.addCharacterTextPropCollection(1);
+
+        tp = tpce.addWithName("font.size");
+        tp.setValue(24);
+        tp = tpce.addWithName("font.index");
+        tp.setValue(1);
+        tp = tpce.addWithName("font.color");
+        tp.setValue(0xfe0033ff);
+        cftp = (CharFlagsTextProp)tpce.addWithName("char_flags");
+        cftp.setSubValue(true, CharFlagsTextProp.UNDERLINE_IDX);
+        assertEquals(4, cftp.getValue());
+
+
+        // Check it's as expected
+        assertEquals(4, stpa.getParagraphStyles().size());
+        assertEquals(5, stpa.getCharacterStyles().size());
+
+        // Compare in detail to b
+        StyleTextPropAtom stpb = new StyleTextPropAtom(data_b,0,data_b.length);
+        stpb.setParentTextSize(data_b_text_len);
+        LinkedList psb = stpb.getParagraphStyles();
+        LinkedList csb = stpb.getCharacterStyles();
+
+        assertEquals(psb.size(), ps.size());
+        assertEquals(csb.size(), cs.size());
+
+        // Ensure Paragraph Character styles match
+        for(int z=0; z<2; z++) {
+            LinkedList lla = cs;
+            LinkedList llb = csb;
+            int upto = 5;
+            if(z == 1) {
+                lla = ps;
+                llb = psb;
+                upto = 4;
+            }
+
+            for(int i=0; i<upto; i++) {
+                TextPropCollection ca = (TextPropCollection)lla.get(i);
+                TextPropCollection cb = (TextPropCollection)llb.get(i);
+
+                assertEquals(ca.getCharactersCovered(), cb.getCharactersCovered());
+                assertEquals(ca.getTextPropList().size(), cb.getTextPropList().size());
+
+                for(int j=0; j<ca.getTextPropList().size(); j++) {
+                    TextProp tpa = (TextProp)ca.getTextPropList().get(j);
+                    TextProp tpb = (TextProp)cb.getTextPropList().get(j);
+                    //System.out.println("TP " + i + " " + j + " " + tpa.getName() + "\t" + tpa.getValue() );
+                    assertEquals(tpa.getName(), tpb.getName());
+                    assertEquals(tpa.getMask(), tpb.getMask());
+                    assertEquals(tpa.getWriteMask(), tpb.getWriteMask());
+                    assertEquals(tpa.getValue(), tpb.getValue());
+                }
+
+                ByteArrayOutputStream ba = new ByteArrayOutputStream();
+                ByteArrayOutputStream bb = new ByteArrayOutputStream();
+
+                ca.writeOut(ba);
+                cb.writeOut(bb);
+                byte[] cab = ba.toByteArray();
+                byte[] cbb = bb.toByteArray();
+
+                assertEquals(cbb.length, cab.length);
+                for(int j=0; j<cab.length; j++) {
+                    //System.out.println("On tp " + z + " " + i + " " + j + "\t" + cab[j] + "\t" + cbb[j]);
+                    assertEquals(cbb[j], cab[j]);
+                }
+            }
+        }
+
+
+
+        // Check byte level with b
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        stpa.writeOut(baos);
+        byte[] b = baos.toByteArray();
+
+        assertEquals(data_b.length, b.length);
+        for(int i=0; i<data_b.length; i++) {
+            //System.out.println(i + "\t" + b[i] + "\t" + data_b[i] + "\t" + Integer.toHexString(b[i]) );
+            assertEquals(data_b[i],b[i]);
+        }
+    }
+
+    public void testWriteA() throws Exception {
+        doReadWrite(data_a, -1);
+    }
+
+    public void testLoadWriteA() throws Exception {
+        doReadWrite(data_b, data_b_text_len);
+    }
+
+
+    public void testWriteB() throws Exception {
+        doReadWrite(data_b, -1);
+    }
+
+    public void testLoadWriteB() throws Exception {
+        doReadWrite(data_b, data_b_text_len);
+    }
+
+    public void testLoadWriteC() throws Exception {
+        doReadWrite(data_c, data_c_text_len);
+    }
+
+    public void testLoadWriteD() throws Exception {
+        doReadWrite(data_d, data_d_text_len);
+    }
+
+    protected void doReadWrite(byte[] data, int textlen) throws Exception {
+        StyleTextPropAtom stpb = new StyleTextPropAtom(data, 0,data.length);
+        if(textlen != -1) stpb.setParentTextSize(textlen);
+
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        stpb.writeOut(out);
+        byte[] bytes = out.toByteArray();
+
+        assertEquals(data.length, bytes.length);
+        try {
+            assertTrue(Arrays.equals(data, bytes));
+        } catch (Throwable e){
+            //print hex dump if failed
+            assertEquals(HexDump.toHex(data), HexDump.toHex(bytes));
+        }
+    }
+
+    public void testNotEnoughDataProp() throws Exception {
+        // We don't have enough data in the record to cover
+        //  all the properties the mask says we have
+        // Make sure we just do the best we can
+        StyleTextPropAtom stpc = new StyleTextPropAtom(data_c,0,data_c.length);
+        stpc.setParentTextSize(data_c_text_len);
+
+        // If we get here, we didn't break
+    }
 
     /**
      * Check the test data for Bug 40143.
@@ -732,8 +720,8 @@ public class TestStyleTextPropAtom extends TestCase {
         assertEquals(1, chprops.findByName("char_flags").getValue());
         assertEquals(1, chprops.findByName("font.index").getValue());
         assertEquals(20, chprops.findByName("font.size").getValue());
-        assertEquals(0, chprops.findByName("asian_or_complex").getValue());
-        assertEquals(1, chprops.findByName("char_unknown_2").getValue());
+        assertEquals(0, chprops.findByName("asian.font.index").getValue());
+        assertEquals(1, chprops.findByName("ansi.font.index").getValue());
     }
 
     /**
@@ -747,16 +735,7 @@ public class TestStyleTextPropAtom extends TestCase {
                        0x00 , 0x00 , 0x13 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x63 , 0x00 ,
                        0x00 , 0x00 , 0x01 , 0x00 , 0x00 , 0x00 , 0x0F , 0x00
         };
-        StyleTextPropAtom stpa = new StyleTextPropAtom(data,0,data.length);
-        stpa.setParentTextSize(length);
-        ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        stpa.writeOut(baos);
-        byte[] b = baos.toByteArray();
-
-        assertEquals(data.length, b.length);
-        for(int i=0; i<data.length; i++) {
-            assertEquals(data[i],b[i]);
-        }
+        doReadWrite(data, length);
 
     }
 }
index e1193179fe82d74f371a555c4c4e860e50e6e71f..51e370bfb96d6ba0c5c2429a0b8cdcebadad0b81 100644 (file)
Binary files a/src/testcases/org/apache/poi/hssf/data/FormulaEvalTestData.xls and b/src/testcases/org/apache/poi/hssf/data/FormulaEvalTestData.xls differ
index 3584e37ea4e41f0c1ac230857ad3a34976f4c539..c9fea7f1e44407b03f4a73c9360ea4333b9336bc 100644 (file)
@@ -24,6 +24,7 @@ import org.apache.poi.hssf.HSSFTestDataSamples;
 import org.apache.poi.hssf.model.FormulaParser.FormulaParseException;
 import org.apache.poi.hssf.record.formula.AbstractFunctionPtg;
 import org.apache.poi.hssf.record.formula.AddPtg;
+import org.apache.poi.hssf.record.formula.AreaI;
 import org.apache.poi.hssf.record.formula.AreaPtg;
 import org.apache.poi.hssf.record.formula.AttrPtg;
 import org.apache.poi.hssf.record.formula.BoolPtg;
@@ -836,4 +837,29 @@ public final class TestFormulaParser extends TestCase {
                }
                cell.setCellFormula("count(fp1)"); // plain cell ref, col is in range
        }
-}
+       
+       public void testParseAreaRefHighRow_bug45358() {
+               Ptg[] ptgs;
+               AreaI aptg;
+               
+               HSSFWorkbook book = new HSSFWorkbook();
+               book.createSheet("Sheet1");
+               
+               ptgs = FormulaParser.parse("Sheet1!A10:A40000", book);
+               aptg = (AreaI) ptgs[0];
+               if (aptg.getLastRow() == -25537) {
+                       throw new AssertionFailedError("Identified bug 45358");
+               }
+               assertEquals(39999, aptg.getLastRow());
+               
+               ptgs = FormulaParser.parse("Sheet1!A10:A65536", book);
+               aptg = (AreaI) ptgs[0];
+               assertEquals(65535, aptg.getLastRow());
+               
+               // plain area refs should be ok too
+               ptgs = parseFormula("A10:A65536");
+               aptg = (AreaI) ptgs[0];
+               assertEquals(65535, aptg.getLastRow());
+               
+       }
+}
\ No newline at end of file
index bff51be2f1bcdd0dad5b9c7473933c8071cfdfac..c7ef2acc1c8791344d049df6c6cdeb8781af63b7 100644 (file)
@@ -1,4 +1,3 @@
-
 /* ====================================================================
    Licensed to the Apache Software Foundation (ASF) under one or more
    contributor license agreements.  See the NOTICE file distributed with
@@ -15,8 +14,6 @@
    See the License for the specific language governing permissions and
    limitations under the License.
 ==================================================================== */
-        
-
 
 package org.apache.poi.hssf.record;
 
@@ -33,9 +30,7 @@ import java.util.Stack;
  *
  * @author Glen Stampoultzis (glens at apache.org)
  */
-public class TestLinkedDataRecord
-        extends TestCase
-{
+public final class TestLinkedDataRecord extends TestCase {
 
 /*
     The records below are records that would appear in a simple bar chart
@@ -160,14 +155,7 @@ recordid = 0x1051, size =8
         (byte)0x00,(byte)0x00,          // index to last column and relative flags
     };
 
-    public TestLinkedDataRecord(String name)
-    {
-        super(name);
-    }
-
-    public void testLoad()
-            throws Exception
-    {
+    public void testLoad() {
 
         LinkedDataRecord record = new LinkedDataRecord(new TestcaseRecordInputStream((short)0x1051, (short)data.length, data));
         assertEquals( LinkedDataRecord.LINK_TYPE_VALUES, record.getLinkType());
@@ -176,19 +164,11 @@ recordid = 0x1051, size =8
         assertEquals( false, record.isCustomNumberFormat() );
         assertEquals( 0, record.getIndexNumberFmtRecord());
 
-        Area3DPtg ptg = new Area3DPtg();
-        ptg.setExternSheetIndex((short)0);
-        ptg.setFirstColumn((short)0);
-        ptg.setLastColumn((short)0);
-        ptg.setFirstRow((short)0);
-        ptg.setLastRow((short)7936);
-        ptg.setFirstColRelative(false);
-        ptg.setLastColRelative(false);
-        ptg.setFirstRowRelative(false);
-        ptg.setLastRowRelative(false);
-        Stack s = new Stack();
-        s.push(ptg);
-        assertEquals( s, record.getFormulaOfLink().getFormulaTokens() );
+        Area3DPtg ptgExpected = new Area3DPtg(0, 7936, 0, 0,
+                false, false, false, false, 0);
+        
+        Object ptgActual = record.getFormulaOfLink().getFormulaTokens().get(0);
+        assertEquals(ptgExpected.toString(),  ptgActual.toString());
 
         assertEquals( data.length + 4, record.getRecordSize() );
 
@@ -196,24 +176,15 @@ recordid = 0x1051, size =8
 
     }
 
-    public void testStore()
-    {
+    public void testStore() {
         LinkedDataRecord record = new LinkedDataRecord();
         record.setLinkType( LinkedDataRecord.LINK_TYPE_VALUES );
         record.setReferenceType( LinkedDataRecord.REFERENCE_TYPE_WORKSHEET );
         record.setOptions( (short)0 );
         record.setCustomNumberFormat( false );
         record.setIndexNumberFmtRecord( (short)0 );
-        Area3DPtg ptg = new Area3DPtg();
-        ptg.setExternSheetIndex((short)0);
-        ptg.setFirstColumn((short)0);
-        ptg.setLastColumn((short)0);
-        ptg.setFirstRow((short)0);
-        ptg.setLastRow((short)7936);
-        ptg.setFirstColRelative(false);
-        ptg.setLastColRelative(false);
-        ptg.setFirstRowRelative(false);
-        ptg.setLastRowRelative(false);
+        Area3DPtg ptg = new Area3DPtg(0, 7936, 0, 0,
+                       false, false, false, false, 0);
         Stack s = new Stack();
         s.push(ptg);
         LinkedDataFormulaField formulaOfLink = new LinkedDataFormulaField();
index 6c855707ba44f7391f5834bb2683b431d5512392..71d15745e9988e284d0e012fff2c47b7a2fdd1ee 100644 (file)
@@ -20,7 +20,8 @@ package org.apache.poi.hssf.record.formula.eval;
 import junit.framework.AssertionFailedError;
 import junit.framework.TestCase;
 
-import org.apache.poi.hssf.record.formula.Area3DPtg;
+import org.apache.poi.hssf.record.formula.AreaPtg;
+import org.apache.poi.hssf.record.formula.functions.EvalFactory;
 
 /**
  * Tests for <tt>AreaEval</tt>
@@ -30,8 +31,8 @@ import org.apache.poi.hssf.record.formula.Area3DPtg;
 public final class TestAreaEval extends TestCase {
 
        public void testGetValue_bug44950() {
-               
-               Area3DPtg ptg = new Area3DPtg("B2:D3", (short)0);
+               // TODO - this test probably isn't testing much anymore
+               AreaPtg ptg = new AreaPtg("B2:D3");
                NumberEval one = new NumberEval(1);
                ValueEval[] values = {
                                one,    
@@ -41,7 +42,7 @@ public final class TestAreaEval extends TestCase {
                                new NumberEval(5),      
                                new NumberEval(6),      
                };
-               AreaEval ae = new Area3DEval(ptg, values);
+               AreaEval ae = EvalFactory.createAreaEval(ptg, values);
                if (one == ae.getValueAt(1, 2)) {
                        throw new AssertionFailedError("Identified bug 44950 a");
                }
index dc20c0d8e5e7f0436ac13bab863ac7493b9163bb..33c38a6c127a8dfa447440e0c6c900584774b60d 100755 (executable)
 
 package org.apache.poi.hssf.record.formula.eval;
 
+import junit.framework.TestCase;
+
 import org.apache.poi.hssf.record.formula.AreaPtg;
 import org.apache.poi.hssf.record.formula.UnaryPlusPtg;
+import org.apache.poi.hssf.record.formula.functions.EvalFactory;
 import org.apache.poi.hssf.record.formula.functions.NumericFunctionInvoker;
 
-import junit.framework.TestCase;
-
 /**
  * Test for unary plus operator evaluator.
- * 
+ *
  * @author Josh Micich
  */
 public final class TestUnaryPlusEval extends TestCase {
-       
+
        /**
         * Test for bug observable at svn revision 618865 (5-Feb-2008)<br/>
-        * The code for handling column operands had been copy-pasted from the row handling code. 
+        * The code for handling column operands had been copy-pasted from the row handling code.
         */
        public void testColumnOperand() {
 
@@ -42,15 +43,14 @@ public final class TestUnaryPlusEval extends TestCase {
                short colNum = (short)5;
                AreaPtg areaPtg = new AreaPtg(firstRow, lastRow, colNum, colNum, false, false, false, false);
                ValueEval[] values = {
-                               new NumberEval(27),     
-                               new NumberEval(29),     
-                               new NumberEval(35),     // value in row 10 
-                               new NumberEval(37),     
-                               new NumberEval(38),     
+                               new NumberEval(27),
+                               new NumberEval(29),
+                               new NumberEval(35),     // value in row 10
+                               new NumberEval(37),
+                               new NumberEval(38),
                };
-               Eval areaEval = new Area2DEval(areaPtg, values);
-               Eval[] args = { 
-                       areaEval,       
+               Eval[] args = {
+                       EvalFactory.createAreaEval(areaPtg, values),
                };
 
                double result = NumericFunctionInvoker.invoke(new UnaryPlusEval(UnaryPlusPtg.instance), args, 10, (short)20);
index 51435d314c9e1198d2e7e3fecae61d7f0923eb89..1c8d74f44a94b58b537f2fa65b3c346307a55a6e 100755 (executable)
    See the License for the specific language governing permissions and
    limitations under the License.
 ==================================================================== */
-        
 
 package org.apache.poi.hssf.record.formula.functions;
 
 import org.apache.poi.hssf.record.formula.AreaPtg;
+import org.apache.poi.hssf.record.formula.Ref3DPtg;
 import org.apache.poi.hssf.record.formula.RefPtg;
-import org.apache.poi.hssf.record.formula.eval.Area2DEval;
 import org.apache.poi.hssf.record.formula.eval.AreaEval;
+import org.apache.poi.hssf.record.formula.eval.AreaEvalBase;
 import org.apache.poi.hssf.record.formula.eval.NumberEval;
-import org.apache.poi.hssf.record.formula.eval.Ref2DEval;
 import org.apache.poi.hssf.record.formula.eval.RefEval;
+import org.apache.poi.hssf.record.formula.eval.RefEvalBase;
 import org.apache.poi.hssf.record.formula.eval.ValueEval;
 
 /**
@@ -32,7 +32,7 @@ import org.apache.poi.hssf.record.formula.eval.ValueEval;
  * 
  * @author Josh Micich
  */
-final class EvalFactory {
+public final class EvalFactory {
 
        private EvalFactory() {
                // no instances of this class
@@ -44,6 +44,14 @@ final class EvalFactory {
         */
        public static AreaEval createAreaEval(String areaRefStr, ValueEval[] values) {
                AreaPtg areaPtg = new AreaPtg(areaRefStr);
+               return createAreaEval(areaPtg, values);
+       }
+
+       /**
+        * Creates a dummy AreaEval 
+        * @param values empty (<code>null</code>) entries in this array will be converted to NumberEval.ZERO
+        */
+       public static AreaEval createAreaEval(AreaPtg areaPtg, ValueEval[] values) {
                int nCols = areaPtg.getLastColumn() - areaPtg.getFirstColumn() + 1;
                int nRows = areaPtg.getLastRow() - areaPtg.getFirstRow() + 1;
                int nExpected = nRows * nCols;
@@ -55,13 +63,57 @@ final class EvalFactory {
                                values[i] = NumberEval.ZERO;
                        }
                }
-               return new Area2DEval(areaPtg, values);
+               return new MockAreaEval(areaPtg, values);
        }
 
        /**
         * Creates a single RefEval (with value zero)
         */
        public static RefEval createRefEval(String refStr) {
-               return new Ref2DEval(new RefPtg(refStr), NumberEval.ZERO);
+               return createRefEval(refStr, NumberEval.ZERO);
+       }
+       public static RefEval createRefEval(String refStr, ValueEval value) {
+               return new MockRefEval(new RefPtg(refStr), value);
+       }
+       
+       private static final class MockAreaEval extends AreaEvalBase {
+               private final ValueEval[] _values;
+               public MockAreaEval(AreaPtg areaPtg, ValueEval[] values) {
+                       super(areaPtg);
+                       _values = values;
+               }
+               public ValueEval getRelativeValue(int relativeRowIndex, int relativeColumnIndex) {
+                       if (relativeRowIndex < 0 || relativeRowIndex >=getHeight()) {
+                               throw new IllegalArgumentException("row index out of range");
+                       }
+                       int width = getWidth();
+                       if (relativeColumnIndex < 0 || relativeColumnIndex >=width) {
+                               throw new IllegalArgumentException("column index out of range");
+                       }
+                       int oneDimensionalIndex = relativeRowIndex * width + relativeColumnIndex;
+                       return _values[oneDimensionalIndex];
+               }
+               public AreaEval offset(int relFirstRowIx, int relLastRowIx, int relFirstColIx, int relLastColIx) {
+                       throw new RuntimeException("Operation not implemented on this mock object");
+               }
+       }
+       
+       private static final class MockRefEval extends RefEvalBase {
+               private final ValueEval _value;
+               public MockRefEval(RefPtg ptg, ValueEval value) {
+                       super(ptg.getRow(), ptg.getColumn());
+                       _value = value;
+               }
+               public MockRefEval(Ref3DPtg ptg, ValueEval value) {
+                       super(ptg.getRow(), ptg.getColumn());
+                       _value = value;
+               }
+               public ValueEval getInnerValueEval() {
+                       return _value;
+               }
+               public AreaEval offset(int relFirstRowIx, int relLastRowIx, int relFirstColIx, int relLastColIx) {
+                       throw new RuntimeException("Operation not implemented on this mock object");
+               }
        }
+       
 }
index eca00872a3ddf772a4f08ae425c575ea8cd4a95d..41d703e2cfb2f7ff6c910aff4ae39dfd6b29e29b 100755 (executable)
@@ -21,9 +21,7 @@ import junit.framework.AssertionFailedError;
 import junit.framework.TestCase;
 
 import org.apache.poi.hssf.HSSFTestDataSamples;
-import org.apache.poi.hssf.record.formula.AreaPtg;
 import org.apache.poi.hssf.record.formula.RefPtg;
-import org.apache.poi.hssf.record.formula.eval.Area2DEval;
 import org.apache.poi.hssf.record.formula.eval.AreaEval;
 import org.apache.poi.hssf.record.formula.eval.BlankEval;
 import org.apache.poi.hssf.record.formula.eval.BoolEval;
@@ -91,7 +89,7 @@ public final class TestCountFuncs extends TestCase {
                                BoolEval.TRUE,
                                BlankEval.INSTANCE,
                };
-               range = createAreaEval("A1:B3", values);
+               range = EvalFactory.createAreaEval("A1:B3", values);
                confirmCountIf(2, range, BoolEval.TRUE);
 
                // when criteria is numeric
@@ -103,7 +101,7 @@ public final class TestCountFuncs extends TestCase {
                                new NumberEval(2),
                                BoolEval.TRUE,
                };
-               range = createAreaEval("A1:B3", values);
+               range = EvalFactory.createAreaEval("A1:B3", values);
                confirmCountIf(3, range, new NumberEval(2));
                // note - same results when criteria is a string that parses as the number with the same value
                confirmCountIf(3, range, new StringEval("2.00"));
@@ -126,20 +124,15 @@ public final class TestCountFuncs extends TestCase {
                                new NumberEval(25),
                                new NumberEval(25),
                };
-               Area2DEval arg0 = new Area2DEval(new AreaPtg("C1:C6"), values);
+               AreaEval arg0 = EvalFactory.createAreaEval("C1:C6", values);
 
-               Ref2DEval criteriaArg = new Ref2DEval(new RefPtg("A1"), new NumberEval(25));
+               ValueEval criteriaArg = EvalFactory.createRefEval("A1", new NumberEval(25));
                Eval[] args=  { arg0, criteriaArg, };
 
                double actual = NumericFunctionInvoker.invoke(new Countif(), args);
                assertEquals(4, actual, 0D);
        }
 
-
-       private static AreaEval createAreaEval(String areaRefStr, ValueEval[] values) {
-               return new Area2DEval(new AreaPtg(areaRefStr), values);
-       }
-
        private static void confirmCountA(int expected, Eval[] args) {
                double result = NumericFunctionInvoker.invoke(new Counta(), args);
                assertEquals(expected, result, 0);
index 492d68e983b511c6aac5ba5d45cfb9296d565653..80c154596eab77b30eaa8d3940f854b3ff09bc38 100755 (executable)
@@ -19,8 +19,7 @@ package org.apache.poi.hssf.record.formula.functions;
 
 import junit.framework.TestCase;
 
-import org.apache.poi.hssf.record.formula.AreaPtg;
-import org.apache.poi.hssf.record.formula.eval.Area2DEval;
+import org.apache.poi.hssf.record.formula.eval.AreaEval;
 import org.apache.poi.hssf.record.formula.eval.Eval;
 import org.apache.poi.hssf.record.formula.eval.NumberEval;
 import org.apache.poi.hssf.record.formula.eval.ValueEval;
@@ -68,7 +67,7 @@ public final class TestIndex extends TestCase {
                for (int i = 0; i < values.length; i++) {
                        values[i] = new NumberEval(dValues[i]);
                }
-               Area2DEval arg0 = new Area2DEval(new AreaPtg(areaRefString), values);
+               AreaEval arg0 = EvalFactory.createAreaEval(areaRefString, values);
                
                Eval[] args;
                if (colNum > 0) {
index d275e5f333b8c61bcb4fd20e20204bc2c5bb4af2..48104c22e5e739f6dd6fd83b63af468cf8774142 100755 (executable)
@@ -19,8 +19,6 @@ package org.apache.poi.hssf.record.formula.functions;
 
 import junit.framework.TestCase;
 
-import org.apache.poi.hssf.record.formula.AreaPtg;
-import org.apache.poi.hssf.record.formula.eval.Area2DEval;
 import org.apache.poi.hssf.record.formula.eval.AreaEval;
 import org.apache.poi.hssf.record.formula.eval.BoolEval;
 import org.apache.poi.hssf.record.formula.eval.ErrorEval;
@@ -32,7 +30,7 @@ import org.apache.poi.hssf.record.formula.eval.ValueEval;
 
 /**
  * Test cases for MATCH()
- * 
+ *
  * @author Josh Micich
  */
 public final class TestMatch extends TestCase {
@@ -41,8 +39,8 @@ public final class TestMatch extends TestCase {
        private static final NumberEval MATCH_EXACT = new NumberEval(0);
        /** greater than or equal to */
        private static final NumberEval MATCH_SMALLEST_GTE = new NumberEval(-1);
-       
-       
+
+
        private static Eval invokeMatch(Eval lookup_value, Eval lookup_array, Eval match_type) {
                Eval[] args = { lookup_value, lookup_array, match_type, };
                return new Match().evaluate(args, -1, (short)-1);
@@ -54,26 +52,19 @@ public final class TestMatch extends TestCase {
                NumericValueEval nve = (NumericValueEval)actualEval;
                assertEquals(expected, nve.getNumberValue(), 0);
        }
-       /**
-        * Convenience method
-        * @return <code>new Area2DEval(new AreaPtg(ref), values)</code>
-        */
-       private static AreaEval createAreaEval(String ref, ValueEval[] values) {
-               return new Area2DEval(new AreaPtg(ref), values);
-       }
-       
+
        public void testSimpleNumber() {
-               
+
                ValueEval[] values = {
-                       new NumberEval(4),      
-                       new NumberEval(5),      
-                       new NumberEval(10),     
-                       new NumberEval(10),     
-                       new NumberEval(25),     
+                       new NumberEval(4),
+                       new NumberEval(5),
+                       new NumberEval(10),
+                       new NumberEval(10),
+                       new NumberEval(25),
                };
-               
-               AreaEval ae = createAreaEval("A1:A5", values);
-               
+
+               AreaEval ae = EvalFactory.createAreaEval("A1:A5", values);
+
                confirmInt(2, invokeMatch(new NumberEval(5), ae, MATCH_LARGEST_LTE));
                confirmInt(2, invokeMatch(new NumberEval(5), ae, MATCH_EXACT));
                confirmInt(4, invokeMatch(new NumberEval(10), ae, MATCH_LARGEST_LTE));
@@ -81,19 +72,19 @@ public final class TestMatch extends TestCase {
                confirmInt(4, invokeMatch(new NumberEval(20), ae, MATCH_LARGEST_LTE));
                assertEquals(ErrorEval.NA, invokeMatch(new NumberEval(20), ae, MATCH_EXACT));
        }
-       
+
        public void testReversedNumber() {
-               
+
                ValueEval[] values = {
-                       new NumberEval(25),     
-                       new NumberEval(10),     
-                       new NumberEval(10),     
-                       new NumberEval(10),     
-                       new NumberEval(4),      
+                       new NumberEval(25),
+                       new NumberEval(10),
+                       new NumberEval(10),
+                       new NumberEval(10),
+                       new NumberEval(4),
                };
-               
-               AreaEval ae = createAreaEval("A1:A5", values);
-               
+
+               AreaEval ae = EvalFactory.createAreaEval("A1:A5", values);
+
                confirmInt(2, invokeMatch(new NumberEval(10), ae, MATCH_SMALLEST_GTE));
                confirmInt(2, invokeMatch(new NumberEval(10), ae, MATCH_EXACT));
                confirmInt(4, invokeMatch(new NumberEval(9), ae, MATCH_SMALLEST_GTE));
@@ -101,19 +92,19 @@ public final class TestMatch extends TestCase {
                assertEquals(ErrorEval.NA, invokeMatch(new NumberEval(20), ae, MATCH_EXACT));
                assertEquals(ErrorEval.NA, invokeMatch(new NumberEval(26), ae, MATCH_SMALLEST_GTE));
        }
-       
+
        public void testSimpleString() {
-               
+
                ValueEval[] values = {
-                       new StringEval("Albert"),       
-                       new StringEval("Charles"),      
-                       new StringEval("Ed"),   
-                       new StringEval("Greg"), 
-                       new StringEval("Ian"),  
+                       new StringEval("Albert"),
+                       new StringEval("Charles"),
+                       new StringEval("Ed"),
+                       new StringEval("Greg"),
+                       new StringEval("Ian"),
                };
-               
-               AreaEval ae = createAreaEval("A1:A5", values);
-               
+
+               AreaEval ae = EvalFactory.createAreaEval("A1:A5", values);
+
                // Note String comparisons are case insensitive
                confirmInt(3, invokeMatch(new StringEval("Ed"), ae, MATCH_LARGEST_LTE));
                confirmInt(3, invokeMatch(new StringEval("eD"), ae, MATCH_LARGEST_LTE));
@@ -122,90 +113,90 @@ public final class TestMatch extends TestCase {
                confirmInt(4, invokeMatch(new StringEval("Hugh"), ae, MATCH_LARGEST_LTE));
                assertEquals(ErrorEval.NA, invokeMatch(new StringEval("Hugh"), ae, MATCH_EXACT));
        }
-       
+
        public void testSimpleBoolean() {
-               
+
                ValueEval[] values = {
-                               BoolEval.FALSE, 
-                               BoolEval.FALSE, 
-                               BoolEval.TRUE,  
-                               BoolEval.TRUE,  
+                               BoolEval.FALSE,
+                               BoolEval.FALSE,
+                               BoolEval.TRUE,
+                               BoolEval.TRUE,
                };
-               
-               AreaEval ae = createAreaEval("A1:A4", values);
-               
+
+               AreaEval ae = EvalFactory.createAreaEval("A1:A4", values);
+
                // Note String comparisons are case insensitive
                confirmInt(2, invokeMatch(BoolEval.FALSE, ae, MATCH_LARGEST_LTE));
                confirmInt(1, invokeMatch(BoolEval.FALSE, ae, MATCH_EXACT));
                confirmInt(4, invokeMatch(BoolEval.TRUE, ae, MATCH_LARGEST_LTE));
                confirmInt(3, invokeMatch(BoolEval.TRUE, ae, MATCH_EXACT));
        }
-       
+
        public void testHeterogeneous() {
-               
+
                ValueEval[] values = {
-                               new NumberEval(4),      
-                               BoolEval.FALSE, 
+                               new NumberEval(4),
+                               BoolEval.FALSE,
                                new NumberEval(5),
-                               new StringEval("Albert"),       
-                               BoolEval.FALSE, 
-                               BoolEval.TRUE,  
-                               new NumberEval(10),     
-                               new StringEval("Charles"),      
-                               new StringEval("Ed"),   
-                               new NumberEval(10),     
-                               new NumberEval(25),     
-                               BoolEval.TRUE,  
-                               new StringEval("Ed"),   
+                               new StringEval("Albert"),
+                               BoolEval.FALSE,
+                               BoolEval.TRUE,
+                               new NumberEval(10),
+                               new StringEval("Charles"),
+                               new StringEval("Ed"),
+                               new NumberEval(10),
+                               new NumberEval(25),
+                               BoolEval.TRUE,
+                               new StringEval("Ed"),
                };
-               
-               AreaEval ae = createAreaEval("A1:A13", values);
-               
+
+               AreaEval ae = EvalFactory.createAreaEval("A1:A13", values);
+
                assertEquals(ErrorEval.NA, invokeMatch(new StringEval("Aaron"), ae, MATCH_LARGEST_LTE));
-               
+
                confirmInt(5, invokeMatch(BoolEval.FALSE, ae, MATCH_LARGEST_LTE));
                confirmInt(2, invokeMatch(BoolEval.FALSE, ae, MATCH_EXACT));
                confirmInt(3, invokeMatch(new NumberEval(5), ae, MATCH_LARGEST_LTE));
                confirmInt(3, invokeMatch(new NumberEval(5), ae, MATCH_EXACT));
-               
+
                confirmInt(8, invokeMatch(new StringEval("CHARLES"), ae, MATCH_EXACT));
-               
+
                confirmInt(4, invokeMatch(new StringEval("Ben"), ae, MATCH_LARGEST_LTE));
-               
+
                confirmInt(13, invokeMatch(new StringEval("ED"), ae, MATCH_LARGEST_LTE));
                confirmInt(9, invokeMatch(new StringEval("ED"), ae, MATCH_EXACT));
-                       
+
                confirmInt(13, invokeMatch(new StringEval("Hugh"), ae, MATCH_LARGEST_LTE));
                assertEquals(ErrorEval.NA, invokeMatch(new StringEval("Hugh"), ae, MATCH_EXACT));
-               
+
                confirmInt(11, invokeMatch(new NumberEval(30), ae, MATCH_LARGEST_LTE));
                confirmInt(12, invokeMatch(BoolEval.TRUE, ae, MATCH_LARGEST_LTE));
        }
-       
+
 
        /**
         * Ensures that the match_type argument can be an <tt>AreaEval</tt>.<br/>
         * Bugzilla 44421
         */
        public void testMatchArgTypeArea() {
-               
+
                ValueEval[] values = {
-                       new NumberEval(4),      
-                       new NumberEval(5),      
-                       new NumberEval(10),     
-                       new NumberEval(10),     
-                       new NumberEval(25),     
+                       new NumberEval(4),
+                       new NumberEval(5),
+                       new NumberEval(10),
+                       new NumberEval(10),
+                       new NumberEval(25),
                };
-               
-               AreaEval ae = createAreaEval("A1:A5", values);
 
-               AreaEval matchAE = createAreaEval("C1:C1", new ValueEval[] { MATCH_LARGEST_LTE, });
-               
+               AreaEval ae = EvalFactory.createAreaEval("A1:A5", values);
+
+               AreaEval matchAE = EvalFactory.createAreaEval("C1:C1", new ValueEval[] { MATCH_LARGEST_LTE, });
+
                try {
                        confirmInt(4, invokeMatch(new NumberEval(10), ae, matchAE));
                } catch (RuntimeException e) {
                        if(e.getMessage().startsWith("Unexpected match_type type")) {
-                               // identified bug 44421 
+                               // identified bug 44421
                                fail(e.getMessage());
                        }
                        // some other error ??
index eb576506a0027541dc95a2637ee9f17c88152ebb..d9571852497dc99c7b31bae104a62e014712697a 100644 (file)
@@ -20,6 +20,8 @@
  */
 package org.apache.poi.hssf.record.formula.functions;
 
+import org.apache.poi.hssf.record.formula.functions.XYNumericFunction.Accumulator;
+
 
 /**
  * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
@@ -566,99 +568,99 @@ public class TestMathX extends AbstractNumericTestCase {
     }
 
     public void testSumx2my2() {
-        double d = 0;
         double[] xarr = null;
         double[] yarr = null;
         
         xarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
         yarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
-        d = MathX.sumx2my2(xarr, yarr);
-        assertEquals("sumx2my2 ", 100, d);
+        confirmSumx2my2(xarr, yarr, 100);
         
         xarr = new double[]{-1, -2, -3, -4, -5, -6, -7, -8, -9, -10};
         yarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
-        d = MathX.sumx2my2(xarr, yarr);
-        assertEquals("sumx2my2 ", 100, d);
+        confirmSumx2my2(xarr, yarr, 100);
         
         xarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
         yarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
-        d = MathX.sumx2my2(xarr, yarr);
-        assertEquals("sumx2my2 ", -100, d);
+        confirmSumx2my2(xarr, yarr, -100);
         
         xarr = new double[]{10};
         yarr = new double[]{9};
-        d = MathX.sumx2my2(xarr, yarr);
-        assertEquals("sumx2my2 ", 19, d);
+        confirmSumx2my2(xarr, yarr, 19);
         
         xarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
         yarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
-        d = MathX.sumx2my2(xarr, yarr);
-        assertEquals("sumx2my2 ", 0, d);
-        
+        confirmSumx2my2(xarr, yarr, 0);
     }
 
     public void testSumx2py2() {
-        double d = 0;
         double[] xarr = null;
         double[] yarr = null;
         
         xarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
         yarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
-        d = MathX.sumx2py2(xarr, yarr);
-        assertEquals("sumx2py2 ", 670, d);
+        confirmSumx2py2(xarr, yarr, 670);
         
         xarr = new double[]{-1, -2, -3, -4, -5, -6, -7, -8, -9, -10};
         yarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
-        d = MathX.sumx2py2(xarr, yarr);
-        assertEquals("sumx2py2 ", 670, d);
+        confirmSumx2py2(xarr, yarr, 670);
         
         xarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
         yarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
-        d = MathX.sumx2py2(xarr, yarr);
-        assertEquals("sumx2py2 ", 670, d);
+        confirmSumx2py2(xarr, yarr, 670);
         
         xarr = new double[]{10};
         yarr = new double[]{9};
-        d = MathX.sumx2py2(xarr, yarr);
-        assertEquals("sumx2py2 ", 181, d);
+        confirmSumx2py2(xarr, yarr, 181);
         
         xarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
         yarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
-        d = MathX.sumx2py2(xarr, yarr);
-        assertEquals("sumx2py2 ", 770, d);
+        confirmSumx2py2(xarr, yarr, 770);
     }
 
     public void testSumxmy2() {
-        double d = 0;
         double[] xarr = null;
         double[] yarr = null;
         
         xarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
         yarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
-        d = MathX.sumxmy2(xarr, yarr);
-        assertEquals("sumxmy2 ", 10, d);
+        confirmSumxmy2(xarr, yarr, 10);
         
         xarr = new double[]{-1, -2, -3, -4, -5, -6, -7, -8, -9, -10};
         yarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
-        d = MathX.sumxmy2(xarr, yarr);
-        assertEquals("sumxmy2 ", 1330, d);
+        confirmSumxmy2(xarr, yarr, 1330);
         
         xarr = new double[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
         yarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
-        d = MathX.sumxmy2(xarr, yarr);
-        assertEquals("sumxmy2 ", 10, d);
+        confirmSumxmy2(xarr, yarr, 10);
         
         xarr = new double[]{10};
         yarr = new double[]{9};
-        d = MathX.sumxmy2(xarr, yarr);
-        assertEquals("sumxmy2 ", 1, d);
+        confirmSumxmy2(xarr, yarr, 1);
         
         xarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
         yarr = new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
-        d = MathX.sumxmy2(xarr, yarr);
-        assertEquals("sumxmy2 ", 0, d);
+        confirmSumxmy2(xarr, yarr, 0);
     }
 
+    private static void confirmSumx2my2(double[] xarr, double[] yarr, double expectedResult) {
+        confirmXY(new Sumx2my2().createAccumulator(), xarr, yarr, expectedResult);
+    }
+    private static void confirmSumx2py2(double[] xarr, double[] yarr, double expectedResult) {
+        confirmXY(new Sumx2py2().createAccumulator(), xarr, yarr, expectedResult);
+    }
+    private static void confirmSumxmy2(double[] xarr, double[] yarr, double expectedResult) {
+        confirmXY(new Sumxmy2().createAccumulator(), xarr, yarr, expectedResult);
+    }
+
+    private static void confirmXY(Accumulator acc, double[] xarr, double[] yarr,
+            double expectedResult) {
+        double result = 0.0;
+        for (int i = 0; i < xarr.length; i++) {
+            result += acc.accumulate(xarr[i], yarr[i]);
+        }
+        assertEquals(expectedResult, result, 0.0);
+    }
+    
     public void testRound() {
         double d = 0;
         int p = 0;
index 87dd470c681b2e0e17bc3f48fb426cfd3c04f944..76cd1056edef3d26bb866b4a78b9bd9e1d25764c 100755 (executable)
 
 package org.apache.poi.hssf.record.formula.functions;
 
-import org.apache.poi.hssf.record.formula.AreaPtg;
-import org.apache.poi.hssf.record.formula.RefPtg;
-import org.apache.poi.hssf.record.formula.eval.Area2DEval;
+import junit.framework.TestCase;
+
 import org.apache.poi.hssf.record.formula.eval.AreaEval;
 import org.apache.poi.hssf.record.formula.eval.BlankEval;
 import org.apache.poi.hssf.record.formula.eval.BoolEval;
 import org.apache.poi.hssf.record.formula.eval.ErrorEval;
 import org.apache.poi.hssf.record.formula.eval.Eval;
 import org.apache.poi.hssf.record.formula.eval.NumberEval;
-import org.apache.poi.hssf.record.formula.eval.Ref2DEval;
 import org.apache.poi.hssf.record.formula.eval.RefEval;
 import org.apache.poi.hssf.record.formula.eval.StringEval;
 import org.apache.poi.hssf.record.formula.eval.ValueEval;
-
-import junit.framework.TestCase;
 /**
  * Tests for Excel function MID()
- * 
+ *
  * @author Josh Micich
  */
 public final class TestMid extends TestCase {
 
-       
+
        private static Eval invokeMid(Eval text, Eval startPos, Eval numChars) {
                Eval[] args = new Eval[] { text, startPos, numChars, };
                return new Mid().evaluate(args, -1, (short)-1);
@@ -56,28 +52,28 @@ public final class TestMid extends TestCase {
                assertEquals(ErrorEval.class, result.getClass());
                assertEquals(expectedError.getErrorCode(), ((ErrorEval)result).getErrorCode());
        }
-       
+
        public void testBasic() {
-               
+
                confirmMid(new StringEval("galactic"), new NumberEval(3), new NumberEval(4), "lact");
        }
-       
+
        /**
         * Valid cases where args are not precisely (string, int, int) but can be resolved OK.
         */
        public void testUnusualArgs() {
                // startPos with fractional digits
                confirmMid(new StringEval("galactic"), new NumberEval(3.1), new NumberEval(4), "lact");
-               
+
                // string startPos
                confirmMid(new StringEval("galactic"), new StringEval("3"), new NumberEval(4), "lact");
-               
-               // text (first) arg type is number, other args are strings with fractional digits 
+
+               // text (first) arg type is number, other args are strings with fractional digits
                confirmMid(new NumberEval(123456), new StringEval("3.1"), new StringEval("2.9"), "34");
-               
+
                // startPos is 1x1 area ref, numChars is cell ref
-               AreaEval aeStart = new Area2DEval(new AreaPtg("A1:A1"), new ValueEval[] { new NumberEval(2), } );
-               RefEval reNumChars = new Ref2DEval(new RefPtg("B1"), new NumberEval(3));
+               AreaEval aeStart = EvalFactory.createAreaEval("A1:A1", new ValueEval[] { new NumberEval(2), } );
+               RefEval reNumChars = EvalFactory.createRefEval("B1", new NumberEval(3));
                confirmMid(new StringEval("galactic"), aeStart, reNumChars, "ala");
 
                confirmMid(new StringEval("galactic"), new NumberEval(3.1), BlankEval.INSTANCE, "");
@@ -85,7 +81,7 @@ public final class TestMid extends TestCase {
                confirmMid(new StringEval("galactic"), new NumberEval(3), BoolEval.FALSE, "");
                confirmMid(new StringEval("galactic"), new NumberEval(3), BoolEval.TRUE, "l");
                confirmMid(BlankEval.INSTANCE, new NumberEval(3), BoolEval.TRUE, "");
-       
+
        }
 
        /**
@@ -93,7 +89,7 @@ public final class TestMid extends TestCase {
         */
        public void testExtremes() {
                confirmMid(new StringEval("galactic"), new NumberEval(4), new NumberEval(400), "actic");
-               
+
                confirmMid(new StringEval("galactic"), new NumberEval(30), new NumberEval(4), "");
                confirmMid(new StringEval("galactic"), new NumberEval(3), new NumberEval(0), "");
        }
@@ -106,9 +102,9 @@ public final class TestMid extends TestCase {
                confirmMid(new StringEval("galactic"), ErrorEval.NAME_INVALID, new NumberEval(4), ErrorEval.NAME_INVALID);
                confirmMid(new StringEval("galactic"), new NumberEval(3), ErrorEval.NAME_INVALID, ErrorEval.NAME_INVALID);
                confirmMid(new StringEval("galactic"), ErrorEval.DIV_ZERO, ErrorEval.NAME_INVALID, ErrorEval.DIV_ZERO);
-               
+
                confirmMid(new StringEval("galactic"), BlankEval.INSTANCE, new NumberEval(3.1), ErrorEval.VALUE_INVALID);
-               
+
                confirmMid(new StringEval("galactic"), new NumberEval(0), new NumberEval(4), ErrorEval.VALUE_INVALID);
                confirmMid(new StringEval("galactic"), new NumberEval(1), new NumberEval(-1), ErrorEval.VALUE_INVALID);
        }
index 2f9a6314be54222bd69195d188dcebc3449424bc..47ee0afbb62938fdfa303c0af759fa5019237c6f 100755 (executable)
 
 package org.apache.poi.hssf.record.formula.functions;
 
-import org.apache.poi.hssf.record.formula.RefPtg;
+import junit.framework.TestCase;
+
 import org.apache.poi.hssf.record.formula.eval.AreaEval;
 import org.apache.poi.hssf.record.formula.eval.ErrorEval;
 import org.apache.poi.hssf.record.formula.eval.Eval;
 import org.apache.poi.hssf.record.formula.eval.NumberEval;
 import org.apache.poi.hssf.record.formula.eval.NumericValueEval;
-import org.apache.poi.hssf.record.formula.eval.Ref2DEval;
 import org.apache.poi.hssf.record.formula.eval.RefEval;
 import org.apache.poi.hssf.record.formula.eval.ValueEval;
 
-import junit.framework.TestCase;
-
 /**
  * Test cases for SUMPRODUCT()
  * 
@@ -50,7 +48,7 @@ public final class TestSumproduct extends TestCase {
 
        public void testScalarSimple() {
 
-               RefEval refEval = new Ref2DEval(new RefPtg("A1"), new NumberEval(3));
+               RefEval refEval = EvalFactory.createRefEval("A1", new NumberEval(3));
                Eval[] args = {
                        refEval, 
                        new NumberEval(2),
@@ -113,7 +111,6 @@ public final class TestSumproduct extends TestCase {
                };
                AreaEval aeA = EvalFactory.createAreaEval("A1:A2", aValues);
                AreaEval aeB = EvalFactory.createAreaEval("B1:B2", new ValueEval[2]);
-               aeB.getValues()[1] = ErrorEval.REF_INVALID;
 
                Eval[] args = { aeA, aeB, };
                assertEquals(ErrorEval.REF_INVALID, invokeSumproduct(args));
index c57640eabc9e408dbf6c7f9081c04e3d1081261e..ac7152d0e20c6bb670551cefe324a3318b6510e1 100755 (executable)
 
 package org.apache.poi.hssf.record.formula.functions;
 
-import org.apache.poi.hssf.record.formula.RefPtg;
+import junit.framework.TestCase;
+
 import org.apache.poi.hssf.record.formula.eval.BlankEval;
 import org.apache.poi.hssf.record.formula.eval.BoolEval;
 import org.apache.poi.hssf.record.formula.eval.ErrorEval;
 import org.apache.poi.hssf.record.formula.eval.Eval;
 import org.apache.poi.hssf.record.formula.eval.NumberEval;
-import org.apache.poi.hssf.record.formula.eval.Ref2DEval;
 import org.apache.poi.hssf.record.formula.eval.StringEval;
 import org.apache.poi.hssf.record.formula.eval.ValueEval;
 
-import junit.framework.TestCase;
-
 /**
  * Test cases for Excel function T()
  * 
@@ -50,7 +48,7 @@ public final class TestTFunc extends TestCase {
         * where cell A1 has the specified innerValue
         */
        private Eval invokeTWithReference(ValueEval innerValue) {
-               Eval arg = new Ref2DEval(new RefPtg((short)1, (short)1, false, false), innerValue);
+               Eval arg = EvalFactory.createRefEval("$B$2", innerValue);
                return invokeT(arg);
        }
        
index c9f043bd3b79aa61c8ea8633632ba6e377435379..0d62b1fb0fae4a6f2e4c5ec4eb7064eab42a39fc 100755 (executable)
@@ -19,8 +19,6 @@ package org.apache.poi.hssf.record.formula.functions;
 
 import junit.framework.TestCase;
 
-import org.apache.poi.hssf.record.formula.AreaPtg;
-import org.apache.poi.hssf.record.formula.eval.Area2DEval;
 import org.apache.poi.hssf.record.formula.eval.ErrorEval;
 import org.apache.poi.hssf.record.formula.eval.Eval;
 import org.apache.poi.hssf.record.formula.eval.NumberEval;
@@ -100,7 +98,7 @@ public final class TestXYNumericFunction extends TestCase {
 
        private static ValueEval createAreaEval(ValueEval[] values) {
                String refStr = "A1:A" + values.length;
-               return new Area2DEval(new AreaPtg(refStr), values);
+               return EvalFactory.createAreaEval(refStr, values);
        }
 
        public void testErrors() {
index 2382a82359a22d8d28c3fa30820efe2a9253901b..f3430d8bcb62ca8138436a917077bec27a57d322 100644 (file)
@@ -24,8 +24,8 @@ import java.io.IOException;
 import junit.framework.TestCase;
 
 import org.apache.poi.hssf.HSSFTestDataSamples;
-import org.apache.poi.hssf.util.AreaReference;
-import org.apache.poi.hssf.util.CellReference;
+import org.apache.poi.ss.util.AreaReference;
+import org.apache.poi.ss.util.CellReference;
 
 /**
  * 
index 5eb2abb6e690569e4ed13a4fdc01cde391c27593..a5dbb096d411b897ef92212a656ff382f64a715e 100644 (file)
@@ -34,6 +34,8 @@ import org.apache.poi.hssf.usermodel.HSSFName;
 import org.apache.poi.hssf.usermodel.HSSFRow;
 import org.apache.poi.hssf.usermodel.HSSFSheet;
 import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.util.AreaReference;
+import org.apache.poi.ss.util.CellReference;
 /**
  * 
  */
index 8ec8f994674576a37ee780245c3da12322059220..9cc8659fffae213c4abf9c02fa46d69590bb6590 100644 (file)
@@ -20,7 +20,8 @@ package org.apache.poi.hssf.util;
 
 import junit.framework.TestCase;
 
-import org.apache.poi.hssf.util.CellReference.NameType;
+import org.apache.poi.ss.util.CellReference;
+import org.apache.poi.ss.util.CellReference.NameType;
 
 
 public final class TestCellReference extends TestCase {