]> source.dussan.org Git - poi.git/commitdiff
Merged revisions 638786-638802,638805-638811,638813-638814,638816-639230,639233-63924...
authorNick Burch <nick@apache.org>
Mon, 11 Aug 2008 23:58:54 +0000 (23:58 +0000)
committerNick Burch <nick@apache.org>
Mon, 11 Aug 2008 23:58:54 +0000 (23:58 +0000)
https://svn.apache.org/repos/asf/poi/trunk

........
  r684884 | josh | 2008-08-11 20:28:58 +0100 (Mon, 11 Aug 2008) | 1 line

  deleted obsolete comment (should have been done in c669809)
........
  r684938 | josh | 2008-08-11 22:24:19 +0100 (Mon, 11 Aug 2008) | 1 line

  Refinements to fix for bug 45126.  Excel does not produce any records like 'Excel_Name_Record_Titles_*'
........
  r684939 | nick | 2008-08-11 22:25:17 +0100 (Mon, 11 Aug 2008) | 1 line

  CHPXs and PAPXs are apparently cp based, but are really byte based! Work around this
........
  r684959 | nick | 2008-08-11 23:07:37 +0100 (Mon, 11 Aug 2008) | 1 line

  Get insert based HWPF tests working fine, delete ones still problematic
........
  r684971 | josh | 2008-08-11 23:55:38 +0100 (Mon, 11 Aug 2008) | 1 line

  initial work on supporting calls to add-in functions
........
  r684986 | nick | 2008-08-12 00:42:39 +0100 (Tue, 12 Aug 2008) | 1 line

  Finally get all HWPF tests to pass again, by working around how evil PAPX/CHPX/SEPX byte references are
........

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

47 files changed:
src/documentation/content/xdocs/changes.xml
src/documentation/content/xdocs/status.xml
src/java/org/apache/poi/hssf/model/FormulaParser.java
src/java/org/apache/poi/hssf/model/LinkTable.java
src/java/org/apache/poi/hssf/model/Workbook.java
src/java/org/apache/poi/hssf/record/ExternSheetRecord.java
src/java/org/apache/poi/hssf/record/ExternSheetSubRecord.java [deleted file]
src/java/org/apache/poi/hssf/record/NameRecord.java
src/java/org/apache/poi/hssf/record/SupBookRecord.java
src/java/org/apache/poi/hssf/record/formula/AbstractFunctionPtg.java
src/java/org/apache/poi/hssf/record/formula/NameXPtg.java
src/java/org/apache/poi/hssf/usermodel/HSSFName.java
src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java
src/ooxml/interfaces-jdk14/org/apache/poi/ss/usermodel/Name.java
src/ooxml/interfaces-jdk14/org/apache/poi/ss/usermodel/Workbook.java
src/ooxml/interfaces-jdk15/org/apache/poi/ss/usermodel/Name.java
src/scratchpad/src/org/apache/poi/hwpf/HWPFDocument.java
src/scratchpad/src/org/apache/poi/hwpf/model/BytePropertyNode.java [new file with mode: 0644]
src/scratchpad/src/org/apache/poi/hwpf/model/CHPBinTable.java
src/scratchpad/src/org/apache/poi/hwpf/model/CHPFormattedDiskPage.java
src/scratchpad/src/org/apache/poi/hwpf/model/CHPX.java
src/scratchpad/src/org/apache/poi/hwpf/model/PAPBinTable.java
src/scratchpad/src/org/apache/poi/hwpf/model/PAPFormattedDiskPage.java
src/scratchpad/src/org/apache/poi/hwpf/model/PAPX.java
src/scratchpad/src/org/apache/poi/hwpf/model/PropertyNode.java
src/scratchpad/src/org/apache/poi/hwpf/model/SEPX.java
src/scratchpad/src/org/apache/poi/hwpf/model/SectionTable.java
src/scratchpad/src/org/apache/poi/hwpf/model/TextPiece.java
src/scratchpad/src/org/apache/poi/hwpf/model/TextPieceTable.java
src/scratchpad/src/org/apache/poi/hwpf/model/types/FIBAbstractType.java
src/scratchpad/src/org/apache/poi/hwpf/usermodel/Range.java
src/scratchpad/testcases/org/apache/poi/hwpf/model/TestCHPBinTable.java
src/scratchpad/testcases/org/apache/poi/hwpf/model/TestPAPBinTable.java
src/scratchpad/testcases/org/apache/poi/hwpf/model/TestSectionTable.java
src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestProblems.java
src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestRangeDelete.java
src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestRangeInsertion.java
src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestRangeProperties.java
src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestRangeReplacement.java
src/testcases/org/apache/poi/hssf/data/FormulaEvalTestData.xls
src/testcases/org/apache/poi/hssf/data/testNames.xls [new file with mode: 0644]
src/testcases/org/apache/poi/hssf/model/TestFormulaParser.java
src/testcases/org/apache/poi/hssf/record/formula/TestExternalFunctionFormulas.java
src/testcases/org/apache/poi/hssf/record/formula/eval/TestExternalFunction.java
src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java
src/testcases/org/apache/poi/hssf/usermodel/TestHSSFWorkbook.java
src/testcases/org/apache/poi/hssf/usermodel/TestNamedRange.java

index 61632f25efabcd1f7a6bb86e1d4685ae9dc55eb2..fc7ffaceed880671a0ce62f39562b3926a25fbdf 100644 (file)
@@ -58,6 +58,7 @@
            <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="fix">Big improvement in how HWPF handles unicode text, and more sanity checking of text ranges within HWPF</action>
            <action dev="POI-DEVELOPERS" type="add">Include headers and footers int he extracted text from HWPF's WordExtractor</action>
            <action dev="POI-DEVELOPERS" type="add">Added support to HWPF for headers and footers</action>
            <action dev="POI-DEVELOPERS" type="fix">Improve how HWPF deals with unicode internally. Should avoid some odd behaviour when manipulating unicode text</action>
index a8157894f668c5c656b1611f569f4e9db8128d95..1aaf0cc1a65d234bcf603f3a2a47e76e4a03e195 100644 (file)
@@ -55,6 +55,7 @@
            <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="fix">Big improvement in how HWPF handles unicode text, and more sanity checking of text ranges within HWPF</action>
            <action dev="POI-DEVELOPERS" type="add">Include headers and footers int he extracted text from HWPF's WordExtractor</action>
            <action dev="POI-DEVELOPERS" type="add">Added support to HWPF for headers and footers</action>
            <action dev="POI-DEVELOPERS" type="fix">Improve how HWPF deals with unicode internally. Should avoid some odd behaviour when manipulating unicode text</action>
index e229f0358fed6888b5f3b03eef1518e05f89ad40..5fd30d06e04170ecb2c50a357f40b7b9ae89a154 100644 (file)
@@ -25,6 +25,7 @@ import java.util.Stack;
 import org.apache.poi.hssf.record.formula.*;
 import org.apache.poi.hssf.record.formula.function.FunctionMetadata;
 import org.apache.poi.hssf.record.formula.function.FunctionMetadataRegistry;
+import org.apache.poi.ss.usermodel.Name;
 import org.apache.poi.ss.usermodel.Workbook;
 import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
 import org.apache.poi.hssf.usermodel.HSSFWorkbook;
@@ -370,13 +371,32 @@ public final class FormulaParser {
      * @param name case preserved function name (as it was entered/appeared in the formula).
      */
     private ParseNode function(String name) {
-        NamePtg nameToken = null;
-        // Note regarding parameter -
-        if(!AbstractFunctionPtg.isInternalFunctionName(name)) {
-            // external functions get a Name token which points to a defined name record
-            nameToken = new NamePtg(name, this.book);
-
+        Ptg nameToken = null;
+        if(!AbstractFunctionPtg.isBuiltInFunctionName(name)) {
+               // user defined function
             // in the token tree, the name is more or less the first argument
+               
+        
+               int nameIndex = book.getNameIndex(name);
+               if (nameIndex >= 0) {
+                       Name hName = book.getNameAt(nameIndex);
+                       if (!hName.isFunctionName()) {
+                               throw new FormulaParseException("Attempt to use name '" + name 
+                                               + "' as a function, but defined name in workbook does not refer to a function");
+                       }
+                       
+                       // calls to user-defined functions within the workbook 
+                       // get a Name token which points to a defined name record
+                       nameToken = new NamePtg(name, this.book);
+               } else {
+                               if(book instanceof HSSFWorkbook) {
+                                       nameToken = ((HSSFWorkbook)book).getNameXPtg(name);
+                               }
+                       if (nameToken == null) {
+                               throw new FormulaParseException("Name '" + name 
+                                               + "' is completely unknown in the current workbook");
+                       }
+               }
         }
 
         Match('(');
@@ -390,11 +410,11 @@ public final class FormulaParser {
      * Generates the variable function ptg for the formula.
      * <p>
      * For IF Formulas, additional PTGs are added to the tokens
-     * @param name
+     * @param name a {@link NamePtg} or {@link NameXPtg} or <code>null</code>
      * @param numArgs
      * @return Ptg a null is returned if we're in an IF formula, it needs extreme manipulation and is handled in this function
      */
-    private ParseNode getFunction(String name, NamePtg namePtg, ParseNode[] args) {
+    private ParseNode getFunction(String name, Ptg namePtg, ParseNode[] args) {
 
         FunctionMetadata fm = FunctionMetadataRegistry.getFunctionByName(name.toUpperCase());
         int numArgs = args.length;
index 1d8781d9713dc1e91939a031aa24b4ea88d574d3..9d1707558d63792de794dadbbf2f3c0e17d05211 100755 (executable)
@@ -25,11 +25,11 @@ import org.apache.poi.hssf.record.CRNCountRecord;
 import org.apache.poi.hssf.record.CRNRecord;
 import org.apache.poi.hssf.record.CountryRecord;
 import org.apache.poi.hssf.record.ExternSheetRecord;
-import org.apache.poi.hssf.record.ExternSheetSubRecord;
 import org.apache.poi.hssf.record.ExternalNameRecord;
 import org.apache.poi.hssf.record.NameRecord;
 import org.apache.poi.hssf.record.Record;
 import org.apache.poi.hssf.record.SupBookRecord;
+import org.apache.poi.hssf.record.formula.NameXPtg;
 
 /**
  * Link Table (OOO pdf reference: 4.10.3 ) <p/>
@@ -122,6 +122,19 @@ final class LinkTable {
                public String getNameText(int definedNameIndex) {
                        return _externalNameRecords[definedNameIndex].getText();
                }
+
+               /**
+                * Performs case-insensitive search
+                * @return -1 if not found
+                */
+               public int getIndexOfName(String name) {
+                       for (int i = 0; i < _externalNameRecords.length; i++) {
+                               if(_externalNameRecords[i].getText().equalsIgnoreCase(name)) {
+                                       return i;
+                               }
+                       }
+                       return -1;
+               }
        }
 
        private final ExternalBookBlock[] _externalBookBlocks;
@@ -192,14 +205,18 @@ final class LinkTable {
        }
 
 
-       public NameRecord getSpecificBuiltinRecord(byte name, int sheetIndex) {
+       /**
+        * @param builtInCode a BUILTIN_~ constant from {@link NameRecord}
+        * @param sheetNumber 1-based sheet number
+        */
+       public NameRecord getSpecificBuiltinRecord(byte builtInCode, int sheetNumber) {
 
                Iterator iterator = _definedNames.iterator();
                while (iterator.hasNext()) {
                        NameRecord record = ( NameRecord ) iterator.next();
 
                        //print areas are one based
-                       if (record.getBuiltInName() == name && record.getIndexToSheet() == sheetIndex) {
+                       if (record.getBuiltInName() == builtInCode && record.getSheetNumber() == sheetNumber) {
                                return record;
                        }
                }
@@ -241,69 +258,56 @@ final class LinkTable {
                _definedNames.remove(namenum);
        }
 
-    /**
-     * checks if the given name is already included in the linkTable
-     */
-    public boolean nameAlreadyExists(NameRecord name)
-    {
-       // Check to ensure no other names have the same case-insensitive name
-       for ( int i = getNumNames()-1; i >=0; i-- ) {
-               NameRecord rec = getNameRecord(i);
-               if (rec != name) {
-                       if (isDuplicatedNames(name, rec))
-                               return true;
-               }
-       }
-       return false;
-    }
-    
-    private boolean isDuplicatedNames(NameRecord firstName, NameRecord lastName)
-    {
-       return lastName.getNameText().equalsIgnoreCase(firstName.getNameText()) 
-               && isSameSheetNames(firstName, lastName);
-    }
-    private boolean isSameSheetNames(NameRecord firstName, NameRecord lastName)
-    {
-       return lastName.getEqualsToIndexToSheet() == firstName.getEqualsToIndexToSheet();
-    }
-
-    
-       public short getIndexToSheet(short num) {
-               return _externSheetRecord.getREFRecordAt(num).getIndexToFirstSupBook();
+       /**
+        * checks if the given name is already included in the linkTable
+        */
+       public boolean nameAlreadyExists(NameRecord name)
+       {
+               // Check to ensure no other names have the same case-insensitive name
+               for ( int i = getNumNames()-1; i >=0; i-- ) {
+                       NameRecord rec = getNameRecord(i);
+                       if (rec != name) {
+                               if (isDuplicatedNames(name, rec))
+                                       return true;
+                       }
+               }
+               return false;
+       }
+       
+       private static boolean isDuplicatedNames(NameRecord firstName, NameRecord lastName) {
+               return lastName.getNameText().equalsIgnoreCase(firstName.getNameText()) 
+                       && isSameSheetNames(firstName, lastName);
+       }
+       private static boolean isSameSheetNames(NameRecord firstName, NameRecord lastName) {
+               return lastName.getSheetNumber() == firstName.getSheetNumber();
+       }
+
+       
+       public int getIndexToSheet(int extRefIndex) {
+               return _externSheetRecord.getFirstSheetIndexFromRefIndex(extRefIndex);
        }
 
-       public int getSheetIndexFromExternSheetIndex(int externSheetNumber) {
-               if (externSheetNumber >= _externSheetRecord.getNumOfREFStructures()) {
+       public int getSheetIndexFromExternSheetIndex(int extRefIndex) {
+               if (extRefIndex >= _externSheetRecord.getNumOfRefs()) {
                        return -1;
                }
-               return _externSheetRecord.getREFRecordAt(externSheetNumber).getIndexToFirstSupBook();
+               return _externSheetRecord.getFirstSheetIndexFromRefIndex(extRefIndex);
        }
 
-       public short addSheetIndexToExternSheet(short sheetNumber) {
-
-               ExternSheetSubRecord record = new ExternSheetSubRecord();
-               record.setIndexToFirstSupBook(sheetNumber);
-               record.setIndexToLastSupBook(sheetNumber);
-               _externSheetRecord.addREFRecord(record);
-               _externSheetRecord.setNumOfREFStructures((short)(_externSheetRecord.getNumOfREFStructures() + 1));
-               return (short)(_externSheetRecord.getNumOfREFStructures() - 1);
+       public int addSheetIndexToExternSheet(int sheetNumber) {
+               // TODO - what about the first parameter (extBookIndex)?
+               return _externSheetRecord.addRef(0, sheetNumber, sheetNumber);
        }
 
-       public short checkExternSheet(int sheetNumber) {
+       public short checkExternSheet(int sheetIndex) {
 
                //Trying to find reference to this sheet
-               int nESRs = _externSheetRecord.getNumOfREFStructures();
-               for(short i=0; i< nESRs; i++) {
-                       ExternSheetSubRecord esr = _externSheetRecord.getREFRecordAt(i);
-
-                       if (esr.getIndexToFirstSupBook() ==  sheetNumber
-                                       && esr.getIndexToLastSupBook() == sheetNumber){
-                               return i;
-                       }
+               int i = _externSheetRecord.getRefIxForSheet(sheetIndex);
+               if (i>=0) {
+                       return (short)i;
                }
-
                //We Haven't found reference to this sheet
-               return addSheetIndexToExternSheet((short) sheetNumber);
+               return (short)addSheetIndexToExternSheet((short) sheetIndex);
        }
 
 
@@ -324,11 +328,31 @@ final class LinkTable {
        }
 
        public int getNumberOfREFStructures() {
-               return _externSheetRecord.getNumOfREFStructures();
+               return _externSheetRecord.getNumOfRefs();
        }
 
        public String resolveNameXText(int refIndex, int definedNameIndex) {
-               short extBookIndex = _externSheetRecord.getREFRecordAt(refIndex).getIndexToSupBook();
+               int extBookIndex = _externSheetRecord.getExtbookIndexFromRefIndex(refIndex);
                return _externalBookBlocks[extBookIndex].getNameText(definedNameIndex);
        }
+
+       public NameXPtg getNameXPtg(String name) {
+               // first find any external book block that contains the name:
+               for (int i = 0; i < _externalBookBlocks.length; i++) {
+                       int definedNameIndex = _externalBookBlocks[i].getIndexOfName(name);
+                       if (definedNameIndex < 0) {
+                               continue;
+                       }
+                       // found it.
+                       int sheetRefIndex = findRefIndexFromExtBookIndex(i); 
+                       if (sheetRefIndex >= 0) {
+                               return new NameXPtg(sheetRefIndex, definedNameIndex);
+                       }
+               }
+               return null;
+       }
+
+       private int findRefIndexFromExtBookIndex(int extBookIndex) {
+               return _externSheetRecord.findRefIndexFromExtBookIndex(extBookIndex); 
+       }
 }
index f80c41661d8ad6755fa9ea523e4923417473ce80..5ad1ef28d3cc4d725fa6ee3ab33a1ebe52ec3d98 100644 (file)
    limitations under the License.
 ==================================================================== */
 
-
 package org.apache.poi.hssf.model;
 
-import org.apache.poi.ddf.*;
-import org.apache.poi.hssf.record.*;
-import org.apache.poi.hssf.util.HSSFColor;
-import org.apache.poi.hssf.util.SheetReferences;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
-
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
 
+import org.apache.poi.ddf.EscherBSERecord;
+import org.apache.poi.ddf.EscherBoolProperty;
+import org.apache.poi.ddf.EscherContainerRecord;
+import org.apache.poi.ddf.EscherDggRecord;
+import org.apache.poi.ddf.EscherOptRecord;
+import org.apache.poi.ddf.EscherProperties;
+import org.apache.poi.ddf.EscherRGBProperty;
+import org.apache.poi.ddf.EscherRecord;
+import org.apache.poi.ddf.EscherSplitMenuColorsRecord;
+import org.apache.poi.hssf.record.BOFRecord;
+import org.apache.poi.hssf.record.BackupRecord;
+import org.apache.poi.hssf.record.BookBoolRecord;
+import org.apache.poi.hssf.record.BoundSheetRecord;
+import org.apache.poi.hssf.record.CodepageRecord;
+import org.apache.poi.hssf.record.CountryRecord;
+import org.apache.poi.hssf.record.DSFRecord;
+import org.apache.poi.hssf.record.DateWindow1904Record;
+import org.apache.poi.hssf.record.DrawingGroupRecord;
+import org.apache.poi.hssf.record.EOFRecord;
+import org.apache.poi.hssf.record.ExtSSTRecord;
+import org.apache.poi.hssf.record.ExtendedFormatRecord;
+import org.apache.poi.hssf.record.ExternSheetRecord;
+import org.apache.poi.hssf.record.FileSharingRecord;
+import org.apache.poi.hssf.record.FnGroupCountRecord;
+import org.apache.poi.hssf.record.FontRecord;
+import org.apache.poi.hssf.record.FormatRecord;
+import org.apache.poi.hssf.record.HideObjRecord;
+import org.apache.poi.hssf.record.HyperlinkRecord;
+import org.apache.poi.hssf.record.InterfaceEndRecord;
+import org.apache.poi.hssf.record.InterfaceHdrRecord;
+import org.apache.poi.hssf.record.MMSRecord;
+import org.apache.poi.hssf.record.NameRecord;
+import org.apache.poi.hssf.record.PaletteRecord;
+import org.apache.poi.hssf.record.PasswordRecord;
+import org.apache.poi.hssf.record.PasswordRev4Record;
+import org.apache.poi.hssf.record.PrecisionRecord;
+import org.apache.poi.hssf.record.ProtectRecord;
+import org.apache.poi.hssf.record.ProtectionRev4Record;
+import org.apache.poi.hssf.record.RecalcIdRecord;
+import org.apache.poi.hssf.record.Record;
+import org.apache.poi.hssf.record.RefreshAllRecord;
+import org.apache.poi.hssf.record.SSTRecord;
+import org.apache.poi.hssf.record.StyleRecord;
+import org.apache.poi.hssf.record.SupBookRecord;
+import org.apache.poi.hssf.record.TabIdRecord;
+import org.apache.poi.hssf.record.UnicodeString;
+import org.apache.poi.hssf.record.UseSelFSRecord;
+import org.apache.poi.hssf.record.WindowOneRecord;
+import org.apache.poi.hssf.record.WindowProtectRecord;
+import org.apache.poi.hssf.record.WriteAccessRecord;
+import org.apache.poi.hssf.record.WriteProtectRecord;
+import org.apache.poi.hssf.record.formula.NameXPtg;
+import org.apache.poi.hssf.util.HSSFColor;
+import org.apache.poi.hssf.util.SheetReferences;
+import org.apache.poi.util.POILogFactory;
+import org.apache.poi.util.POILogger;
+
 /**
  * Low level model implementation of a Workbook.  Provides creational methods
  * for settings and objects contained in the workbook object.
@@ -54,18 +103,13 @@ import java.util.Locale;
  * @see org.apache.poi.hssf.usermodel.HSSFWorkbook
  * @version 1.0-pre
  */
-
-public class Workbook implements Model
-{
+public final class Workbook implements Model {
     private static final int   DEBUG       = POILogger.DEBUG;
 
-//    public static Workbook currentBook = null;
-
     /**
      * constant used to set the "codepage" wherever "codepage" is set in records
-     * (which is duplciated in more than one record)
+     * (which is duplicated in more than one record)
      */
-
     private final static short CODEPAGE    = ( short ) 0x4b0;
 
     /**
@@ -105,8 +149,6 @@ public class Workbook implements Model
 
     private static POILogger   log = POILogFactory.getLogger(Workbook.class);
 
-    protected static final String EXCEL_REPEATING_NAME_PREFIX_ = "Excel_Name_Record_Titles_";
-
     /**
      * Creates new Workbook with no intitialization --useless right now
      * @see #createWorkbook(List)
@@ -250,9 +292,9 @@ public class Workbook implements Model
         for ( ; k < recs.size(); k++) {
             Record rec = ( Record ) recs.get(k);
             switch (rec.getSid()) {
-               case HyperlinkRecord.sid:
-                       retval.hyperlinks.add(rec);
-                       break;
+                case HyperlinkRecord.sid:
+                    retval.hyperlinks.add(rec);
+                    break;
             }
         }
         
@@ -358,22 +400,22 @@ public class Workbook implements Model
     }
 
 
-       /**Retrieves the Builtin NameRecord that matches the name and index
-        * There shouldn't be too many names to make the sequential search too slow
-        * @param name byte representation of the builtin name to match
-        * @param sheetIndex Index to match
-        * @return null if no builtin NameRecord matches
-        */
-    public NameRecord getSpecificBuiltinRecord(byte name, int sheetIndex)
+    /**Retrieves the Builtin NameRecord that matches the name and index
+     * There shouldn't be too many names to make the sequential search too slow
+     * @param name byte representation of the builtin name to match
+     * @param sheetNumber 1-based sheet number
+     * @return null if no builtin NameRecord matches
+     */
+    public NameRecord getSpecificBuiltinRecord(byte name, int sheetNumber)
     {
-        return getOrCreateLinkTable().getSpecificBuiltinRecord(name, sheetIndex);
+        return getOrCreateLinkTable().getSpecificBuiltinRecord(name, sheetNumber);
     }
 
-       /**
-        * Removes the specified Builtin NameRecord that matches the name and index
-        * @param name byte representation of the builtin to match
-        * @param sheetIndex zero-based sheet reference
-        */
+    /**
+     * Removes the specified Builtin NameRecord that matches the name and index
+     * @param name byte representation of the builtin to match
+     * @param sheetIndex zero-based sheet reference
+     */
     public void removeBuiltinRecord(byte name, int sheetIndex) {
         linkTable.removeBuiltinRecord(name, sheetIndex);
         // TODO - do we need "this.records.remove(...);" similar to that in this.removeName(int namenum) {}?
@@ -413,18 +455,18 @@ public class Workbook implements Model
      * Retrieves the index of the given font
      */
     public int getFontIndex(FontRecord font) {
-       for(int i=0; i<=numfonts; i++) {
+        for(int i=0; i<=numfonts; i++) {
             FontRecord thisFont =
                 ( FontRecord ) records.get((records.getFontpos() - (numfonts - 1)) + i);
             if(thisFont == font) {
-               // There is no 4!
-               if(i > 3) {
-                       return (i+1);
-               }
-               return i;
+                // There is no 4!
+                if(i > 3) {
+                    return (i+1);
+                }
+                return i;
             }
-       }
-       throw new IllegalArgumentException("Could not find that font!"); 
+        }
+        throw new IllegalArgumentException("Could not find that font!"); 
     }
 
     /**
@@ -451,7 +493,7 @@ public class Workbook implements Model
      *  so you'll need to update those yourself!
      */
     public void removeFontRecord(FontRecord rec) {
-       records.remove(rec); // this updates FontPos for us
+        records.remove(rec); // this updates FontPos for us
         numfonts--;
     }
 
@@ -468,19 +510,23 @@ public class Workbook implements Model
     /**
      * Sets the BOF for a given sheet
      *
-     * @param sheetnum the number of the sheet to set the positing of the bof for
+     * @param sheetIndex the number of the sheet to set the positing of the bof for
      * @param pos the actual bof position
      */
 
-    public void setSheetBof(int sheetnum, int pos) {
+    public void setSheetBof(int sheetIndex, int pos) {
         if (log.check( POILogger.DEBUG ))
-            log.log(DEBUG, "setting bof for sheetnum =", new Integer(sheetnum),
+            log.log(DEBUG, "setting bof for sheetnum =", new Integer(sheetIndex),
                 " at pos=", new Integer(pos));
-        checkSheets(sheetnum);
-        (( BoundSheetRecord ) boundsheets.get(sheetnum))
+        checkSheets(sheetIndex);
+        getBoundSheetRec(sheetIndex)
         .setPositionOfBof(pos);
     }
 
+    private BoundSheetRecord getBoundSheetRec(int sheetIndex) {
+        return ((BoundSheetRecord) boundsheets.get(sheetIndex));
+    }
+
     /**
      * Returns the position of the backup record.
      */
@@ -516,7 +562,7 @@ public class Workbook implements Model
     {
         for ( int i = 0; i < boundsheets.size(); i++ )
         {
-            BoundSheetRecord boundSheetRecord = (BoundSheetRecord) boundsheets.get( i );
+            BoundSheetRecord boundSheetRecord = getBoundSheetRec(i);
             if (excludeSheetIdx != i && name.equalsIgnoreCase(boundSheetRecord.getSheetname()))
                 return true;
         }
@@ -533,35 +579,33 @@ public class Workbook implements Model
      */    
     public void setSheetName(int sheetnum, String sheetname, short encoding ) {
         checkSheets(sheetnum);
-        BoundSheetRecord sheet = (BoundSheetRecord)boundsheets.get( sheetnum );
+        BoundSheetRecord sheet = getBoundSheetRec(sheetnum);
         sheet.setSheetname(sheetname);
         sheet.setSheetnameLength( (byte)sheetname.length() );
-               sheet.setCompressedUnicodeFlag( (byte)encoding );
+        sheet.setCompressedUnicodeFlag( (byte)encoding );
     }
     
     /**
-        * sets the order of appearance for a given sheet.
-        *
-        * @param sheetname the name of the sheet to reorder
-        * @param pos the position that we want to insert the sheet into (0 based)
-        */
+     * sets the order of appearance for a given sheet.
+     *
+     * @param sheetname the name of the sheet to reorder
+     * @param pos the position that we want to insert the sheet into (0 based)
+     */
     
     public void setSheetOrder(String sheetname, int pos ) {
-       int sheetNumber = getSheetIndex(sheetname);
-       //remove the sheet that needs to be reordered and place it in the spot we want
-       boundsheets.add(pos, boundsheets.remove(sheetNumber));  
+    int sheetNumber = getSheetIndex(sheetname);
+    //remove the sheet that needs to be reordered and place it in the spot we want
+    boundsheets.add(pos, boundsheets.remove(sheetNumber));    
     }
 
     /**
      * gets the name for a given sheet.
      *
-     * @param sheetnum the sheet number (0 based)
+     * @param sheetIndex the sheet number (0 based)
      * @return sheetname the name for the sheet
      */
-
-    public String getSheetName(int sheetnum) {
-        return (( BoundSheetRecord ) boundsheets.get(sheetnum))
-        .getSheetname();
+    public String getSheetName(int sheetIndex) {
+        return getBoundSheetRec(sheetIndex).getSheetname();
     }
 
     /**
@@ -572,8 +616,7 @@ public class Workbook implements Model
      */
 
     public boolean isSheetHidden(int sheetnum) {
-        BoundSheetRecord bsr = ( BoundSheetRecord ) boundsheets.get(sheetnum);
-        return bsr.isHidden();
+        return getBoundSheetRec(sheetnum).isHidden();
     }
 
     /**
@@ -584,8 +627,7 @@ public class Workbook implements Model
      */
     
     public void setSheetHidden(int sheetnum, boolean hidden) {
-        BoundSheetRecord bsr = ( BoundSheetRecord ) boundsheets.get(sheetnum);
-        bsr.setHidden(hidden);
+        getBoundSheetRec(sheetnum).setHidden(hidden);
     }
     /**
      * get the sheet's index
@@ -627,11 +669,13 @@ public class Workbook implements Model
         }
     }
 
-    public void removeSheet(int sheetnum) {
-        if (boundsheets.size() > sheetnum) {
-            records.remove(records.getBspos() - (boundsheets.size() - 1) + sheetnum);
-//            records.bspos--;
-            boundsheets.remove(sheetnum);
+    /**
+     * @param sheetIndex zero based sheet index
+     */
+    public void removeSheet(int sheetIndex) {
+        if (boundsheets.size() > sheetIndex) {
+            records.remove(records.getBspos() - (boundsheets.size() - 1) + sheetIndex);
+            boundsheets.remove(sheetIndex);
             fixTabIdRecord();
         }
         
@@ -642,20 +686,18 @@ public class Workbook implements Model
         // However, the sheet index must be adjusted, or
         //  excel will break. (Sheet index is either 0 for
         //  global, or 1 based index to sheet)
-        int sheetNum1Based = sheetnum + 1;
+        int sheetNum1Based = sheetIndex + 1;
         for(int i=0; i<getNumNames(); i++) {
-               NameRecord nr = getNameRecord(i);
-               
-               if(nr.getIndexToSheet() == sheetNum1Based) {
-                       // Excel re-writes these to point to no sheet
-                       nr.setEqualsToIndexToSheet((short)0);
-               } else if(nr.getIndexToSheet() > sheetNum1Based) {
-                       // Bump down by one, so still points
-                       //  at the same sheet
-                       nr.setEqualsToIndexToSheet((short)(
-                                       nr.getEqualsToIndexToSheet()-1
-                       ));
-               }
+            NameRecord nr = getNameRecord(i);
+            
+            if(nr.getSheetNumber() == sheetNum1Based) {
+                // Excel re-writes these to point to no sheet
+                nr.setSheetNumber(0);
+            } else if(nr.getSheetNumber() > sheetNum1Based) {
+                // Bump down by one, so still points
+                //  at the same sheet
+                nr.setSheetNumber(nr.getSheetNumber()-1);
+            }
         }
     }
 
@@ -721,7 +763,7 @@ public class Workbook implements Model
      *  so you'll need to update those yourself!
      */
     public void removeExFormatRecord(ExtendedFormatRecord rec) {
-       records.remove(rec); // this updates XfPos for us
+        records.remove(rec); // this updates XfPos for us
         numxfs--;
     }
 
@@ -813,9 +855,9 @@ public class Workbook implements Model
 //
 //            Record record = records.get(k);
 ////             Let's skip RECALCID records, as they are only use for optimization
-//         if(record.getSid() != RecalcIdRecord.sid || ((RecalcIdRecord)record).isNeeded()) {
+//        if(record.getSid() != RecalcIdRecord.sid || ((RecalcIdRecord)record).isNeeded()) {
 //                pos += record.serialize(pos, retval);   // rec.length;
-//         }
+//        }
 //        }
 //        log.log(DEBUG, "Exiting serialize workbook");
 //        return retval;
@@ -858,7 +900,7 @@ public class Workbook implements Model
                 if (record instanceof BoundSheetRecord) {
                      if(!wroteBoundSheets) {
                         for (int i = 0; i < boundsheets.size(); i++) {
-                            len+= ((BoundSheetRecord)boundsheets.get(i))
+                            len+= getBoundSheetRec(i)
                                              .serialize(pos+offset+len, data);
                         }
                         wroteBoundSheets = true;
@@ -1141,8 +1183,8 @@ public class Workbook implements Model
         retval.setWidth(( short ) 0x3a5c);
         retval.setHeight(( short ) 0x23be);
         retval.setOptions(( short ) 0x38);
-        retval.setSelectedTab(( short ) 0x0);
-        retval.setDisplayedTab(( short ) 0x0);
+        retval.setActiveSheetIndex( 0x0);
+        retval.setFirstVisibleTab(0x0);
         retval.setNumSelectedTabs(( short ) 1);
         retval.setTabWidthRatio(( short ) 0x258);
         return retval;
@@ -1821,10 +1863,10 @@ public class Workbook implements Model
 
         // from Russia with love ;)
         if ( Locale.getDefault().toString().equals( "ru_RU" ) ) {
-               retval.setCurrentCountry(( short ) 7);
+            retval.setCurrentCountry(( short ) 7);
         }
         else {
-               retval.setCurrentCountry(( short ) 1);
+            retval.setCurrentCountry(( short ) 1);
         }
 
         return retval;
@@ -1889,15 +1931,15 @@ public class Workbook implements Model
      * @return sheet name
      */
     public String findSheetNameFromExternSheet(short num){
-        String result="";
 
-        short indexToSheet = linkTable.getIndexToSheet(num);
+        int indexToSheet = linkTable.getIndexToSheet(num);
         
-        if (indexToSheet>-1) { //error check, bail out gracefully!
-            result = getSheetName(indexToSheet);
+        if (indexToSheet < 0) {
+            // TODO - what does '-1' mean here?
+            //error check, bail out gracefully!
+            return "";
         }
-
-        return result;
+        return getSheetName(indexToSheet);
     }
 
     /**
@@ -1950,10 +1992,10 @@ public class Workbook implements Model
      */
     public NameRecord addName(NameRecord name)
     {
-       
+        
         LinkTable linkTable = getOrCreateLinkTable();
         if(linkTable.nameAlreadyExists(name)) {
-               throw new IllegalArgumentException(
+            throw new IllegalArgumentException(
                 "You are trying to assign a duplicated name record: "
                 + name.getNameText());
         }
@@ -1964,27 +2006,18 @@ public class Workbook implements Model
     
     /**
      * Generates a NameRecord to represent a built-in region
-     * @return a new NameRecord unless the index is invalid
+     * @return a new NameRecord
      */
-    public NameRecord createBuiltInName(byte builtInName, int index)
-    {
-        if (index == -1 || index+1 > Short.MAX_VALUE) 
-            throw new IllegalArgumentException("Index is not valid ["+index+"]");
+    public NameRecord createBuiltInName(byte builtInName, int sheetNumber) {
+        if (sheetNumber < 0 || sheetNumber+1 > Short.MAX_VALUE) {
+            throw new IllegalArgumentException("Sheet number ["+sheetNumber+"]is not valid ");
+        }
         
-        NameRecord name = new NameRecord(builtInName, (short)(index));
+        NameRecord name = new NameRecord(builtInName, sheetNumber);
         
-        String prefix = EXCEL_REPEATING_NAME_PREFIX_ + index + "_";
-        int cont = 0;
         while(linkTable.nameAlreadyExists(name)) {
-               cont++;
-               String altNameName = prefix + cont;
-               
-               // It would be better to set a different builtInName here.
-               // It does not seem possible, so we create it as a 
-               //  non built-in name from this point on
-               name = new NameRecord();
-               name.setNameText(altNameName);
-            name.setNameTextLength((byte)altNameName.length());
+            throw new RuntimeException("Builtin (" + builtInName 
+                    + ") already exists for sheet (" + sheetNumber + ")");
         }
         addName(name);
         return name;
@@ -1992,16 +2025,15 @@ public class Workbook implements Model
 
 
     /** removes the name
-     * @param namenum name index
+     * @param nameIndex name index
      */
-    public void removeName(int namenum){
+    public void removeName(int nameIndex){
         
-        if (linkTable.getNumNames() > namenum) {
+        if (linkTable.getNumNames() > nameIndex) {
             int idx = findFirstRecordLocBySid(NameRecord.sid);
-            records.remove(idx + namenum);
-            linkTable.removeName(namenum);
+            records.remove(idx + nameIndex);
+            linkTable.removeName(nameIndex);
         }
-
     }
 
     /**
@@ -2011,19 +2043,19 @@ public class Workbook implements Model
      * @return the format id of a format that matches or -1 if none found and createIfNotFound
      */
     public short getFormat(String format, boolean createIfNotFound) {
-       Iterator iterator;
-       for (iterator = formats.iterator(); iterator.hasNext();) {
-           FormatRecord r = (FormatRecord)iterator.next();
-           if (r.getFormatString().equals(format)) {
-               return r.getIndexCode();
-           }
-       }
+    Iterator iterator;
+    for (iterator = formats.iterator(); iterator.hasNext();) {
+        FormatRecord r = (FormatRecord)iterator.next();
+        if (r.getFormatString().equals(format)) {
+        return r.getIndexCode();
+        }
+    }
 
-       if (createIfNotFound) {
-           return createFormat(format);
-       }
+    if (createIfNotFound) {
+        return createFormat(format);
+    }
 
-       return -1;
+    return -1;
     }
 
     /**
@@ -2031,7 +2063,7 @@ public class Workbook implements Model
      * @return ArrayList of FormatRecords in the notebook
      */
     public ArrayList getFormats() {
-       return formats;
+    return formats;
     }
 
     /**
@@ -2043,7 +2075,7 @@ public class Workbook implements Model
      */
     public short createFormat( String format )
     {
-//        ++xfpos;     //These are to ensure that positions are updated properly
+//        ++xfpos;    //These are to ensure that positions are updated properly
 //        ++palettepos;
 //        ++bspos;
         FormatRecord rec = new FormatRecord();
@@ -2113,7 +2145,7 @@ public class Workbook implements Model
 
     public List getHyperlinks()
     {
-       return hyperlinks;
+        return hyperlinks;
     }
     
     public List getRecords()
@@ -2170,54 +2202,54 @@ public class Workbook implements Model
      * Finds the primary drawing group, if one already exists
      */
     public void findDrawingGroup() {
-       // Need to find a DrawingGroupRecord that
-       //  contains a EscherDggRecord
-       for(Iterator rit = records.iterator(); rit.hasNext();) {
-               Record r = (Record)rit.next();
-               
-               if(r instanceof DrawingGroupRecord) {
-               DrawingGroupRecord dg = (DrawingGroupRecord)r;
-               dg.processChildRecords();
-               
-               EscherContainerRecord cr =
-                       dg.getEscherContainer();
-               if(cr == null) {
-                       continue;
-               }
-               
-               EscherDggRecord dgg = null;
-               for(Iterator it = cr.getChildRecords().iterator(); it.hasNext();) {
-                       Object er = it.next();
-                       if(er instanceof EscherDggRecord) {
-                               dgg = (EscherDggRecord)er;
-                       }
-               }
-               
-               if(dgg != null) {
-                       drawingManager = new DrawingManager2(dgg);
-                       return;
-               }
-               }
-       }
-
-       // Look for the DrawingGroup record
+        // Need to find a DrawingGroupRecord that
+        //  contains a EscherDggRecord
+        for(Iterator rit = records.iterator(); rit.hasNext();) {
+            Record r = (Record)rit.next();
+            
+            if(r instanceof DrawingGroupRecord) {
+                DrawingGroupRecord dg =    (DrawingGroupRecord)r;
+                dg.processChildRecords();
+                
+                EscherContainerRecord cr =
+                    dg.getEscherContainer();
+                if(cr == null) {
+                    continue;
+                }
+                
+                EscherDggRecord dgg = null;
+                for(Iterator it = cr.getChildRecords().iterator(); it.hasNext();) {
+                    Object er = it.next();
+                    if(er instanceof EscherDggRecord) {
+                        dgg = (EscherDggRecord)er;
+                    }
+                }
+                
+                if(dgg != null) {
+                    drawingManager = new DrawingManager2(dgg);
+                    return;
+                }
+            }
+        }
+
+        // Look for the DrawingGroup record
         int dgLoc = findFirstRecordLocBySid(DrawingGroupRecord.sid);
         
-       // If there is one, does it have a EscherDggRecord?
+        // If there is one, does it have a EscherDggRecord?
         if(dgLoc != -1) {
-               DrawingGroupRecord dg =
-                       (DrawingGroupRecord)records.get(dgLoc);
-               EscherDggRecord dgg = null;
-               for(Iterator it = dg.getEscherRecords().iterator(); it.hasNext();) {
-                       Object er = it.next();
-                       if(er instanceof EscherDggRecord) {
-                               dgg = (EscherDggRecord)er;
-                       }
-               }
-               
-               if(dgg != null) {
-                       drawingManager = new DrawingManager2(dgg);
-               }
+            DrawingGroupRecord dg =
+                (DrawingGroupRecord)records.get(dgLoc);
+            EscherDggRecord dgg = null;
+            for(Iterator it = dg.getEscherRecords().iterator(); it.hasNext();) {
+                Object er = it.next();
+                if(er instanceof EscherDggRecord) {
+                    dgg = (EscherDggRecord)er;
+                }
+            }
+            
+            if(dgg != null) {
+                drawingManager = new DrawingManager2(dgg);
+            }
         }
     }
 
@@ -2379,7 +2411,7 @@ public class Workbook implements Model
      */
     public boolean isWriteProtected() {
         if (this.fileShare == null) {
-               return false;
+            return false;
         }
         FileSharingRecord frec = getFileSharing();
         return (frec.getReadOnly() == 1);
@@ -2419,6 +2451,8 @@ public class Workbook implements Model
     public String resolveNameXText(int refIndex, int definedNameIndex) {
         return linkTable.resolveNameXText(refIndex, definedNameIndex);
     }
-}
-
 
+    public NameXPtg getNameXPtg(String name) {
+        return getOrCreateLinkTable().getNameXPtg(name);
+    }
+}
index 0d1823a7c49286befae8c2b3419fcdf2a09cb098..2b0744a91e3e7be67a728aaa24d12579fe7b60a5 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
    See the License for the specific language governing permissions and
    limitations under the License.
 ==================================================================== */
-        
 
 package org.apache.poi.hssf.record;
 
-import org.apache.poi.util.LittleEndian;
-
 import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.poi.util.LittleEndian;
 
 /**
- * Title:        Extern Sheet <P>
- * Description:  A List of Inndexes to SupBook <P>
- * REFERENCE:  <P>
+ * EXTERNSHEET (0x0017)<br/>
+ * A List of Indexes to  EXTERNALBOOK (supplemental book) Records <p/>
+ * 
  * @author Libin Roman (Vista Portal LDT. Developer)
- * @version 1.0-pre
  */
-
 public class ExternSheetRecord extends Record {
-    public final static short sid = 0x17;
-    private short             field_1_number_of_REF_sturcutres;
-    private ArrayList         field_2_REF_structures;
+    public final static short sid = 0x0017;
+    private List         _list;
+    
+    private final class RefSubRecord {
+       public static final int ENCODED_SIZE = 6;
+
+       /** index to External Book Block (which starts with a EXTERNALBOOK record) */
+        private int _extBookIndex;
+        private int _firstSheetIndex; // may be -1 (0xFFFF)
+        private int _lastSheetIndex;  // may be -1 (0xFFFF)
+        
+        
+        /** a Constructor for making new sub record
+         */
+        public RefSubRecord(int extBookIndex, int firstSheetIndex, int lastSheetIndex) {
+               _extBookIndex = extBookIndex;
+               _firstSheetIndex = firstSheetIndex;
+               _lastSheetIndex = lastSheetIndex;
+        }
+        
+        /**
+         * @param in the RecordInputstream to read the record from
+         */
+        public RefSubRecord(RecordInputStream in) {
+            this(in.readShort(), in.readShort(), in.readShort());
+        }
+        public int getExtBookIndex(){
+            return _extBookIndex;
+        }
+        public int getFirstSheetIndex(){
+            return _firstSheetIndex;
+        }
+        public int getLastSheetIndex(){
+            return _lastSheetIndex;
+        }
+        
+        public String toString() {
+            StringBuffer buffer = new StringBuffer();
+            buffer.append("extBook=").append(_extBookIndex);
+            buffer.append(" firstSheet=").append(_firstSheetIndex);
+            buffer.append(" lastSheet=").append(_lastSheetIndex);
+            return buffer.toString();
+        }
+        
+        /**
+         * called by the class that is responsible for writing this sucker.
+         * Subclasses should implement this so that their data is passed back in a
+         * byte array.
+         *
+         * @param offset to begin writing at
+         * @param data byte array containing instance data
+         * @return number of bytes written
+         */
+        public void serialize(int offset, byte [] data) {
+            LittleEndian.putUShort(data, 0 + offset, _extBookIndex);
+            LittleEndian.putUShort(data, 2 + offset, _firstSheetIndex);
+            LittleEndian.putUShort(data, 4 + offset, _lastSheetIndex);
+        }
+    }    
+    
+    
     
     public ExternSheetRecord() {
-        field_2_REF_structures = new ArrayList();
+        _list = new ArrayList();
     }
     
     /**
@@ -68,72 +123,60 @@ public class ExternSheetRecord extends Record {
      * @param in the RecordInputstream to read the record from
      */
     protected void fillFields(RecordInputStream in) {
-        field_2_REF_structures           = new ArrayList();
+        _list           = new ArrayList();
         
-        field_1_number_of_REF_sturcutres = in.readShort();
+        int nItems  = in.readShort();
         
-        for (int i = 0 ; i < field_1_number_of_REF_sturcutres ; ++i) {
-            ExternSheetSubRecord rec = new ExternSheetSubRecord(in);
+        for (int i = 0 ; i < nItems ; ++i) {
+            RefSubRecord rec = new RefSubRecord(in);
             
-            field_2_REF_structures.add( rec);
+            _list.add( rec);
         }
     }
     
-    /** 
-     * sets the number of the REF structors , that is in Excel file
-     * @param numStruct number of REF structs
-     */
-    public void setNumOfREFStructures(short numStruct) {
-        field_1_number_of_REF_sturcutres = numStruct;
-    }
-    
+
     /**  
-     * return the number of the REF structors , that is in Excel file
-     * @return number of REF structs
+     * @return number of REF structures
      */
-    public short getNumOfREFStructures() {
-        return field_1_number_of_REF_sturcutres;
+    public int getNumOfRefs() {
+        return _list.size();
     }
     
     /** 
      * adds REF struct (ExternSheetSubRecord)
      * @param rec REF struct
      */
-    public void addREFRecord(ExternSheetSubRecord rec) {
-        field_2_REF_structures.add(rec);
+    public void addREFRecord(RefSubRecord rec) {
+        _list.add(rec);
     }
     
     /** returns the number of REF Records, which is in model
      * @return number of REF records
      */
     public int getNumOfREFRecords() {
-        return field_2_REF_structures.size();
+        return _list.size();
     }
     
-    /** returns the REF record (ExternSheetSubRecord)
-     * @param elem index to place
-     * @return REF record
-     */
-    public ExternSheetSubRecord getREFRecordAt(int elem) {
-        ExternSheetSubRecord result = ( ExternSheetSubRecord ) field_2_REF_structures.get(elem);
-        
-        return result;
-    }
     
     public String toString() {
-        StringBuffer buffer = new StringBuffer();
-        
-        buffer.append("[EXTERNSHEET]\n");
-        buffer.append("   numOfRefs     = ").append(getNumOfREFStructures()).append("\n");
-        for (int k=0; k < this.getNumOfREFRecords(); k++) {
-            buffer.append("refrec         #").append(k).append('\n');
-            buffer.append(getREFRecordAt(k).toString());
-            buffer.append("----refrec     #").append(k).append('\n');
+        StringBuffer sb = new StringBuffer();
+        int nItems = _list.size();
+        sb.append("[EXTERNSHEET]\n");
+        sb.append("   numOfRefs     = ").append(nItems).append("\n");
+        for (int i=0; i < nItems; i++) {
+            sb.append("refrec         #").append(i).append(": ");
+            sb.append(getRef(i).toString());
+            sb.append('\n');
         }
-        buffer.append("[/EXTERNSHEET]\n");
+        sb.append("[/EXTERNSHEET]\n");
         
         
-        return buffer.toString();
+        return sb.toString();
+    }
+    
+    
+    private int getDataSize() {
+       return 2 + _list.size() * RefSubRecord.ENCODED_SIZE;
     }
     
     /**
@@ -146,24 +189,29 @@ public class ExternSheetRecord extends Record {
      * @return number of bytes written
      */
     public int serialize(int offset, byte [] data) {
-        LittleEndian.putShort(data, 0 + offset, sid);
-        LittleEndian.putShort(data, 2 + offset,(short)(2 + (getNumOfREFRecords() *6)));
+        int dataSize = getDataSize();
         
-        LittleEndian.putShort(data, 4 + offset, getNumOfREFStructures());
+        int nItems = _list.size();
+
+        LittleEndian.putShort(data, 0 + offset, sid);
+               LittleEndian.putUShort(data, 2 + offset, dataSize);
+        LittleEndian.putUShort(data, 4 + offset, nItems);
         
         int pos = 6 ;
         
-        for (int k = 0; k < getNumOfREFRecords(); k++) {
-            ExternSheetSubRecord record = getREFRecordAt(k);
-            System.arraycopy(record.serialize(), 0, data, pos + offset, 6);
-            
+        for (int i = 0; i < nItems; i++) {
+            getRef(i).serialize(offset + pos, data);
             pos +=6;
         }
-        return getRecordSize();
+        return dataSize + 4;
     }
+
+       private RefSubRecord getRef(int i) {
+               return (RefSubRecord) _list.get(i);
+       }
     
     public int getRecordSize() {
-        return 4 + 2 + getNumOfREFRecords() * 6;
+        return 4 + getDataSize();
     }
     
     /**
@@ -172,4 +220,44 @@ public class ExternSheetRecord extends Record {
     public short getSid() {
         return sid;
     }
+
+       public int getExtbookIndexFromRefIndex(int refIndex) {
+        return getRef(refIndex).getExtBookIndex();
+       }
+
+       /**
+        * @return -1 if not found
+        */
+       public int findRefIndexFromExtBookIndex(int extBookIndex) {
+        int nItems = _list.size();
+        for (int i = 0; i < nItems; i++) {
+            if (getRef(i).getExtBookIndex() == extBookIndex) {
+               return i;
+            }
+        }
+               return -1;
+       }
+
+       public int getFirstSheetIndexFromRefIndex(int extRefIndex) {
+               return getRef(extRefIndex).getFirstSheetIndex();
+       }
+
+       /**
+        * @return index of newly added ref
+        */
+       public int addRef(int extBookIndex, int firstSheetIndex, int lastSheetIndex) {
+               _list.add(new RefSubRecord(extBookIndex, firstSheetIndex, lastSheetIndex));
+               return _list.size() - 1;
+       }
+
+       public int getRefIxForSheet(int sheetIndex) {
+        int nItems = _list.size();
+        for (int i = 0; i < nItems; i++) {
+            RefSubRecord ref = getRef(i);
+                       if (ref.getFirstSheetIndex() == sheetIndex && ref.getLastSheetIndex() == sheetIndex) {
+               return i;
+            }
+        }
+               return -1;
+       }
 }
diff --git a/src/java/org/apache/poi/hssf/record/ExternSheetSubRecord.java b/src/java/org/apache/poi/hssf/record/ExternSheetSubRecord.java
deleted file mode 100644 (file)
index 184895d..0000000
+++ /dev/null
@@ -1,154 +0,0 @@
-
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-        
-
-package org.apache.poi.hssf.record;
-
-import org.apache.poi.util.LittleEndian;
-
-/**
- * Title:        A sub Record for Extern Sheet <P>
- * Description:  Defines a named range within a workbook. <P>
- * REFERENCE:  <P>
- * @author Libin Roman (Vista Portal LDT. Developer)
- * @version 1.0-pre
- */
-
-public class ExternSheetSubRecord extends Record {
-    public final static short sid = 0xFFF; // only here for conformance, doesn't really have an sid
-    private short             field_1_index_to_supbook;
-    private short             field_2_index_to_first_supbook_sheet;
-    private short             field_3_index_to_last_supbook_sheet;
-    
-    
-    /** a Constractor for making new sub record
-     */
-    public ExternSheetSubRecord() {
-    }
-    
-    /**
-     * Constructs a Extern Sheet Sub Record record and sets its fields appropriately.
-     *
-     * @param in the RecordInputstream to read the record from
-     */
-    public ExternSheetSubRecord(RecordInputStream in) {
-        super(in);
-    }
-    
-    
-    /** Sets the Index to the sup book
-     * @param index sup book index
-     */
-    public void setIndexToSupBook(short index){
-        field_1_index_to_supbook = index;
-    }
-    
-    /** gets the index to sup book
-     * @return sup book index
-     */
-    public short getIndexToSupBook(){
-        return field_1_index_to_supbook;
-    }
-    
-    /** sets the index to first sheet in supbook
-     * @param index index to first sheet
-     */
-    public void setIndexToFirstSupBook(short index){
-        field_2_index_to_first_supbook_sheet = index;
-    }
-    
-    /** gets the index to first sheet from supbook
-     * @return index to first supbook
-     */
-    public short getIndexToFirstSupBook(){
-        return field_2_index_to_first_supbook_sheet;
-    }
-    
-    /** sets the index to last sheet in supbook
-     * @param index index to last sheet
-     */
-    public void setIndexToLastSupBook(short index){
-        field_3_index_to_last_supbook_sheet = index;
-    }
-    
-    /** gets the index to last sheet in supbook
-     * @return index to last supbook
-     */
-    public short getIndexToLastSupBook(){
-        return field_3_index_to_last_supbook_sheet;
-    }
-    
-    /**
-     * called by constructor, should throw runtime exception in the event of a
-     * record passed with a differing ID.
-     *
-     * @param id alleged id for this record
-     */
-    protected void validateSid(short id) {
-        // do nothing
-    }
-    
-    /**
-     * @param in the RecordInputstream to read the record from
-     */
-    protected void fillFields(RecordInputStream in) {
-        field_1_index_to_supbook             = in.readShort();
-        field_2_index_to_first_supbook_sheet = in.readShort();
-        field_3_index_to_last_supbook_sheet  = in.readShort();
-    }
-    
-    
-    public String toString() {
-        StringBuffer buffer = new StringBuffer();
-        buffer.append("   supbookindex =").append(getIndexToSupBook()).append('\n');
-        buffer.append("   1stsbindex   =").append(getIndexToFirstSupBook()).append('\n');
-        buffer.append("   lastsbindex  =").append(getIndexToLastSupBook()).append('\n');
-        return buffer.toString();
-    }
-    
-    /**
-     * called by the class that is responsible for writing this sucker.
-     * Subclasses should implement this so that their data is passed back in a
-     * byte array.
-     *
-     * @param offset to begin writing at
-     * @param data byte array containing instance data
-     * @return number of bytes written
-     */
-    public int serialize(int offset, byte [] data) {
-        LittleEndian.putShort(data, 0 + offset, getIndexToSupBook());
-        LittleEndian.putShort(data, 2 + offset, getIndexToFirstSupBook());
-        LittleEndian.putShort(data, 4 + offset, getIndexToLastSupBook());
-        
-        return getRecordSize();
-    }
-    
-    
-    /** returns the record size
-     */
-    public int getRecordSize() {
-        return 6;
-    }
-    
-    /**
-     * return the non static version of the id for this record.
-     */
-    public short getSid() {
-        return sid;
-    }
-}
index dbd796991c69656a525e80eebc782d3e4c00e838..6c6c53a92bd40402933ee678b28b7e736424f216 100644 (file)
@@ -34,7 +34,7 @@ import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.StringUtil;
 
 /**
- * Title:        Name Record (aka Named Range) <P>
+ * Title:        DEFINEDNAME Record (0x0018) <p/>
  * Description:  Defines a named range within a workbook. <P>
  * REFERENCE:  <P>
  * @author Libin Roman (Vista Portal LDT. Developer)
@@ -43,10 +43,7 @@ import org.apache.poi.util.StringUtil;
  * @version 1.0-pre
  */
 public final class NameRecord extends Record {
-    /**
-     */
-    public final static short sid = 0x18; //Docs says that it is 0x218
-    
+    public final static short sid = 0x0018;
        /**Included for completeness sake, not implemented
           */
        public final static byte  BUILTIN_CONSOLIDATE_AREA      = (byte)1;
@@ -91,347 +88,338 @@ public final class NameRecord extends Record {
        /**Included for completeness sake, not implemented
         */
        public final static byte  BUILTIN_SHEET_TITLE           = (byte)12;
-    
-    public static final short OPT_HIDDEN_NAME =   (short) 0x0001;
-    public static final short OPT_FUNCTION_NAME = (short) 0x0002;
-    public static final short OPT_COMMAND_NAME =  (short) 0x0004;
-    public static final short OPT_MACRO =         (short) 0x0008;
-    public static final short OPT_COMPLEX =       (short) 0x0010;
-    public static final short OPT_BUILTIN =       (short) 0x0020;
-    public static final short OPT_BINDATA =       (short) 0x1000;
-
-    
-    private short             field_1_option_flag;
-    private byte              field_2_keyboard_shortcut;
-    private byte              field_3_length_name_text;
-    private short             field_4_length_name_definition;
-    private short             field_5_index_to_sheet;     // unused: see field_6
-    private short             field_6_equals_to_index_to_sheet;
-    private byte              field_7_length_custom_menu;
-    private byte              field_8_length_description_text;
-    private byte              field_9_length_help_topic_text;
-    private byte              field_10_length_status_bar_text;
-    private byte              field_11_compressed_unicode_flag;   // not documented
-    private byte              field_12_builtIn_name;
-    private String            field_12_name_text;
-    private Stack             field_13_name_definition;
-    private String            field_14_custom_menu_text;
-    private String            field_15_description_text;
-    private String            field_16_help_topic_text;
-    private String            field_17_status_bar_text;
-
-
-    /** Creates new NameRecord */
-    public NameRecord() {
-        field_13_name_definition = new Stack();
-
-        field_12_name_text = new String();
-        field_14_custom_menu_text = new String();
-        field_15_description_text = new String();
-        field_16_help_topic_text = new String();
-        field_17_status_bar_text = new String();
-    }
-
-    /**
-     * Constructs a Name record and sets its fields appropriately.
-     *
-     * @param in the RecordInputstream to read the record from
-     */
-    public NameRecord(RecordInputStream in) {
-        super(in);
-    }
+       
+       private static final class Option {
+               public static final int OPT_HIDDEN_NAME =   0x0001;
+               public static final int OPT_FUNCTION_NAME = 0x0002;
+               public static final int OPT_COMMAND_NAME =  0x0004;
+               public static final int OPT_MACRO =         0x0008;
+               public static final int OPT_COMPLEX =       0x0010;
+               public static final int OPT_BUILTIN =       0x0020;
+               public static final int OPT_BINDATA =       0x1000;
+       }
+       
+       private short             field_1_option_flag;
+       private byte              field_2_keyboard_shortcut;
+       private byte              field_3_length_name_text;
+       private short             field_4_length_name_definition;
+       private short             field_5_index_to_sheet;     // unused: see field_6
+       /** the one based sheet number.  Zero if this is a global name */
+       private int               field_6_sheetNumber;
+       private byte              field_7_length_custom_menu;
+       private byte              field_8_length_description_text;
+       private byte              field_9_length_help_topic_text;
+       private byte              field_10_length_status_bar_text;
+       private byte              field_11_compressed_unicode_flag;   // not documented
+       private byte              field_12_builtIn_name;
+       private String            field_12_name_text;
+       private Stack             field_13_name_definition;
+       private String            field_14_custom_menu_text;
+       private String            field_15_description_text;
+       private String            field_16_help_topic_text;
+       private String            field_17_status_bar_text;
+
+
+       /** Creates new NameRecord */
+       public NameRecord() {
+               field_13_name_definition = new Stack();
+
+               field_12_name_text = new String();
+               field_14_custom_menu_text = new String();
+               field_15_description_text = new String();
+               field_16_help_topic_text = new String();
+               field_17_status_bar_text = new String();
+       }
+
+       /**
+        * Constructs a Name record and sets its fields appropriately.
+        *
+        * @param in the RecordInputstream to read the record from
+        */
+       public NameRecord(RecordInputStream in) {
+               super(in);
+       }
 
        /**
         * Constructor to create a built-in named region
         * @param builtin Built-in byte representation for the name record, use the public constants
-        * @param index 
         */
-       public NameRecord(byte builtin, short index)
+       public NameRecord(byte builtin, int sheetNumber)
        {
-           this();         
-           this.field_12_builtIn_name = builtin;
-           this.setOptionFlag((short)(this.getOptionFlag() | OPT_BUILTIN));
-           this.setNameTextLength((byte)1);
-           this.setEqualsToIndexToSheet(index); //the extern sheets are set through references
-           
-           //clearing these because they are not used with builtin records
+               this();         
+               this.field_12_builtIn_name = builtin;
+               this.setOptionFlag((short)(this.field_1_option_flag | Option.OPT_BUILTIN));
+               this.setNameTextLength((byte)1);
+               field_6_sheetNumber = sheetNumber; //the extern sheets are set through references
+               
+               //clearing these because they are not used with builtin records
                this.setCustomMenuLength((byte)0);
                this.setDescriptionTextLength((byte)0);
                this.setHelpTopicLength((byte)0);
                this.setStatusBarLength((byte)0);
 
-           
-       }
-
-    /** sets the option flag for the named range
-     * @param flag option flag
-     */
-    public void setOptionFlag(short flag){
-        field_1_option_flag = flag;
-    }
-
-
-    /** sets the keyboard shortcut
-     * @param shortcut keyboard shortcut
-     */
-    public void setKeyboardShortcut(byte shortcut){
-        field_2_keyboard_shortcut = shortcut;
-    }
-
-    /** sets the name of the named range length
-     * @param length name length
-     */
-    public void setNameTextLength(byte length){
-        field_3_length_name_text = length;
-    }
-
-    /** sets the definition (reference - formula) length
-     * @param length defenition length
-     */
-    public void setDefinitionTextLength(short length){
-        field_4_length_name_definition = length;
-    }
-
-    /** sets the index number to the extern sheet (thats is what writen in documentation
-     *  but as i saw , it works differently)
-     * @param index extern sheet index
-     */
-    public void setUnused(short index){
-        field_5_index_to_sheet = index;
-
-        // field_6_equals_to_index_to_sheet is equal to field_5_index_to_sheet
+               
+       }
+
+       /** sets the option flag for the named range
+        * @param flag option flag
+        */
+       public void setOptionFlag(short flag){
+               field_1_option_flag = flag;
+       }
+
+
+       /** sets the keyboard shortcut
+        * @param shortcut keyboard shortcut
+        */
+       public void setKeyboardShortcut(byte shortcut){
+               field_2_keyboard_shortcut = shortcut;
+       }
+
+       /** sets the name of the named range length
+        * @param length name length
+        */
+       public void setNameTextLength(byte length){
+               field_3_length_name_text = length;
+       }
+
+       /** sets the definition (reference - formula) length
+        * @param length defenition length
+        */
+       public void setDefinitionTextLength(short length){
+               field_4_length_name_definition = length;
+       }
+
+       /** sets the index number to the extern sheet (thats is what writen in documentation
+        *  but as i saw , it works differently)
+        * @param index extern sheet index
+        */
+       public void setUnused(short index){
+               field_5_index_to_sheet = index;
+
+               // field_6_equals_to_index_to_sheet is equal to field_5_index_to_sheet
 //        field_6_equals_to_index_to_sheet = index;
-    }
+       }
 
-    public short getEqualsToIndexToSheet()
-    {
-        return field_6_equals_to_index_to_sheet;
-    }
+       /**
+        * For named ranges, and built-in names
+        * @return the 1-based sheet number.  Zero if this is a global name 
+        */
+       public int getSheetNumber()
+       {
+               return field_6_sheetNumber;
+       }
 
        /**
-        * Convenience method to retrieve the index the name refers to.
-        * @see #getEqualsToIndexToSheet()
-        * @return short
-        */
-       public short getIndexToSheet() {
-               return getEqualsToIndexToSheet();
-       }
-
-    /**
-     * @return function group
-     * @see FnGroupCountRecord
-     */
-    public byte getFnGroup() {
-        int masked = field_1_option_flag & 0x0fc0;
-        return (byte) (masked >> 4);
-    }
-
-    public void setEqualsToIndexToSheet(short value)
-    {
-        field_6_equals_to_index_to_sheet = value;
-    }
-
-
-    /** sets the custom menu length
-     * @param length custom menu length
-     */
-    public void setCustomMenuLength(byte length){
-        field_7_length_custom_menu = length;
-    }
-
-    /** sets the length of named range description
-     * @param length description length
-     */
-    public void setDescriptionTextLength(byte length){
-        field_8_length_description_text = length;
-    }
-
-    /** sets the help topic length
-     * @param length help topic length
-     */
-    public void setHelpTopicLength(byte length){
-        field_9_length_help_topic_text = length;
-    }
-
-    /** sets the length of the status bar text
-     * @param length status bar text length
-     */
-    public void setStatusBarLength(byte length){
-        field_10_length_status_bar_text = length;
-    }
-
-    /** sets the compressed unicode flag
-     * @param flag unicode flag
-     */
-    public void setCompressedUnicodeFlag(byte flag) {
-        field_11_compressed_unicode_flag = flag;
-    }
-
-    /** sets the name of the named range
-     * @param name named range name
-     */
-    public void setNameText(String name){
-        field_12_name_text = name;
-        setCompressedUnicodeFlag(
-               StringUtil.hasMultibyte(name) ? (byte)1 : (byte)0
-        );
-    }
-
-    //    public void setNameDefintion(String definition){
-    //        test = definition;
-    //    }
-
-    /** sets the custom menu text
-     * @param text custom menu text
-     */
-    public void setCustomMenuText(String text){
-        field_14_custom_menu_text = text;
-    }
-
-    /** sets the description text
-     * @param text the description text
-     */
-    public void setDescriptionText(String text){
-        field_15_description_text = text;
-    }
-
-    /** sets the help topic text
-     * @param text help topix text
-     */
-    public void setHelpTopicText(String text){
-        field_16_help_topic_text = text;
-    }
-
-    /** sets the status bar text
-     * @param text status bar text
-     */
-    public void setStatusBarText(String text){
-        field_17_status_bar_text = text;
-    }
-
-    /** gets the option flag
-     * @return option flag
-     */
-    public short getOptionFlag(){
-        return field_1_option_flag;
-    }
-
-    /** returns the keyboard shortcut
-     * @return keyboard shortcut
-     */
-    public byte getKeyboardShortcut(){
-        return field_2_keyboard_shortcut ;
-    }
-
-    /** 
-     * gets the name length, in characters
-     * @return name length
-     */
-    public byte getNameTextLength(){
-        return field_3_length_name_text;
-    }
-    
-    /** 
-     * gets the name length, in bytes
-     * @return raw name length
-     */
-    public byte getRawNameTextLength(){
-       if( (field_11_compressed_unicode_flag & 0x01) == 1 ) {
-               return (byte)(2 * field_3_length_name_text);
-       }
-       return field_3_length_name_text;
-    }
-
-    /** get the definition length
-     * @return definition length
-     */
-    public short getDefinitionLength(){
-        return field_4_length_name_definition;
-    }
-
-    /** gets the index to extern sheet
-     * @return index to extern sheet
-     */
-    public short getUnused(){
-        return field_5_index_to_sheet;
-    }
-
-    /** gets the custom menu length
-     * @return custom menu length
-     */
-    public byte getCustomMenuLength(){
-        return field_7_length_custom_menu;
-    }
-
-    /** gets the description text length
-     * @return description text length
-     */
-    public byte getDescriptionTextLength(){
-        return field_8_length_description_text;
-    }
-
-    /** gets the help topic length
-     * @return help topic length
-     */
-    public byte getHelpTopicLength(){
-        return field_9_length_help_topic_text;
-    }
-
-    /** get the status bar text length
-     * @return satus bar length
-     */
-    public byte getStatusBarLength(){
-        return field_10_length_status_bar_text;
-    }
-
-    /** gets the name compressed Unicode flag
-     * @return compressed unicode flag
-     */
-    public byte getCompressedUnicodeFlag() {
-        return field_11_compressed_unicode_flag;
-    }
-
-    /**
-     * @return true if name is hidden
-     */
-    public boolean isHiddenName() {
-        return (field_1_option_flag & OPT_HIDDEN_NAME) != 0;
-    }
-
-    /**
-     * @return true if name is a function
-     */
-    public boolean isFunctionName() {
-        return (field_1_option_flag & OPT_FUNCTION_NAME) != 0;
-    }
-
-    /**
-     * @return true if name is a command
-     */
-    public boolean isCommandName() {
-        return (field_1_option_flag & OPT_COMMAND_NAME) != 0;
-    }
-
-    /**
-     * @return true if function macro or command macro
-     */
-    public boolean isMacro() {
-        return (field_1_option_flag & OPT_MACRO) != 0;
-    }
-
-    /**
-     * @return true if array formula or user defined
-     */
-    public boolean isComplexFunction() {
-        return (field_1_option_flag & OPT_COMPLEX) != 0;
-    }
+        * @return function group
+        * @see FnGroupCountRecord
+        */
+       public byte getFnGroup() {
+               int masked = field_1_option_flag & 0x0fc0;
+               return (byte) (masked >> 4);
+       }
+
 
+       public void setSheetNumber(int value)
+       {
+               field_6_sheetNumber = value;
+       }
+
+
+       /** sets the custom menu length
+        * @param length custom menu length
+        */
+       public void setCustomMenuLength(byte length){
+               field_7_length_custom_menu = length;
+       }
+
+       /** sets the length of named range description
+        * @param length description length
+        */
+       public void setDescriptionTextLength(byte length){
+               field_8_length_description_text = length;
+       }
+
+       /** sets the help topic length
+        * @param length help topic length
+        */
+       public void setHelpTopicLength(byte length){
+               field_9_length_help_topic_text = length;
+       }
+
+       /** sets the length of the status bar text
+        * @param length status bar text length
+        */
+       public void setStatusBarLength(byte length){
+               field_10_length_status_bar_text = length;
+       }
+
+       /** sets the compressed unicode flag
+        * @param flag unicode flag
+        */
+       public void setCompressedUnicodeFlag(byte flag) {
+               field_11_compressed_unicode_flag = flag;
+       }
+
+       /** sets the name of the named range
+        * @param name named range name
+        */
+       public void setNameText(String name){
+               field_12_name_text = name;
+               setCompressedUnicodeFlag(
+                       StringUtil.hasMultibyte(name) ? (byte)1 : (byte)0
+               );
+       }
+
+       /** sets the custom menu text
+        * @param text custom menu text
+        */
+       public void setCustomMenuText(String text){
+               field_14_custom_menu_text = text;
+       }
+
+       /** sets the description text
+        * @param text the description text
+        */
+       public void setDescriptionText(String text){
+               field_15_description_text = text;
+       }
+
+       /** sets the help topic text
+        * @param text help topix text
+        */
+       public void setHelpTopicText(String text){
+               field_16_help_topic_text = text;
+       }
+
+       /** sets the status bar text
+        * @param text status bar text
+        */
+       public void setStatusBarText(String text){
+               field_17_status_bar_text = text;
+       }
+
+       /** gets the option flag
+        * @return option flag
+        */
+       public short getOptionFlag(){
+               return field_1_option_flag;
+       }
+
+       /** returns the keyboard shortcut
+        * @return keyboard shortcut
+        */
+       public byte getKeyboardShortcut(){
+               return field_2_keyboard_shortcut ;
+       }
+
+       /** 
+        * gets the name length, in characters
+        * @return name length
+        */
+       public byte getNameTextLength(){
+               return field_3_length_name_text;
+       }
+       
+       /** 
+        * gets the name length, in bytes
+        * @return raw name length
+        */
+       public byte getRawNameTextLength(){
+               if( (field_11_compressed_unicode_flag & 0x01) == 1 ) {
+                       return (byte)(2 * field_3_length_name_text);
+               }
+               return field_3_length_name_text;
+       }
+
+       /** get the definition length
+        * @return definition length
+        */
+       public short getDefinitionLength(){
+               return field_4_length_name_definition;
+       }
+
+       /** gets the index to extern sheet
+        * @return index to extern sheet
+        */
+       public short getUnused(){
+               return field_5_index_to_sheet;
+       }
+
+       /** gets the custom menu length
+        * @return custom menu length
+        */
+       public byte getCustomMenuLength(){
+               return field_7_length_custom_menu;
+       }
+
+       /** gets the description text length
+        * @return description text length
+        */
+       public byte getDescriptionTextLength(){
+               return field_8_length_description_text;
+       }
+
+       /** gets the help topic length
+        * @return help topic length
+        */
+       public byte getHelpTopicLength(){
+               return field_9_length_help_topic_text;
+       }
+
+       /** get the status bar text length
+        * @return satus bar length
+        */
+       public byte getStatusBarLength(){
+               return field_10_length_status_bar_text;
+       }
+
+       /** gets the name compressed Unicode flag
+        * @return compressed unicode flag
+        */
+       public byte getCompressedUnicodeFlag() {
+               return field_11_compressed_unicode_flag;
+       }
+
+
+       /**
+        * @return true if name is hidden
+        */
+       public boolean isHiddenName() {
+               return (field_1_option_flag & Option.OPT_HIDDEN_NAME) != 0;
+       }
+       /**
+        * @return true if name is a function
+        */
+       public boolean isFunctionName() {
+               return (field_1_option_flag & Option.OPT_FUNCTION_NAME) != 0;
+       }
+
+
+       /**
+        * @return true if name is a command
+        */
+       public boolean isCommandName() {
+               return (field_1_option_flag & Option.OPT_COMMAND_NAME) != 0;
+       }
+       /**
+        * @return true if function macro or command macro
+        */
+       public boolean isMacro() {
+               return (field_1_option_flag & Option.OPT_MACRO) != 0;
+       }
+       /**
+        * @return true if array formula or user defined
+        */
+       public boolean isComplexFunction() {
+               return (field_1_option_flag & Option.OPT_COMPLEX) != 0;
+       }
 
        /**Convenience Function to determine if the name is a built-in name
         */
        public boolean isBuiltInName()
        {
-           return ((this.getOptionFlag() & OPT_BUILTIN) != 0);
+               return ((this.field_1_option_flag & Option.OPT_BUILTIN) != 0);
        }
 
 
@@ -440,7 +428,7 @@ public final class NameRecord extends Record {
         */
        public String getNameText(){
 
-       return this.isBuiltInName() ? this.translateBuiltInName(this.getBuiltInName()) : field_12_name_text;
+               return this.isBuiltInName() ? this.translateBuiltInName(this.getBuiltInName()) : field_12_name_text;
        }
 
        /** Gets the Built In Name
@@ -448,85 +436,85 @@ public final class NameRecord extends Record {
         */
        public byte getBuiltInName()
        {
-           return this.field_12_builtIn_name;
-       }
-
-
-    /** gets the definition, reference (Formula)
-     * @return definition -- can be null if we cant parse ptgs
-     */
-    public List getNameDefinition() {
-        return field_13_name_definition;
-    }
-
-    public void setNameDefinition(Stack nameDefinition) {
-        field_13_name_definition = nameDefinition;
-    }
-
-    /** get the custom menu text
-     * @return custom menu text
-     */
-    public String getCustomMenuText(){
-        return field_14_custom_menu_text;
-    }
-
-    /** gets the description text
-     * @return description text
-     */
-    public String getDescriptionText(){
-        return field_15_description_text;
-    }
-
-    /** get the help topic text
-     * @return gelp topic text
-     */
-    public String getHelpTopicText(){
-        return field_16_help_topic_text;
-    }
-
-    /** gets the status bar text
-     * @return status bar text
-     */
-    public String getStatusBarText(){
-        return field_17_status_bar_text;
-    }
-
-    /**
-     * called by constructor, should throw runtime exception in the event of a
-     * record passed with a differing ID.
-     *
-     * @param id alleged id for this record
-     */
-    protected void validateSid(short id) {
-        if (id != sid) {
-            throw new RecordFormatException("NOT A valid Name RECORD");
-        }
-    }
-    
-    /**
-     * called by the class that is responsible for writing this sucker.
-     * Subclasses should implement this so that their data is passed back in a
+               return this.field_12_builtIn_name;
+       }
+
+
+       /** gets the definition, reference (Formula)
+        * @return definition -- can be null if we cant parse ptgs
+        */
+       public List getNameDefinition() {
+               return field_13_name_definition;
+       }
+
+       public void setNameDefinition(Stack nameDefinition) {
+               field_13_name_definition = nameDefinition;
+       }
+
+       /** get the custom menu text
+        * @return custom menu text
+        */
+       public String getCustomMenuText(){
+               return field_14_custom_menu_text;
+       }
+
+       /** gets the description text
+        * @return description text
+        */
+       public String getDescriptionText(){
+               return field_15_description_text;
+       }
+
+       /** get the help topic text
+        * @return gelp topic text
+        */
+       public String getHelpTopicText(){
+               return field_16_help_topic_text;
+       }
+
+       /** gets the status bar text
+        * @return status bar text
+        */
+       public String getStatusBarText(){
+               return field_17_status_bar_text;
+       }
+
+       /**
+        * called by constructor, should throw runtime exception in the event of a
+        * record passed with a differing ID.
+        *
+        * @param id alleged id for this record
+        */
+       protected void validateSid(short id) {
+               if (id != sid) {
+                       throw new RecordFormatException("NOT A valid Name RECORD");
+               }
+       }
+       
+       /**
+        * called by the class that is responsible for writing this sucker.
+        * Subclasses should implement this so that their data is passed back in a
         * @param offset to begin writing at
         * @param data byte array containing instance data
-     * @return number of bytes written
-     */
-    public int serialize( int offset, byte[] data )
-    {
-        LittleEndian.putShort( data, 0 + offset, sid );
-        short size = (short)( 15 + getTextsLength() + getNameDefinitionSize());
-        LittleEndian.putShort( data, 2 + offset, size );
-        // size defined below
-        LittleEndian.putShort( data, 4 + offset, getOptionFlag() );
-        data[6 + offset] = getKeyboardShortcut();
-        data[7 + offset] = getNameTextLength();
-        LittleEndian.putShort( data, 8 + offset, getDefinitionLength() );
-        LittleEndian.putShort( data, 10 + offset, getUnused() );
-        LittleEndian.putShort( data, 12 + offset, getEqualsToIndexToSheet() );
-        data[14 + offset] = getCustomMenuLength();
-        data[15 + offset] = getDescriptionTextLength();
-        data[16 + offset] = getHelpTopicLength();
-        data[17 + offset] = getStatusBarLength();
-        data[18 + offset] = getCompressedUnicodeFlag();
+        * @return number of bytes written
+        */
+       public int serialize( int offset, byte[] data )
+       {
+               LittleEndian.putShort( data, 0 + offset, sid );
+               short size = (short)( 15 + getTextsLength() + getNameDefinitionSize());
+               LittleEndian.putShort( data, 2 + offset, size );
+               // size defined below
+               LittleEndian.putShort( data, 4 + offset, getOptionFlag() );
+               data[6 + offset] = getKeyboardShortcut();
+               data[7 + offset] = getNameTextLength();
+               LittleEndian.putShort( data, 8 + offset, getDefinitionLength() );
+               LittleEndian.putShort( data, 10 + offset, getUnused() );
+               LittleEndian.putUShort( data, 12 + offset, field_6_sheetNumber);
+               data[14 + offset] = getCustomMenuLength();
+               data[15 + offset] = getDescriptionTextLength();
+               data[16 + offset] = getHelpTopicLength();
+               data[17 + offset] = getStatusBarLength();
+               data[18 + offset] = getCompressedUnicodeFlag();
 
                        int start_of_name_definition = 19 + field_3_length_name_text;
 
@@ -544,343 +532,343 @@ public final class NameRecord extends Record {
                        Ptg.serializePtgStack(field_13_name_definition,  data, start_of_name_definition + offset );
 
 
-            int start_of_custom_menu_text = start_of_name_definition + field_4_length_name_definition;
-            StringUtil.putCompressedUnicode( getCustomMenuText(), data, start_of_custom_menu_text + offset );
-
-            int start_of_description_text = start_of_custom_menu_text + field_7_length_custom_menu;
-            StringUtil.putCompressedUnicode( getDescriptionText(), data, start_of_description_text + offset );
-
-            int start_of_help_topic_text = start_of_description_text + field_8_length_description_text;
-            StringUtil.putCompressedUnicode( getHelpTopicText(), data, start_of_help_topic_text + offset );
-
-            int start_of_status_bar_text = start_of_help_topic_text + field_9_length_help_topic_text;
-            StringUtil.putCompressedUnicode( getStatusBarText(), data, start_of_status_bar_text + offset );
-
-            return getRecordSize();
-        /* } */
-    }
-
-    /** 
-     * Gets the length of all texts, in bytes
-     * @return total length
-     */
-    public int getTextsLength(){
-        int result;
-
-        result = getRawNameTextLength() + getDescriptionTextLength() +
-               getHelpTopicLength() + getStatusBarLength();
-
-        return result;
-    }
-    
-    private int getNameDefinitionSize() {
-       int result = 0;
-        List list   = field_13_name_definition;
-        
-        for (int k = 0; k < list.size(); k++)
-        {
-               Ptg ptg = ( Ptg ) list.get(k);
-               
-               result += ptg.getSize();
-        }
-        return result;    
-    }
-
-    /** returns the record size
-     */
-    public int getRecordSize(){
-        int result;
-
-        result = 19 + getTextsLength() + getNameDefinitionSize();
-        
-
-        return result;
-    }
-
-    /** gets the extern sheet number
-     * @return extern sheet index
-     */
-    public short getExternSheetNumber(){
-        if (field_13_name_definition == null || field_13_name_definition.isEmpty()) return 0;
-        Ptg ptg = (Ptg) field_13_name_definition.peek();
-        short result = 0;
-
-        if (ptg.getClass() == Area3DPtg.class){
-            result = ((Area3DPtg) ptg).getExternSheetIndex();
-
-        } else if (ptg.getClass() == Ref3DPtg.class){
-            result = ((Ref3DPtg) ptg).getExternSheetIndex();
-        }
-
-        return result;
-    }
-
-    /** sets the extern sheet number
-     * @param externSheetNumber extern sheet number
-     */
-    public void setExternSheetNumber(short externSheetNumber){
-        Ptg ptg;
-
-        if (field_13_name_definition == null || field_13_name_definition.isEmpty()){
-            field_13_name_definition = new Stack();
-            ptg = createNewPtg();
-        } else {
-            ptg = (Ptg) field_13_name_definition.peek();
-        }
-
-        if (ptg.getClass() == Area3DPtg.class){
-            ((Area3DPtg) ptg).setExternSheetIndex(externSheetNumber);
-
-        } else if (ptg.getClass() == Ref3DPtg.class){
-            ((Ref3DPtg) ptg).setExternSheetIndex(externSheetNumber);
-        }
-
-    }
-
-    private Ptg createNewPtg(){
-        Ptg ptg = new Area3DPtg();
-        field_13_name_definition.push(ptg);
-
-        return ptg;
-    }
-
-    /** gets the reference , the area only (range)
-     * @return area reference
-     */
+                       int start_of_custom_menu_text = start_of_name_definition + field_4_length_name_definition;
+                       StringUtil.putCompressedUnicode( getCustomMenuText(), data, start_of_custom_menu_text + offset );
+
+                       int start_of_description_text = start_of_custom_menu_text + field_7_length_custom_menu;
+                       StringUtil.putCompressedUnicode( getDescriptionText(), data, start_of_description_text + offset );
+
+                       int start_of_help_topic_text = start_of_description_text + field_8_length_description_text;
+                       StringUtil.putCompressedUnicode( getHelpTopicText(), data, start_of_help_topic_text + offset );
+
+                       int start_of_status_bar_text = start_of_help_topic_text + field_9_length_help_topic_text;
+                       StringUtil.putCompressedUnicode( getStatusBarText(), data, start_of_status_bar_text + offset );
+
+                       return getRecordSize();
+               /* } */
+       }
+
+       /** 
+        * Gets the length of all texts, in bytes
+        * @return total length
+        */
+       public int getTextsLength(){
+               int result;
+
+               result = getRawNameTextLength() + getDescriptionTextLength() +
+                       getHelpTopicLength() + getStatusBarLength();
+
+               return result;
+       }
+       
+       private int getNameDefinitionSize() {
+               int result = 0;
+               List list   = field_13_name_definition;
+               
+               for (int k = 0; k < list.size(); k++)
+               {
+                       Ptg ptg = ( Ptg ) list.get(k);
+                       
+                       result += ptg.getSize();
+               }
+               return result;    
+       }
+
+       /** returns the record size
+        */
+       public int getRecordSize(){
+               int result;
+
+               result = 19 + getTextsLength() + getNameDefinitionSize();
+               
+
+               return result;
+       }
+
+       /** gets the extern sheet number
+        * @return extern sheet index
+        */
+       public short getExternSheetNumber(){
+               if (field_13_name_definition == null || field_13_name_definition.isEmpty()) return 0;
+               Ptg ptg = (Ptg) field_13_name_definition.peek();
+               short result = 0;
+
+               if (ptg.getClass() == Area3DPtg.class){
+                       result = ((Area3DPtg) ptg).getExternSheetIndex();
+
+               } else if (ptg.getClass() == Ref3DPtg.class){
+                       result = ((Ref3DPtg) ptg).getExternSheetIndex();
+               }
+
+               return result;
+       }
+
+       /** sets the extern sheet number
+        * @param externSheetNumber extern sheet number
+        */
+       public void setExternSheetNumber(short externSheetNumber){
+               Ptg ptg;
+
+               if (field_13_name_definition == null || field_13_name_definition.isEmpty()){
+                       field_13_name_definition = new Stack();
+                       ptg = createNewPtg();
+               } else {
+                       ptg = (Ptg) field_13_name_definition.peek();
+               }
+
+               if (ptg.getClass() == Area3DPtg.class){
+                       ((Area3DPtg) ptg).setExternSheetIndex(externSheetNumber);
+
+               } else if (ptg.getClass() == Ref3DPtg.class){
+                       ((Ref3DPtg) ptg).setExternSheetIndex(externSheetNumber);
+               }
+
+       }
+
+       private Ptg createNewPtg(){
+               Ptg ptg = new Area3DPtg();
+               field_13_name_definition.push(ptg);
+
+               return ptg;
+       }
+
+       /** gets the reference , the area only (range)
+        * @return area reference
+        */
        public String getAreaReference(HSSFWorkbook book){
                return FormulaParser.toFormulaString(book, field_13_name_definition);
        }
 
-    /** sets the reference , the area only (range)
-     * @param ref area reference
-     */
-    public void setAreaReference(String ref){
-        //Trying to find if what ptg do we need
-        RangeAddress ra = new RangeAddress(ref);
-        Ptg oldPtg;
-        Ptg ptg;
-
-        if (field_13_name_definition==null ||field_13_name_definition.isEmpty()){
-            field_13_name_definition = new Stack();
-            oldPtg = createNewPtg();
-        } else {
-            //Trying to find extern sheet index
-            oldPtg = (Ptg) field_13_name_definition.pop();
-        }
-
-        short externSheetIndex = 0;
-
-        if (oldPtg.getClass() == Area3DPtg.class){
-            externSheetIndex =  ((Area3DPtg) oldPtg).getExternSheetIndex();
-
-        } else if (oldPtg.getClass() == Ref3DPtg.class){
-            externSheetIndex =  ((Ref3DPtg) oldPtg).getExternSheetIndex();
-        }
-
-        if (ra.hasRange()) {
-               // Is it contiguous or not?
-               AreaReference[] refs = 
-                       AreaReference.generateContiguous(ref);
-            this.setDefinitionTextLength((short)0);
-
-            // 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());
-                   field_13_name_definition.push(ptg);
-                   this.setDefinitionTextLength( (short)(getDefinitionLength() + ptg.getSize()) );
-               }
-               // And then a union if we had more than one area
-               if(refs.length > 1) {
-                       ptg = UnionPtg.instance;
-                field_13_name_definition.push(ptg);
-                   this.setDefinitionTextLength( (short)(getDefinitionLength() + ptg.getSize()) );
-               }
-        } else {
-            ptg = new Ref3DPtg();
-            ((Ref3DPtg) ptg).setExternSheetIndex(externSheetIndex);
-            ((Ref3DPtg) ptg).setArea(ref);
-            field_13_name_definition.push(ptg);
-            this.setDefinitionTextLength((short)ptg.getSize());
-        }
-    }
-
-    /**
-     * called by the constructor, should set class level fields.  Should throw
-     * runtime exception for bad/icomplete data.
-     *
-     * @param in the RecordInputstream to read the record from
-     */
-    protected void fillFields(RecordInputStream in) {
-        field_1_option_flag             = in.readShort();
-        field_2_keyboard_shortcut       = in.readByte();
-        field_3_length_name_text        = in.readByte();
-        field_4_length_name_definition  = in.readShort();
-        field_5_index_to_sheet          = in.readShort();
-        field_6_equals_to_index_to_sheet= in.readShort();
-        field_7_length_custom_menu      = in.readByte();
-        field_8_length_description_text = in.readByte();
-        field_9_length_help_topic_text  = in.readByte();
-        field_10_length_status_bar_text = in.readByte();
-            
-        //store the name in byte form if it's a builtin name
-        field_11_compressed_unicode_flag= in.readByte();        
-        if (this.isBuiltInName()) {
-           field_12_builtIn_name = in.readByte();
-        } else {                
-           if (field_11_compressed_unicode_flag == 1) {
-             field_12_name_text = in.readUnicodeLEString(field_3_length_name_text);
-           } else {
-             field_12_name_text = in.readCompressedUnicode(field_3_length_name_text);
-           }
-        }
-            
-        field_13_name_definition = Ptg.createParsedExpressionTokens(field_4_length_name_definition, in);
-    
-        //Who says that this can only ever be compressed unicode???
-        field_14_custom_menu_text       = in.readCompressedUnicode(LittleEndian.ubyteToInt(field_7_length_custom_menu));
-    
-        field_15_description_text       = in.readCompressedUnicode(LittleEndian.ubyteToInt(field_8_length_description_text));
-    
-        field_16_help_topic_text        = in.readCompressedUnicode(LittleEndian.ubyteToInt(field_9_length_help_topic_text));
-    
-        field_17_status_bar_text        = in.readCompressedUnicode(LittleEndian.ubyteToInt(field_10_length_status_bar_text));
-        /*} */
-    }
-
-    /**
-     * return the non static version of the id for this record.
-     */
-    public short getSid() {
-        return sid;
-    }
-    /*
-      20 00 
-      00 
-      01 
-      1A 00 // sz = 0x1A = 26
-      00 00 
-      01 00 
-      00 
-      00 
-      00 
-      00 
-      00 // unicode flag
-      07 // name
-      
-      29 17 00 3B 00 00 00 00 FF FF 00 00 02 00 3B 00 //{ 26
-      00 07 00 07 00 00 00 FF 00 10                   //  }
-      
-      
-      
-      20 00 
-      00 
-      01 
-      0B 00 // sz = 0xB = 11
-      00 00 
-      01 00 
-      00 
-      00 
-      00 
-      00 
-      00 // unicode flag
-      07 // name
-      
-      3B 00 00 07 00 07 00 00 00 FF 00   // { 11 }
+       /** sets the reference , the area only (range)
+        * @param ref area reference
+        */
+       public void setAreaReference(String ref){
+               //Trying to find if what ptg do we need
+               RangeAddress ra = new RangeAddress(ref);
+               Ptg oldPtg;
+               Ptg ptg;
+
+               if (field_13_name_definition==null ||field_13_name_definition.isEmpty()){
+                       field_13_name_definition = new Stack();
+                       oldPtg = createNewPtg();
+               } else {
+                       //Trying to find extern sheet index
+                       oldPtg = (Ptg) field_13_name_definition.pop();
+               }
+
+               short externSheetIndex = 0;
+
+               if (oldPtg.getClass() == Area3DPtg.class){
+                       externSheetIndex =  ((Area3DPtg) oldPtg).getExternSheetIndex();
+
+               } else if (oldPtg.getClass() == Ref3DPtg.class){
+                       externSheetIndex =  ((Ref3DPtg) oldPtg).getExternSheetIndex();
+               }
+
+               if (ra.hasRange()) {
+                       // Is it contiguous or not?
+                       AreaReference[] refs = 
+                               AreaReference.generateContiguous(ref);
+                       this.setDefinitionTextLength((short)0);
+
+                       // 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());
+                               field_13_name_definition.push(ptg);
+                               this.setDefinitionTextLength( (short)(getDefinitionLength() + ptg.getSize()) );
+                       }
+                       // And then a union if we had more than one area
+                       if(refs.length > 1) {
+                               ptg = UnionPtg.instance;
+                               field_13_name_definition.push(ptg);
+                               this.setDefinitionTextLength( (short)(getDefinitionLength() + ptg.getSize()) );
+                       }
+               } else {
+                       ptg = new Ref3DPtg();
+                       ((Ref3DPtg) ptg).setExternSheetIndex(externSheetIndex);
+                       ((Ref3DPtg) ptg).setArea(ref);
+                       field_13_name_definition.push(ptg);
+                       this.setDefinitionTextLength((short)ptg.getSize());
+               }
+       }
+
+       /**
+        * called by the constructor, should set class level fields.  Should throw
+        * runtime exception for bad/icomplete data.
+        *
+        * @param in the RecordInputstream to read the record from
+        */
+       protected void fillFields(RecordInputStream in) {
+               field_1_option_flag             = in.readShort();
+               field_2_keyboard_shortcut       = in.readByte();
+               field_3_length_name_text        = in.readByte();
+               field_4_length_name_definition  = in.readShort();
+               field_5_index_to_sheet          = in.readShort();
+               field_6_sheetNumber = in.readUShort();
+               field_7_length_custom_menu      = in.readByte();
+               field_8_length_description_text = in.readByte();
+               field_9_length_help_topic_text  = in.readByte();
+               field_10_length_status_bar_text = in.readByte();
+                       
+               //store the name in byte form if it's a builtin name
+               field_11_compressed_unicode_flag= in.readByte();        
+               if (this.isBuiltInName()) {
+                  field_12_builtIn_name = in.readByte();
+               } else {                
+                  if (field_11_compressed_unicode_flag == 1) {
+                        field_12_name_text = in.readUnicodeLEString(field_3_length_name_text);
+                  } else {
+                        field_12_name_text = in.readCompressedUnicode(field_3_length_name_text);
+                  }
+               }
+                       
+               field_13_name_definition = Ptg.createParsedExpressionTokens(field_4_length_name_definition, in);
+       
+               //Who says that this can only ever be compressed unicode???
+               field_14_custom_menu_text       = in.readCompressedUnicode(LittleEndian.ubyteToInt(field_7_length_custom_menu));
+       
+               field_15_description_text       = in.readCompressedUnicode(LittleEndian.ubyteToInt(field_8_length_description_text));
+       
+               field_16_help_topic_text        = in.readCompressedUnicode(LittleEndian.ubyteToInt(field_9_length_help_topic_text));
+       
+               field_17_status_bar_text        = in.readCompressedUnicode(LittleEndian.ubyteToInt(field_10_length_status_bar_text));
+               /*} */
+       }
+
+       /**
+        * return the non static version of the id for this record.
+        */
+       public short getSid() {
+               return sid;
+       }
+       /*
+         20 00 
+         00 
+         01 
+         1A 00 // sz = 0x1A = 26
+         00 00 
+         01 00 
+         00 
+         00 
+         00 
+         00 
+         00 // unicode flag
+         07 // name
+         
+         29 17 00 3B 00 00 00 00 FF FF 00 00 02 00 3B 00 //{ 26
+         00 07 00 07 00 00 00 FF 00 10                   //  }
+         
+         
+         
+         20 00 
+         00 
+         01 
+         0B 00 // sz = 0xB = 11
+         00 00 
+         01 00 
+         00 
+         00 
+         00 
+         00 
+         00 // unicode flag
+         07 // name
+         
+         3B 00 00 07 00 07 00 00 00 FF 00   // { 11 }
   */
-    /*
-      18, 00, 
-      1B, 00, 
-      
-      20, 00, 
-      00, 
-      01, 
-      0B, 00, 
-      00, 
-      00, 
-      00, 
-      00, 
-      00, 
-      07, 
-      3B 00 00 07 00 07 00 00 00 FF 00 ]     
-     */
-
-    /**
-     * @see Object#toString()
-     */
-    public String toString() {
-        StringBuffer buffer = new StringBuffer();
-
-        buffer.append("[NAME]\n");
-        buffer.append("    .option flags         = ").append( HexDump.toHex( field_1_option_flag ) )
-            .append("\n");
-        buffer.append("    .keyboard shortcut    = ").append( HexDump.toHex( field_2_keyboard_shortcut ) )
-            .append("\n");
-        buffer.append("    .length of the name   = ").append( field_3_length_name_text )
-            .append("\n");
-        buffer.append("    .size of the formula data = ").append( field_4_length_name_definition )
-            .append("\n");
-        buffer.append("    .unused                   = ").append( field_5_index_to_sheet )
-            .append("\n");
-        buffer.append("    .index to sheet (1-based, 0=Global)           = ").append( field_6_equals_to_index_to_sheet )
-            .append("\n");
-        buffer.append("    .Length of menu text (character count)        = ").append( field_7_length_custom_menu )
-            .append("\n");
-        buffer.append("    .Length of description text (character count) = ").append( field_8_length_description_text )
-            .append("\n");
-        buffer.append("    .Length of help topic text (character count)  = ").append( field_9_length_help_topic_text )
-            .append("\n");
-        buffer.append("    .Length of status bar text (character count)  = ").append( field_10_length_status_bar_text )
-            .append("\n");
-        buffer.append("    .Name (Unicode flag)  = ").append( field_11_compressed_unicode_flag )
-            .append("\n");
-        buffer.append("    .Name (Unicode text)  = ").append( getNameText() )
-            .append("\n");
-        
-        buffer.append("    .Parts (" + field_13_name_definition.size() +"):")
-            .append("\n");
-        Iterator it = field_13_name_definition.iterator();
-        while(it.hasNext()) {
-               Ptg ptg = (Ptg)it.next();
-               buffer.append("       " + ptg.toString()).append("\n");
-        }
-        
-        buffer.append("    .Menu text (Unicode string without length field)        = ").append( field_14_custom_menu_text )
-            .append("\n");
-        buffer.append("    .Description text (Unicode string without length field) = ").append( field_15_description_text )
-            .append("\n");
-        buffer.append("    .Help topic text (Unicode string without length field)  = ").append( field_16_help_topic_text )
-            .append("\n");
-        buffer.append("    .Status bar text (Unicode string without length field)  = ").append( field_17_status_bar_text )
-            .append("\n");
-        buffer.append("[/NAME]\n");
-        
-        return buffer.toString();
-    }
+       /*
+         18, 00, 
+         1B, 00, 
+         
+         20, 00, 
+         00, 
+         01, 
+         0B, 00, 
+         00, 
+         00, 
+         00, 
+         00, 
+         00, 
+         07, 
+         3B 00 00 07 00 07 00 00 00 FF 00 ]     
+        */
+
+       /**
+        * @see Object#toString()
+        */
+       public String toString() {
+               StringBuffer buffer = new StringBuffer();
+
+               buffer.append("[NAME]\n");
+               buffer.append("    .option flags         = ").append( HexDump.toHex( field_1_option_flag ) )
+                       .append("\n");
+               buffer.append("    .keyboard shortcut    = ").append( HexDump.toHex( field_2_keyboard_shortcut ) )
+                       .append("\n");
+               buffer.append("    .length of the name   = ").append( field_3_length_name_text )
+                       .append("\n");
+               buffer.append("    .size of the formula data = ").append( field_4_length_name_definition )
+                       .append("\n");
+               buffer.append("    .unused                   = ").append( field_5_index_to_sheet )
+                       .append("\n");
+               buffer.append("    .index to sheet (1-based, 0=Global)           = ").append( field_6_sheetNumber )
+                       .append("\n");
+               buffer.append("    .Length of menu text (character count)        = ").append( field_7_length_custom_menu )
+                       .append("\n");
+               buffer.append("    .Length of description text (character count) = ").append( field_8_length_description_text )
+                       .append("\n");
+               buffer.append("    .Length of help topic text (character count)  = ").append( field_9_length_help_topic_text )
+                       .append("\n");
+               buffer.append("    .Length of status bar text (character count)  = ").append( field_10_length_status_bar_text )
+                       .append("\n");
+               buffer.append("    .Name (Unicode flag)  = ").append( field_11_compressed_unicode_flag )
+                       .append("\n");
+               buffer.append("    .Name (Unicode text)  = ").append( getNameText() )
+                       .append("\n");
+               
+               buffer.append("    .Parts (" + field_13_name_definition.size() +"):")
+                       .append("\n");
+               Iterator it = field_13_name_definition.iterator();
+               while(it.hasNext()) {
+                       Ptg ptg = (Ptg)it.next();
+                       buffer.append("       " + ptg.toString()).append("\n");
+               }
+               
+               buffer.append("    .Menu text (Unicode string without length field)        = ").append( field_14_custom_menu_text )
+                       .append("\n");
+               buffer.append("    .Description text (Unicode string without length field) = ").append( field_15_description_text )
+                       .append("\n");
+               buffer.append("    .Help topic text (Unicode string without length field)  = ").append( field_16_help_topic_text )
+                       .append("\n");
+               buffer.append("    .Status bar text (Unicode string without length field)  = ").append( field_17_status_bar_text )
+                       .append("\n");
+               buffer.append("[/NAME]\n");
+               
+               return buffer.toString();
+       }
 
        /**Creates a human readable name for built in types
         * @return Unknown if the built-in name cannot be translated
         */
        protected String translateBuiltInName(byte name)
        {
-           switch (name)
-           {
-               case NameRecord.BUILTIN_AUTO_ACTIVATE :     return "Auto_Activate";
-               case NameRecord.BUILTIN_AUTO_CLOSE :        return "Auto_Close";
-               case NameRecord.BUILTIN_AUTO_DEACTIVATE :   return "Auto_Deactivate";
-               case NameRecord.BUILTIN_AUTO_OPEN :         return "Auto_Open";
-               case NameRecord.BUILTIN_CONSOLIDATE_AREA :  return "Consolidate_Area";
-               case NameRecord.BUILTIN_CRITERIA :          return "Criteria";
-               case NameRecord.BUILTIN_DATABASE :          return "Database";
-               case NameRecord.BUILTIN_DATA_FORM :         return "Data_Form";            
-               case NameRecord.BUILTIN_PRINT_AREA :        return "Print_Area";
-               case NameRecord.BUILTIN_PRINT_TITLE :       return "Print_Titles";
-               case NameRecord.BUILTIN_RECORDER :          return "Recorder";
-               case NameRecord.BUILTIN_SHEET_TITLE :       return "Sheet_Title";
-               
-           }
-           
-           return "Unknown";
+               switch (name)
+               {
+                       case NameRecord.BUILTIN_AUTO_ACTIVATE :     return "Auto_Activate";
+                       case NameRecord.BUILTIN_AUTO_CLOSE :        return "Auto_Close";
+                       case NameRecord.BUILTIN_AUTO_DEACTIVATE :   return "Auto_Deactivate";
+                       case NameRecord.BUILTIN_AUTO_OPEN :         return "Auto_Open";
+                       case NameRecord.BUILTIN_CONSOLIDATE_AREA :  return "Consolidate_Area";
+                       case NameRecord.BUILTIN_CRITERIA :          return "Criteria";
+                       case NameRecord.BUILTIN_DATABASE :          return "Database";
+                       case NameRecord.BUILTIN_DATA_FORM :         return "Data_Form";            
+                       case NameRecord.BUILTIN_PRINT_AREA :        return "Print_Area";
+                       case NameRecord.BUILTIN_PRINT_TITLE :       return "Print_Titles";
+                       case NameRecord.BUILTIN_RECORDER :          return "Recorder";
+                       case NameRecord.BUILTIN_SHEET_TITLE :       return "Sheet_Title";
+                       
+               }
+               
+               return "Unknown";
        }
 }
index 6755aa6f8b5fc61e54cdad056536ad468bea056f..cb4eff84068fe709ae9a98ab9f7262135323e0aa 100644 (file)
@@ -22,7 +22,7 @@ import org.apache.poi.util.LittleEndian;
 
 /**
  * Title:        Sup Book (EXTERNALBOOK) <P>
- * Description:  A External Workbook Description (Suplemental Book)
+ * Description:  A External Workbook Description (Supplemental Book)
  *               Its only a dummy record for making new ExternSheet Record <P>
  * REFERENCE:  5.38<P>
  * @author Libin Roman (Vista Portal LDT. Developer)
index fabc85ce52bad6a2a958cba06960c8ca49c273d6..800f45dbf5d1ec6734ae9cb38f55b3a0f87e785d 100644 (file)
@@ -110,7 +110,7 @@ public abstract class AbstractFunctionPtg extends OperationPtg {
      * @return <code>true</code> if the name specifies a standard worksheet function,
      *  <code>false</code> if the name should be assumed to be an external function.
      */
-    public static final boolean isInternalFunctionName(String name) {
+    public static final boolean isBuiltInFunctionName(String name) {
         short ix = FunctionMetadataRegistry.lookupIndexByName(name.toUpperCase());
         return ix >= 0;
     }
index 0a99ff140e51a9ea21d2800e604d1d34285d06f9..b6076e1ea8adf75880955f2e4716ad202f5ef970 100644 (file)
@@ -22,41 +22,55 @@ import org.apache.poi.ss.usermodel.Workbook;
 import org.apache.poi.hssf.record.RecordInputStream;
 
 /**
- *
- * @author  aviks
+ * 
+ * @author aviks
  */
 public final class NameXPtg extends OperandPtg {
-    public final static short sid  = 0x39;
-    private final static int  SIZE = 7;
-    private short             field_1_ixals;   // index to REF entry in externsheet record
-    private short             field_2_ilbl;    //index to defined name or externname table(1 based)
-    private short            field_3_reserved;   // reserved must be 0
-
-
-    public NameXPtg(RecordInputStream in) {
-        field_1_ixals        = in.readShort();
-        field_2_ilbl        = in.readShort();
-        field_3_reserved = in.readShort();
-    }
-
-    public void writeBytes(byte [] array, int offset) {
-        array[ offset + 0 ] = (byte)(sid + getPtgClass());
-        LittleEndian.putShort(array, offset + 1, field_1_ixals);
-        LittleEndian.putShort(array,offset+3, field_2_ilbl);
-        LittleEndian.putShort(array, offset + 5, field_3_reserved);
-    }
-
-    public int getSize() {
-        return SIZE;
-    }
-
-    public String toFormulaString(Workbook book)
-    {
-        // -1 to convert definedNameIndex from 1-based to zero-based
-        return book.resolveNameXText(field_1_ixals, field_2_ilbl-1); 
-    }
-    
-    public byte getDefaultOperandClass() {
+       public final static short sid = 0x39;
+       private final static int SIZE = 7;
+
+       /** index to REF entry in externsheet record */
+       private int _sheetRefIndex;
+       /** index to defined name or externname table(1 based) */
+       private int _nameNumber;
+       /** reserved must be 0 */
+       private int _reserved;
+
+       private NameXPtg(int sheetRefIndex, int nameNumber, int reserved) {
+               _sheetRefIndex = sheetRefIndex;
+               _nameNumber = nameNumber;
+               _reserved = reserved;
+       }
+
+       /**
+        * @param sheetRefIndex index to REF entry in externsheet record
+        * @param nameIndex index to defined name or externname table
+        */
+       public NameXPtg(int sheetRefIndex, int nameIndex) {
+               this(sheetRefIndex, nameIndex + 1, 0);
+       }
+
+       public NameXPtg(RecordInputStream in) {
+               this(in.readUShort(), in.readUShort(), in.readUShort());
+       }
+
+       public void writeBytes(byte[] array, int offset) {
+               LittleEndian.putByte(array, offset + 0, sid + getPtgClass());
+               LittleEndian.putUShort(array, offset + 1, _sheetRefIndex);
+               LittleEndian.putUShort(array, offset + 3, _nameNumber);
+               LittleEndian.putUShort(array, offset + 5, _reserved);
+       }
+
+       public int getSize() {
+               return SIZE;
+       }
+
+       public String toFormulaString(Workbook book) {
+               // -1 to convert definedNameIndex from 1-based to zero-based
+               return book.resolveNameXText(_sheetRefIndex, _nameNumber - 1);
+       }
+
+       public byte getDefaultOperandClass() {
                return Ptg.CLASS_VALUE;
        }
 }
index 31af2b773a066dafaf7685f1033e8503c18fa39c..8d7c0ada8119efb3ad325c832180342cb2fd651d 100644 (file)
@@ -23,67 +23,57 @@ import org.apache.poi.hssf.util.RangeAddress;
 import org.apache.poi.ss.usermodel.Name;
 
 /**
- * Title:        High Level Represantion of Named Range <P>
- * REFERENCE:  <P>
+ * High Level Representation of a 'defined name' which could be a 'built-in' name, 
+ * 'named range' or name of a user defined function.
+ * 
  * @author Libin Roman (Vista Portal LDT. Developer)
  */
-
 public class HSSFName implements Name {
-    private HSSFWorkbook         book;
-    private NameRecord       name;
+    private HSSFWorkbook _book;
+    private NameRecord _definedNameRec;
     
     /** Creates new HSSFName   - called by HSSFWorkbook to create a sheet from
      * scratch.
      *
      * @see org.apache.poi.hssf.usermodel.HSSFWorkbook#createName()
      * @param name the Name Record
-     * @param book lowlevel Workbook object associated with the sheet.
+     * @param book workbook object associated with the sheet.
      */
-    
-    protected HSSFName(HSSFWorkbook book, NameRecord name) {
-        this.book = book;
-        this.name = name;
+    /* package */ HSSFName(HSSFWorkbook book, NameRecord name) {
+        _book = book;
+        _definedNameRec = name;
     }
     
     /** Get the sheets name which this named range is referenced to
-     * @return sheet name, which this named range refered to
+     * @return sheet name, which this named range referred to
      */    
-
     public String getSheetName() {
-        String result ;
-        short indexToExternSheet = name.getExternSheetNumber();
+        short indexToExternSheet = _definedNameRec.getExternSheetNumber();
         
-        result = book.getWorkbook().findSheetNameFromExternSheet(indexToExternSheet);
-        
-        return result;
+        return _book.getWorkbook().findSheetNameFromExternSheet(indexToExternSheet);
     }
     
     /** 
-     * gets the name of the named range
-     * @return named range name
+     * @return text name of this defined name
      */    
-
     public String getNameName(){
-        String result = name.getNameText();
-        
-        return result;
+        return _definedNameRec.getNameText();
     }
     
     /** 
      * sets the name of the named range
      * @param nameName named range name to set
      */    
-
     public void setNameName(String nameName){
-        name.setNameText(nameName);
-        name.setNameTextLength((byte)nameName.length());
-        Workbook wb = book.getWorkbook();
+        _definedNameRec.setNameText(nameName);
+        _definedNameRec.setNameTextLength((byte)nameName.length());
+        Workbook wb = _book.getWorkbook();
         
         //Check to ensure no other names have the same case-insensitive name
         for ( int i = wb.getNumNames()-1; i >=0; i-- )
         {
                NameRecord rec = wb.getNameRecord(i);
-               if (rec != name) {
+               if (rec != _definedNameRec) {
                        if (rec.getNameText().equalsIgnoreCase(getNameName()))
                                throw new IllegalArgumentException("The workbook already contains this name (case-insensitive)");
                }
@@ -91,32 +81,25 @@ public class HSSFName implements Name {
     }
 
     /** 
-     * gets the reference of the named range
-     * @return reference of the named range
+     * Note - this method only applies to named ranges
+     * @return the formula text defining the named range
      */    
-
     public String getReference() {
-        String result;
-        result = name.getAreaReference(book);
-
-        return result;
+       if (_definedNameRec.isFunctionName()) {
+               throw new IllegalStateException("Only applicable to named ranges");
+       }
+        return _definedNameRec.getAreaReference(_book);
     }
 
-    
-
     /** 
      * sets the sheet name which this named range referenced to
      * @param sheetName the sheet name of the reference
      */    
-
     private void setSheetName(String sheetName){
-        int sheetNumber = book.getSheetIndex(sheetName);
-
+        int sheetNumber = _book.getSheetIndex(sheetName);
         short externSheetNumber = (short)
-               book.getExternalSheetIndex(sheetNumber);
-        name.setExternSheetNumber(externSheetNumber);
-//        name.setIndexToSheet(externSheetNumber);
-
+                       _book.getExternalSheetIndex(sheetNumber);
+        _definedNameRec.setExternSheetNumber(externSheetNumber);
     }
 
   
@@ -124,7 +107,6 @@ public class HSSFName implements Name {
      * sets the reference of this named range
      * @param ref the reference to set
      */    
-
     public void setReference(String ref){
 
         RangeAddress ra = new RangeAddress(ref);
@@ -136,8 +118,7 @@ public class HSSFName implements Name {
         }
 
                //allow the poi utilities to parse it out
-        name.setAreaReference(ref);
-
+        _definedNameRec.setAreaReference(ref);
     }
 
     /**
@@ -149,4 +130,14 @@ public class HSSFName implements Name {
         String ref = getReference();
         return "#REF!".endsWith(ref);
     }
+    public boolean isFunctionName() {
+       return _definedNameRec.isFunctionName();
+    }
+    public String toString() {
+        StringBuffer sb = new StringBuffer(64);
+        sb.append(getClass().getName()).append(" [");
+        sb.append(_definedNameRec.getNameText());
+        sb.append("]");
+        return sb.toString();
+    }
 }
index e663f38f2a94827d6660beb3ca8785987d3404b2..c77c8266b0c616b03e38eb85e712fac2098bb2e8 100644 (file)
@@ -53,6 +53,7 @@ import org.apache.poi.hssf.record.UnicodeString;
 import org.apache.poi.hssf.record.UnknownRecord;
 import org.apache.poi.hssf.record.formula.Area3DPtg;
 import org.apache.poi.hssf.record.formula.MemFuncPtg;
+import org.apache.poi.hssf.record.formula.NameXPtg;
 import org.apache.poi.hssf.record.formula.UnionPtg;
 import org.apache.poi.hssf.util.CellReference;
 import org.apache.poi.hssf.util.SheetReferences;
@@ -77,6 +78,9 @@ import org.apache.poi.util.POILogger;
  */
 public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.usermodel.Workbook
 {
+    private static final int MAX_ROW = 0xFFFF;
+    private static final short MAX_COLUMN = (short)0x00FF;
+
     private static final int DEBUG = POILogger.DEBUG;
 
     /**
@@ -856,7 +860,8 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
 
     /**
      * Sets the repeating rows and columns for a sheet (as found in
-     * File->PageSetup->Sheet).  This is function is included in the workbook
+     * 2003:File->PageSetup->Sheet, 2007:Page Layout->Print Titles).
+     *   This is function is included in the workbook
      * because it creates/modifies name records which are stored at the
      * workbook level.
      * <p>
@@ -886,10 +891,10 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
         // Check arguments
         if (startColumn == -1 && endColumn != -1) throw new IllegalArgumentException("Invalid column range specification");
         if (startRow == -1 && endRow != -1) throw new IllegalArgumentException("Invalid row range specification");
-        if (startColumn < -1 || startColumn >= 0xFF) throw new IllegalArgumentException("Invalid column range specification");
-        if (endColumn < -1 || endColumn >= 0xFF) throw new IllegalArgumentException("Invalid column range specification");
-        if (startRow < -1 || startRow > 65535) throw new IllegalArgumentException("Invalid row range specification");
-        if (endRow < -1 || endRow > 65535) throw new IllegalArgumentException("Invalid row range specification");
+        if (startColumn < -1 || startColumn >= MAX_COLUMN) throw new IllegalArgumentException("Invalid column range specification");
+        if (endColumn < -1 || endColumn >= MAX_COLUMN) throw new IllegalArgumentException("Invalid column range specification");
+        if (startRow < -1 || startRow > MAX_ROW) throw new IllegalArgumentException("Invalid row range specification");
+        if (endRow < -1 || endRow > MAX_ROW) throw new IllegalArgumentException("Invalid row range specification");
         if (startColumn > endColumn) throw new IllegalArgumentException("Invalid column range specification");
         if (startRow > endRow) throw new IllegalArgumentException("Invalid row range specification");
 
@@ -901,50 +906,60 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
         boolean removingRange =
                 startColumn == -1 && endColumn == -1 && startRow == -1 && endRow == -1;
 
-        boolean isNewRecord = false;
-        NameRecord nameRecord;
-        nameRecord = findExistingRowColHeaderNameRecord(sheetIndex);
-        if (removingRange )
-        {
-            if (nameRecord != null)
-                workbook.removeName(findExistingRowColHeaderNameRecordIdx(sheetIndex+1));
+        int rowColHeaderNameIndex = findExistingRowColHeaderNameRecordIdx(sheetIndex);
+        if (removingRange) {
+            if (rowColHeaderNameIndex >= 0) {
+                workbook.removeName(rowColHeaderNameIndex);
+            }
             return;
         }
-        if ( nameRecord == null )
-        {
-            nameRecord = workbook.createBuiltInName(NameRecord.BUILTIN_PRINT_TITLE, sheetIndex+1);
+        boolean isNewRecord;
+        NameRecord nameRecord;
+        if (rowColHeaderNameIndex < 0) {
             //does a lot of the house keeping for builtin records, like setting lengths to zero etc
+            nameRecord = workbook.createBuiltInName(NameRecord.BUILTIN_PRINT_TITLE, sheetIndex+1);
             isNewRecord = true;
+        } else {
+            nameRecord = workbook.getNameRecord(rowColHeaderNameIndex);
+            isNewRecord = false;
         }
 
         short definitionTextLength = settingRowAndColumn ? (short)0x001a : (short)0x000b;
-        nameRecord.setDefinitionTextLength(definitionTextLength);
+        nameRecord.setDefinitionTextLength(definitionTextLength); // TODO - remove
 
         Stack ptgs = new Stack();
 
-        if (settingRowAndColumn)
-        {
-            ptgs.add(new MemFuncPtg(23)); // TODO - where did constant '23' come from?
+        if (settingRowAndColumn) {
+            final int exprsSize = 2 * 11 + 1; // Area3DPtg.SIZE + UnionPtg.SIZE
+            ptgs.add(new MemFuncPtg(exprsSize));
         }
         if (startColumn >= 0)
         {
-            Area3DPtg area3DPtg1 = new Area3DPtg();
-            area3DPtg1.setExternSheetIndex(externSheetIndex);
-            area3DPtg1.setFirstColumn((short)startColumn);
-            area3DPtg1.setLastColumn((short)endColumn);
-            area3DPtg1.setFirstRow((short)0);
-            area3DPtg1.setLastRow((short)0xFFFF);
-            ptgs.add(area3DPtg1);
+            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);
+            ptgs.add(colArea);
         }
         if (startRow >= 0)
         {
-            Area3DPtg area3DPtg2 = new Area3DPtg();
-            area3DPtg2.setExternSheetIndex(externSheetIndex);
-            area3DPtg2.setFirstColumn((short)0);
-            area3DPtg2.setLastColumn((short)0x00FF);
-            area3DPtg2.setFirstRow((short)startRow);
-            area3DPtg2.setLastRow((short)endRow);
-            ptgs.add(area3DPtg2);
+            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);
+            ptgs.add(rowArea);
         }
         if (settingRowAndColumn)
         {
@@ -964,38 +979,31 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
         sheet.setActive(true);
     }
 
-    private NameRecord findExistingRowColHeaderNameRecord( int sheetIndex )
-    {
-        int index = findExistingRowColHeaderNameRecordIdx(sheetIndex);
-        if (index == -1)
-            return null;
-        else
-            return (NameRecord)workbook.findNextRecordBySid(NameRecord.sid, index);
-    }
 
-    private int findExistingRowColHeaderNameRecordIdx( int sheetIndex )
-    {
-        int index = 0;
-        NameRecord r = null;
-        while ((r = (NameRecord) workbook.findNextRecordBySid(NameRecord.sid, index)) != null)
-        {
-            int indexToSheet = r.getEqualsToIndexToSheet() -1;
-            if(indexToSheet > -1) { //ignore "GLOBAL" name records
-                int nameRecordSheetIndex = workbook.getSheetIndexFromExternSheetIndex(indexToSheet);
-                if (isRowColHeaderRecord( r ) && nameRecordSheetIndex == sheetIndex)
-                {
-                    return index;
-                }
+    private int findExistingRowColHeaderNameRecordIdx(int sheetIndex) {
+        for(int defNameIndex =0; defNameIndex<names.size(); defNameIndex++) {
+            NameRecord r = workbook.getNameRecord(defNameIndex);
+            if (r == null) {
+                throw new RuntimeException("Unable to find all defined names to iterate over");
+            }
+            if (!isRowColHeaderRecord( r )) {
+                continue;
+            }
+            if(r.getSheetNumber() == 0) {
+                //ignore "GLOBAL" name records
+                continue;
+            }
+            int externIndex = r.getSheetNumber() -1;
+            int nameRecordSheetIndex = workbook.getSheetIndexFromExternSheetIndex(externIndex);
+            if (nameRecordSheetIndex == sheetIndex) {
+                return defNameIndex;
             }
-            index++;
         }
-
         return -1;
     }
 
-    private boolean isRowColHeaderRecord( NameRecord r )
-    {
-        return r.getOptionFlag() == 0x20 && ("" + ((char)7)).equals(r.getNameText());
+    private static boolean isRowColHeaderRecord(NameRecord r) {
+        return r.isBuiltInName() && r.getBuiltInName() == NameRecord.BUILTIN_PRINT_TITLE;
     }
 
     /**
@@ -1089,7 +1097,7 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
      *  and that's not something you should normally do
      */
     protected void resetFontCache() {
-       fonts = new Hashtable();
+        fonts = new Hashtable();
     }
 
     /**
@@ -1658,9 +1666,16 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
        return new HSSFCreationHelper(this);
     }
 
-    private byte[] newUID()
-    {
-        byte[] bytes = new byte[16];
-        return bytes;
+    private static byte[] newUID() {
+        return new byte[16];
     }
+
+    /**
+     * Note - This method should only used by POI internally.  
+     * It may get deleted or change definition in future POI versions
+     */
+       public NameXPtg getNameXPtg(String name) {
+               return workbook.getNameXPtg(name);              
+       }
+
 }
index 846ef66d6b8655346b0e0105015b8286c160c7b8..bf4823972c38c280874001b3f5399b9c86df27a2 100644 (file)
@@ -19,4 +19,5 @@ package org.apache.poi.ss.usermodel;
 
 public interface Name {
     void setNameName(String nameName);
+       boolean isFunctionName();
 }
index f68fd35c620e3c253543d19476d07da74c2052d0..a31d03e4ca780518763b90b3cbc13014ee8024e0 100644 (file)
@@ -33,6 +33,7 @@ public interface Workbook {
 
     HSSFName createName();
     HSSFName getNameAt(int index);
+    int getNameIndex(String name);
     String getNameName(int index);
     String resolveNameXText(int refIndex, int definedNameIndex);
 
index 19f5230610c3b3413a645903027bb131fcdca4c0..7ff4cbcf808bd3162c16fb5c389bff67c5ff3f44 100644 (file)
@@ -53,4 +53,5 @@ public interface Name {
 
     void setReference(String ref);
 
-}
\ No newline at end of file
+       boolean isFunctionName();
+}
index f06786b1fc9a7a210d192e0452e9120fed669d5c..daf1c8e1720736a3c3b9470dd4563fd424ff371c 100644 (file)
@@ -219,24 +219,25 @@ public class HWPFDocument extends POIDocument
         _dataStream = new byte[0];
     }
 
-    // get the start of text in the main stream
-    int fcMin = _fib.getFcMin();
+    // Get the cp of the start of text in the main stream
+    // The latest spec doc says this is always zero!
+    int fcMin = 0;
+    //fcMin = _fib.getFcMin() 
 
-    // load up our standard structures.
+    // Start to load up our standard structures.
     _dop = new DocumentProperties(_tableStream, _fib.getFcDop());
     _cft = new ComplexFileTable(_mainStream, _tableStream, _fib.getFcClx(), fcMin);
     _tpt = _cft.getTextPieceTable();
-    _cbt = new CHPBinTable(_mainStream, _tableStream, _fib.getFcPlcfbteChpx(), _fib.getLcbPlcfbteChpx(), fcMin);
-    _pbt = new PAPBinTable(_mainStream, _tableStream, _dataStream, _fib.getFcPlcfbtePapx(), _fib.getLcbPlcfbtePapx(), fcMin);
-
-    // Word XP puts in a zero filled buffer in front of the text and it screws
-    // up my system for offsets. This is an adjustment.
+    
+    // Word XP and later all put in a zero filled buffer in
+    //  front of the text. This screws up the system for offsets,
+    //  which assume we always start at zero. This is an adjustment.
     int cpMin = _tpt.getCpMin();
-    if (cpMin > 0)
-    {
-      _cbt.adjustForDelete(0, 0, cpMin);
-      _pbt.adjustForDelete(0, 0, cpMin);
-    }
+    
+    // Now load the rest of the properties, which need to be adjusted
+    //  for where text really begin
+    _cbt = new CHPBinTable(_mainStream, _tableStream, _fib.getFcPlcfbteChpx(), _fib.getLcbPlcfbteChpx(), cpMin, _tpt);
+    _pbt = new PAPBinTable(_mainStream, _tableStream, _dataStream, _fib.getFcPlcfbtePapx(), _fib.getLcbPlcfbtePapx(), cpMin, _tpt);
     
     // Read FSPA and Escher information
     _fspa = new FSPATable(_tableStream, _fib.getFcPlcspaMom(), _fib.getLcbPlcspaMom(), getTextTable().getTextPieces());
@@ -252,7 +253,7 @@ public class HWPFDocument extends POIDocument
     // read in the pictures stream
     _pictures = new PicturesTable(this, _dataStream, _mainStream, _fspa, _dgg);
 
-    _st = new SectionTable(_mainStream, _tableStream, _fib.getFcPlcfsed(), _fib.getLcbPlcfsed(), fcMin, getTextTable().getTextPieces());
+    _st = new SectionTable(_mainStream, _tableStream, _fib.getFcPlcfsed(), _fib.getLcbPlcfsed(), fcMin, _tpt, _cpSplit);
     _ss = new StyleSheet(_tableStream, _fib.getFcStshf());
     _ft = new FontTable(_tableStream, _fib.getFcSttbfffn(), _fib.getLcbSttbfffn());
 
@@ -316,6 +317,11 @@ public class HWPFDocument extends POIDocument
    *  document, but excludes any headers and footers.
    */
   public Range getRange() {
+         // First up, trigger a full-recalculate
+         // Needed in case of deletes etc
+         getOverallRange();
+         
+         // Now, return the real one
          return new Range(
                          _cpSplit.getMainDocumentStart(), 
                          _cpSplit.getMainDocumentEnd(), 
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/BytePropertyNode.java b/src/scratchpad/src/org/apache/poi/hwpf/model/BytePropertyNode.java
new file mode 100644 (file)
index 0000000..d22edb6
--- /dev/null
@@ -0,0 +1,60 @@
+/* ====================================================================
+   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.hwpf.model;
+
+/**
+ * Normally PropertyNodes only ever work in characters, but
+ *  a few cases actually store bytes, and this lets everything
+ *  still work despite that.
+ * It handles the conversion as required between bytes
+ *  and characters.
+ */
+public abstract class BytePropertyNode extends PropertyNode {
+       private boolean isUnicode;
+       
+       /**
+        * @param fcStart The start of the text for this property, in _bytes_
+        * @param fcEnd The end of the text for this property, in _bytes_
+        */
+       public BytePropertyNode(int fcStart, int fcEnd, Object buf, boolean isUnicode) {
+               super(
+                               generateCp(fcStart, isUnicode),
+                               generateCp(fcEnd, isUnicode),
+                               buf
+               );
+               this.isUnicode = isUnicode;
+       }
+       private static int generateCp(int val, boolean isUnicode) {
+               if(isUnicode)
+                       return val/2;
+               return val;
+       }
+       
+       public boolean isUnicode() {
+               return isUnicode;
+       }
+       public int getStartBytes() {
+               if(isUnicode)
+                       return getStart()*2;
+               return getStart();
+       }
+       public int getEndBytes() {
+               if(isUnicode)
+                       return getEnd()*2;
+               return getEnd();
+       }
+}
index 48c5a9d8b4865827f02cc7754e61215605b02086..f46aee80a18661b19477066da0644560ba60a098 100644 (file)
@@ -37,6 +37,8 @@ public class CHPBinTable
   /** List of character properties.*/
   protected ArrayList _textRuns = new ArrayList();
 
+  /** So we can know if things are unicode or not */
+  private TextPieceTable tpt;
 
   public CHPBinTable()
   {
@@ -52,9 +54,10 @@ public class CHPBinTable
    * @param fcMin
    */
   public CHPBinTable(byte[] documentStream, byte[] tableStream, int offset,
-                     int size, int fcMin)
+                     int size, int fcMin, TextPieceTable tpt)
   {
     PlexOfCps binTable = new PlexOfCps(tableStream, offset, size, 4);
+    this.tpt = tpt;
 
     int length = binTable.length();
     for (int x = 0; x < length; x++)
@@ -65,7 +68,7 @@ public class CHPBinTable
       int pageOffset = POIFSConstants.BIG_BLOCK_SIZE * pageNum;
 
       CHPFormattedDiskPage cfkp = new CHPFormattedDiskPage(documentStream,
-        pageOffset, fcMin);
+        pageOffset, fcMin, tpt);
 
       int fkpSize = cfkp.size();
 
@@ -116,7 +119,14 @@ public class CHPBinTable
 
   public void insert(int listIndex, int cpStart, SprmBuffer buf)
   {
-    CHPX insertChpx = new CHPX(cpStart, cpStart, buf);
+       boolean needsToBeUnicode = tpt.isUnicodeAtCharOffset(cpStart);
+         
+    CHPX insertChpx = new CHPX(0, 0, buf, needsToBeUnicode);
+    
+    // Ensure character offsets are really characters
+    insertChpx.setStart(cpStart);
+    insertChpx.setEnd(cpStart);
+    
     if (listIndex == _textRuns.size())
     {
       _textRuns.add(insertChpx);
@@ -126,7 +136,16 @@ public class CHPBinTable
       CHPX chpx = (CHPX)_textRuns.get(listIndex);
       if (chpx.getStart() < cpStart)
       {
-        CHPX clone = new CHPX(cpStart, chpx.getEnd(), chpx.getSprmBuf());
+       // Copy the properties of the one before to afterwards
+       // Will go:
+       //  Original, until insert at point
+       //  New one
+       //  Clone of original, on to the old end
+        CHPX clone = new CHPX(0, 0, chpx.getSprmBuf(), needsToBeUnicode);
+        // Again ensure contains character based offsets no matter what
+        clone.setStart(cpStart);
+        clone.setEnd(chpx.getEnd());
+        
         chpx.setEnd(cpStart);
 
         _textRuns.add(listIndex + 1, insertChpx);
index cd1a8c24f0916dfec641bf17f635fc6cfbca31ed..e6b302300feb86b64ecab01403720514110184bc 100644 (file)
@@ -55,13 +55,14 @@ public class CHPFormattedDiskPage extends FormattedDiskPage
      * This constructs a CHPFormattedDiskPage from a raw fkp (512 byte array
      * read from a Word file).
      */
-    public CHPFormattedDiskPage(byte[] documentStream, int offset, int fcMin)
+    public CHPFormattedDiskPage(byte[] documentStream, int offset, int fcMin, TextPieceTable tpt)
     {
       super(documentStream, offset);
 
       for (int x = 0; x < _crun; x++)
       {
-        _chpxList.add(new CHPX(getStart(x) - fcMin, getEnd(x) - fcMin, getGrpprl(x)));
+       boolean isUnicode = tpt.isUnicodeAtByteOffset( getStart(x) );
+        _chpxList.add(new CHPX(getStart(x) - fcMin, getEnd(x) - fcMin, getGrpprl(x), isUnicode));
       }
     }
 
@@ -157,7 +158,7 @@ public class CHPFormattedDiskPage extends FormattedDiskPage
         chpx = (CHPX)_chpxList.get(x);
         byte[] grpprl = chpx.getGrpprl();
 
-        LittleEndian.putInt(buf, fcOffset, chpx.getStart() + fcMin);
+        LittleEndian.putInt(buf, fcOffset, chpx.getStartBytes() + fcMin);
         grpprlOffset -= (1 + grpprl.length);
         grpprlOffset -= (grpprlOffset % 2);
         buf[offsetOffset] = (byte)(grpprlOffset/2);
@@ -168,7 +169,7 @@ public class CHPFormattedDiskPage extends FormattedDiskPage
         fcOffset += FC_SIZE;
       }
       // put the last chpx's end in
-      LittleEndian.putInt(buf, fcOffset, chpx.getEnd() + fcMin);
+      LittleEndian.putInt(buf, fcOffset, chpx.getEndBytes() + fcMin);
       return buf;
     }
 
index 3e7b5b11fb6506018a883f837d7c6ab2e94f6ced..a89036c73357fe48ffac9df43435954f6da9ecbb 100644 (file)
@@ -25,22 +25,26 @@ import org.apache.poi.hwpf.sprm.SprmBuffer;
 import org.apache.poi.hwpf.sprm.CharacterSprmUncompressor;
 
 /**
- * Comment me
+ * DANGER - works in bytes!
+ * 
+ * Make sure you call getStart() / getEnd() when you want characters
+ *  (normal use), but getStartByte() / getEndByte() when you're 
+ *  reading in / writing out!
  *
  * @author Ryan Ackley
  */
 
-public class CHPX extends PropertyNode
+public class CHPX extends BytePropertyNode
 {
 
-  public CHPX(int fcStart, int fcEnd, byte[] grpprl)
+  public CHPX(int fcStart, int fcEnd, byte[] grpprl, boolean isUnicode)
   {
-    super(fcStart, fcEnd, new SprmBuffer(grpprl));
+    super(fcStart, fcEnd, new SprmBuffer(grpprl), isUnicode);
   }
 
-  public CHPX(int fcStart, int fcEnd, SprmBuffer buf)
+  public CHPX(int fcStart, int fcEnd, SprmBuffer buf, boolean isUnicode)
   {
-    super(fcStart, fcEnd, buf);
+    super(fcStart, fcEnd, buf, isUnicode);
   }
 
 
index 6f141d7612729b22389f12a9dd3c6bf283d4b1b9..ed47b59c59323cb7aaacd8a6e6e1d611b3691f3e 100644 (file)
@@ -39,14 +39,18 @@ public class PAPBinTable
   protected ArrayList _paragraphs = new ArrayList();
   byte[] _dataStream;
 
+  /** So we can know if things are unicode or not */
+  private TextPieceTable tpt;
+
   public PAPBinTable()
   {
   }
 
   public PAPBinTable(byte[] documentStream, byte[] tableStream, byte[] dataStream, int offset,
-                     int size, int fcMin)
+                     int size, int fcMin, TextPieceTable tpt)
   {
     PlexOfCps binTable = new PlexOfCps(tableStream, offset, size, 4);
+    this.tpt = tpt;
 
     int length = binTable.length();
     for (int x = 0; x < length; x++)
@@ -57,13 +61,14 @@ public class PAPBinTable
       int pageOffset = POIFSConstants.BIG_BLOCK_SIZE * pageNum;
 
       PAPFormattedDiskPage pfkp = new PAPFormattedDiskPage(documentStream,
-        dataStream, pageOffset, fcMin);
+        dataStream, pageOffset, fcMin, tpt);
 
       int fkpSize = pfkp.size();
 
       for (int y = 0; y < fkpSize; y++)
       {
-        _paragraphs.add(pfkp.getPAPX(y));
+       PAPX papx = pfkp.getPAPX(y);
+        _paragraphs.add(papx);
       }
     }
     _dataStream = dataStream;
@@ -71,7 +76,14 @@ public class PAPBinTable
 
   public void insert(int listIndex, int cpStart, SprmBuffer buf)
   {
-    PAPX forInsert = new PAPX(cpStart, cpStart, buf, _dataStream);
+    boolean needsToBeUnicode = tpt.isUnicodeAtCharOffset(cpStart);
+    
+    PAPX forInsert = new PAPX(0, 0, buf, _dataStream, needsToBeUnicode);
+    
+    // Ensure character offsets are really characters
+    forInsert.setStart(cpStart);
+    forInsert.setEnd(cpStart);
+    
     if (listIndex == _paragraphs.size())
     {
        _paragraphs.add(forInsert);
@@ -90,10 +102,21 @@ public class PAPBinTable
         {
           exc.printStackTrace();
         }
+        
+       // Copy the properties of the one before to afterwards
+       // Will go:
+       //  Original, until insert at point
+       //  New one
+       //  Clone of original, on to the old end
+        PAPX clone = new PAPX(0, 0, clonedBuf, _dataStream, needsToBeUnicode);
+        // Again ensure contains character based offsets no matter what
+        clone.setStart(cpStart);
+        clone.setEnd(currentPap.getEnd());
+        
         currentPap.setEnd(cpStart);
-        PAPX splitPap = new PAPX(cpStart, currentPap.getEnd(), clonedBuf, _dataStream);
-        _paragraphs.add(++listIndex, forInsert);
-        _paragraphs.add(++listIndex, splitPap);
+
+        _paragraphs.add(listIndex + 1, forInsert);
+        _paragraphs.add(listIndex + 2, clone);
       }
       else
       {
index 979825bf84aae65637650a00168011fd96e8311f..1a9a7bad5908ac8acf467939624508d6bbdd75d4 100644 (file)
@@ -60,13 +60,17 @@ public class PAPFormattedDiskPage extends FormattedDiskPage
     /**
      * Creates a PAPFormattedDiskPage from a 512 byte array
      */
-    public PAPFormattedDiskPage(byte[] documentStream, byte[] dataStream, int offset, int fcMin)
+    public PAPFormattedDiskPage(byte[] documentStream, byte[] dataStream, int offset, int fcMin, TextPieceTable tpt)
     {
       super(documentStream, offset);
 
-      for (int x = 0; x < _crun; x++)
-      {
-        _papxList.add(new PAPX(getStart(x) - fcMin, getEnd(x) - fcMin, getGrpprl(x), getParagraphHeight(x), dataStream));
+      for (int x = 0; x < _crun; x++) {
+         int startAt = getStart(x) - fcMin;
+         int endAt = getEnd(x) - fcMin;
+        boolean isUnicode = tpt.isUnicodeAtByteOffset(startAt);
+         //System.err.println(startAt + " -> " + endAt + " = " + isUnicode);
+        
+         _papxList.add(new PAPX(startAt, endAt, getGrpprl(x), getParagraphHeight(x), dataStream, isUnicode));
       }
       _fkp = null;
       _dataStream = dataStream;
@@ -110,7 +114,7 @@ public class PAPFormattedDiskPage extends FormattedDiskPage
     }
 
     /**
-     * Gets the papx for the paragraph at index in this fkp.
+     * Gets the papx grpprl for the paragraph at index in this fkp.
      *
      * @param index The index of the papx to get.
      * @return a papx grpprl.
@@ -259,7 +263,7 @@ public class PAPFormattedDiskPage extends FormattedDiskPage
           grpprlOffset -= (grpprl.length + (2 - grpprl.length % 2));
           grpprlOffset -= (grpprlOffset % 2);
         }
-        LittleEndian.putInt(buf, fcOffset, papx.getStart() + fcMin);
+        LittleEndian.putInt(buf, fcOffset, papx.getStartBytes() + fcMin);
         buf[bxOffset] = (byte)(grpprlOffset/2);
         System.arraycopy(phe, 0, buf, bxOffset + 1, phe.length);
 
@@ -287,7 +291,7 @@ public class PAPFormattedDiskPage extends FormattedDiskPage
 
       }
 
-      LittleEndian.putInt(buf, fcOffset, papx.getEnd() + fcMin);
+      LittleEndian.putInt(buf, fcOffset, papx.getEndBytes() + fcMin);
       return buf;
     }
 
index a7e259ec73f452fb157ad92c38562759eb21abc0..1e8ae86b526b4399ad12752391b13ebb43ddea78 100644 (file)
@@ -29,29 +29,32 @@ import org.apache.poi.hwpf.sprm.SprmBuffer;
 import org.apache.poi.hwpf.sprm.SprmOperation;
 
 /**
- * Comment me
+ * DANGER - works in bytes!
+ * 
+ * Make sure you call getStart() / getEnd() when you want characters
+ *  (normal use), but getStartByte() / getEndByte() when you're 
+ *  reading in / writing out!
  *
  * @author Ryan Ackley
  */
 
-public class PAPX extends PropertyNode
-{
+public class PAPX extends BytePropertyNode {
 
   private ParagraphHeight _phe;
   private int _hugeGrpprlOffset = -1;
 
-  public PAPX(int fcStart, int fcEnd, byte[] papx, ParagraphHeight phe, byte[] dataStream)
+  public PAPX(int fcStart, int fcEnd, byte[] papx, ParagraphHeight phe, byte[] dataStream, boolean isUnicode)
   {
-    super(fcStart, fcEnd, new SprmBuffer(papx));
+    super(fcStart, fcEnd, new SprmBuffer(papx), isUnicode);
     _phe = phe;
     SprmBuffer buf = findHuge(new SprmBuffer(papx), dataStream);
     if(buf != null)
       _buf = buf;
   }
 
-  public PAPX(int fcStart, int fcEnd, SprmBuffer buf, byte[] dataStream)
+  public PAPX(int fcStart, int fcEnd, SprmBuffer buf, byte[] dataStream, boolean isUnicode)
   {
-    super(fcStart, fcEnd, buf);
+    super(fcStart, fcEnd, buf, isUnicode);
     _phe = new ParagraphHeight();
     buf = findHuge(buf, dataStream);
     if(buf != null)
index 42c5f5c27eb02ade48c9506105365527e7179450..5a14917962d59c6617f833f19dd9af016126107a 100644 (file)
@@ -22,7 +22,10 @@ import java.util.Arrays;
 
 /**
  * Represents a lightweight node in the Trees used to store content
- * properties. Works only in characters.
+ *  properties.
+ * This only ever works in characters. For the few odd cases when
+ *  the start and end aren't in characters (eg PAPX and CHPX), use
+ *  {@link BytePropertyNode} between you and this.
  *
  * @author Ryan Ackley
  */
@@ -45,6 +48,11 @@ public abstract class PropertyNode implements Comparable, Cloneable
       _cpStart = fcStart;
       _cpEnd = fcEnd;
       _buf = buf;
+      
+      if(_cpStart < 0) {
+         System.err.println("A property claimed to start before zero, at " + _cpStart + "! Resetting it to zero, and hoping for the best");
+         _cpStart = 0;
+      }
   }
 
   /**
@@ -82,18 +90,18 @@ public abstract class PropertyNode implements Comparable, Cloneable
   {
     int end = start + length;
 
-    if (_cpEnd > start)
-    {
-      if (_cpStart < end)
-      {
-        _cpEnd = end >= _cpEnd ? start : _cpEnd - length;
-        _cpStart = Math.min(start, _cpStart);
-      }
-      else
-      {
-        _cpEnd -= length;
-        _cpStart -= length;
-      }
+    if (_cpEnd > start) {
+        // The start of the change is before we end
+       
+        if (_cpStart < end) {
+            // The delete was somewhere in the middle of us
+            _cpEnd = end >= _cpEnd ? start : _cpEnd - length;
+            _cpStart = Math.min(start, _cpStart);
+        } else {
+            // The delete was before us
+            _cpEnd -= length;
+            _cpStart -= length;
+        }
     }
   }
 
index c66f8aa349a53a0e033e2cc34902f26020fd95a3..7987280ed1370c0b5cdb60b9cf05f28a27b08878 100644 (file)
 
 package org.apache.poi.hwpf.model;
 
-import org.apache.poi.hwpf.sprm.SprmBuffer;
-import org.apache.poi.hwpf.sprm.SectionSprmUncompressor;
 import org.apache.poi.hwpf.sprm.SectionSprmCompressor;
+import org.apache.poi.hwpf.sprm.SectionSprmUncompressor;
 import org.apache.poi.hwpf.usermodel.SectionProperties;
 
-public class SEPX extends PropertyNode
+/**
+ */
+public class SEPX extends BytePropertyNode
 {
 
   SectionDescriptor _sed;
 
-  public SEPX(SectionDescriptor sed, int start, int end, byte[] grpprl)
+  public SEPX(SectionDescriptor sed, int start, int end, byte[] grpprl, boolean isUnicode)
   {
-    super(start, end, SectionSprmUncompressor.uncompressSEP(grpprl, 0));
+    super(start, end, SectionSprmUncompressor.uncompressSEP(grpprl, 0), isUnicode);
     _sed = sed;
   }
 
index 7b9c23325fc78cf603cd603367c3e79fa7e849d2..b88edbb95e285d5656c7afaaf5ce837c12c61ff5 100644 (file)
@@ -34,6 +34,9 @@ public class SectionTable
   protected ArrayList _sections = new ArrayList();
   protected List _text;
 
+  /** So we can know if things are unicode or not */
+  private TextPieceTable tpt;
+
   public SectionTable()
   {
   }
@@ -41,10 +44,11 @@ public class SectionTable
 
   public SectionTable(byte[] documentStream, byte[] tableStream, int offset,
                       int size, int fcMin,
-                      List tpt)
+                      TextPieceTable tpt, CPSplitCalculator cps)
   {
     PlexOfCps sedPlex = new PlexOfCps(tableStream, offset, size, SED_SIZE);
-    _text = tpt;
+    this.tpt = tpt;
+    this._text = tpt.getTextPieces();
 
     int length = sedPlex.length();
 
@@ -54,11 +58,16 @@ public class SectionTable
       SectionDescriptor sed = new SectionDescriptor(node.getBytes(), 0);
 
       int fileOffset = sed.getFc();
+      int startAt = CPtoFC(node.getStart());
+      int endAt = CPtoFC(node.getEnd());
+      
+      boolean isUnicodeAtStart = tpt.isUnicodeAtByteOffset( startAt );
+//      System.err.println(startAt + " -> " + endAt + " = " + isUnicodeAtStart);
 
       // check for the optimization
       if (fileOffset == 0xffffffff)
       {
-        _sections.add(new SEPX(sed, CPtoFC(node.getStart()), CPtoFC(node.getEnd()), new byte[0]));
+        _sections.add(new SEPX(sed, startAt, endAt, new byte[0], isUnicodeAtStart));
       }
       else
       {
@@ -67,9 +76,34 @@ public class SectionTable
         byte[] buf = new byte[sepxSize];
         fileOffset += LittleEndian.SHORT_SIZE;
         System.arraycopy(documentStream, fileOffset, buf, 0, buf.length);
-        _sections.add(new SEPX(sed, CPtoFC(node.getStart()), CPtoFC(node.getEnd()), buf));
+        _sections.add(new SEPX(sed, startAt, endAt, buf, isUnicodeAtStart));
       }
     }
+    
+    // Some files seem to lie about their unicode status, which
+    //  is very very pesky. Try to work around these, but this
+    //  is getting on for black magic...
+    int mainEndsAt = cps.getMainDocumentEnd();
+    boolean matchAt = false;
+    boolean matchHalf = false;
+    for(int i=0; i<_sections.size(); i++) {
+       SEPX s = (SEPX)_sections.get(i);
+       if(s.getEnd() == mainEndsAt) {
+               matchAt = true;
+       } else if(s.getEndBytes() == mainEndsAt || s.getEndBytes() == mainEndsAt-1) {
+               matchHalf = true;
+       }
+    }
+    if(! matchAt && matchHalf) {
+       System.err.println("Your document seemed to be mostly unicode, but the section definition was in bytes! Trying anyway, but things may well go wrong!");
+        for(int i=0; i<_sections.size(); i++) {
+               SEPX s = (SEPX)_sections.get(i);
+            GenericPropertyNode node = sedPlex.getProperty(i);
+            
+               s.setStart( CPtoFC(node.getStart()) );
+               s.setEnd( CPtoFC(node.getEnd()) );
+        }
+    }
   }
 
   public void adjustForInsert(int listIndex, int length)
@@ -171,7 +205,7 @@ public class SectionTable
 
       // Line using Ryan's FCtoCP() conversion method -
       // unable to observe any effect on our testcases when using this code - piers
-      GenericPropertyNode property = new GenericPropertyNode(FCtoCP(sepx.getStart()), FCtoCP(sepx.getEnd()), sed.toByteArray());
+      GenericPropertyNode property = new GenericPropertyNode(FCtoCP(sepx.getStartBytes()), FCtoCP(sepx.getEndBytes()), sed.toByteArray());
 
 
       plex.addProperty(property);
index 351c06ae7426fa700664f83ca7696f46503a588e..bf2cf3014a95d192c5c5692e1ddde82bddc487bb 100644 (file)
@@ -118,6 +118,9 @@ public class TextPiece extends PropertyNode implements Comparable
           if(end > buf.length()) {
                   throw new StringIndexOutOfBoundsException("Index " + end + " out of range 0 -> " + buf.length());
           }
+          if(end < start) {
+                  throw new StringIndexOutOfBoundsException("Asked for text from " + start + " to " + end + ", which has an end before the start!");
+          }
           return buf.substring(start, end);
    }
 
index 5e903ecb8ae70793dc2f71dd472a20ecdac82c39..129603463282c536e727bc8961b7defcf0144812 100644 (file)
@@ -25,6 +25,9 @@ import org.apache.poi.poifs.common.POIFSConstants;
 import java.io.IOException;
 import java.io.UnsupportedEncodingException;
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Hashtable;
+import java.util.Iterator;
 import java.util.List;
 
 /**
@@ -62,8 +65,17 @@ public class TextPieceTable
       pieces[x] = new PieceDescriptor(node.getBytes(), 0);
     }
 
-    int firstPieceFilePosition = pieces[0].getFilePosition();
-    _cpMin = firstPieceFilePosition - fcMin;
+    
+    // Figure out the cp of the earliest text piece
+    // Note that text pieces don't have to be stored in order!
+    _cpMin = pieces[0].getFilePosition() - fcMin;
+    for (int x = 0; x < pieces.length; x++) {
+       int start = pieces[x].getFilePosition() - fcMin;
+       if(start < _cpMin) {
+               _cpMin = start;
+       }
+    }
+
 
     // using the PieceDescriptors, build our list of TextPieces.
     for (int x = 0; x < pieces.length; x++)
@@ -93,6 +105,15 @@ public class TextPieceTable
       // And now build the piece
       _textPieces.add(new TextPiece(nodeStartChars, nodeEndChars, buf, pieces[x], node.getStart()));
     }
+    
+    // In the interest of our sanity, now sort the text pieces
+    //  into order, if they're not already
+    TextPiece[] tp = (TextPiece[])
+       _textPieces.toArray(new TextPiece[_textPieces.size()]);
+    Arrays.sort(tp);
+    for(int i=0; i<tp.length; i++) {
+       _textPieces.set(i, tp[i]);
+    }
   }
 
   public int getCpMin()
@@ -104,6 +125,62 @@ public class TextPieceTable
   {
     return _textPieces;
   }
+  
+  /**
+   * Is the text at the given Character offset
+   *  unicode, or plain old ascii?
+   * In a very evil fashion, you have to actually 
+   *  know this to make sense of character and
+   *  paragraph properties :(
+   * @param cp The character offset to check about
+   */
+  public boolean isUnicodeAtCharOffset(int cp) {
+         boolean lastWas = false;
+         
+         Iterator it = _textPieces.iterator();
+         while(it.hasNext()) {
+                 TextPiece tp = (TextPiece)it.next();
+                 // If the text piece covers the character, all good
+                 if(tp.getStart() <= cp && tp.getEnd() >= cp) {
+                         return tp.isUnicode();
+                 }
+                 // Otherwise keep track for the last one
+                 lastWas = tp.isUnicode();
+         }
+         
+         // If they ask off the end, just go with the last one...
+         return lastWas;
+  }
+  /**
+   * Is the text at the given byte offset
+   *  unicode, or plain old ascii?
+   * In a very evil fashion, you have to actually 
+   *  know this to make sense of character and
+   *  paragraph properties :(
+   * @param cp The character offset to check about
+   */
+  public boolean isUnicodeAtByteOffset(int bytePos) {
+         boolean lastWas = false;
+         int curByte = 0;
+         
+         Iterator it = _textPieces.iterator();
+         while(it.hasNext()) {
+                 TextPiece tp = (TextPiece)it.next();
+                 int nextByte = curByte + tp.bytesLength();
+                 
+                 // If the text piece covers the character, all good
+                 if(curByte <= bytePos && nextByte >= bytePos) {
+                         return tp.isUnicode();
+                 }
+                 // Otherwise keep track for the last one
+                 lastWas = tp.isUnicode();
+                 // Move along
+                 curByte = nextByte;
+         }
+         
+         // If they ask off the end, just go with the last one...
+         return lastWas;
+  }
 
   public byte[] writeTo(HWPFOutputStream docStream)
     throws IOException
index 6615823281e10f71396285ac0f677ae0200797e5..63961b455222c33dc76fe785a8e11745c332ec29 100644 (file)
@@ -70,10 +70,10 @@ public abstract class FIBAbstractType
         private static BitField  fFutureSavedUndo = BitFieldFactory.getInstance(0x0008);
         private static BitField  fWord97Saved = BitFieldFactory.getInstance(0x0010);
         private static BitField  fSpare0 = BitFieldFactory.getInstance(0x00FE);
-    protected  int field_11_chs;
-    protected  int field_12_chsTables;
-    protected  int field_13_fcMin;
-    protected  int field_14_fcMac;
+    protected  int field_11_chs;       /** Latest docs say this is Reserved3! */
+    protected  int field_12_chsTables; /** Latest docs say this is Reserved4! */
+    protected  int field_13_fcMin;     /** Latest docs say this is Reserved5! */
+    protected  int field_14_fcMac;     /** Latest docs say this is Reserved6! */
 
 
     public FIBAbstractType()
index 109fd175b4f301c3852a0719697f73c490c4cad0..0a145d5fd43130d68ca399d99a1f8a2b911605d1 100644 (file)
@@ -155,6 +155,8 @@ public class Range
     _characters = _doc.getCharacterTable().getTextRuns();
     _text = _doc.getTextTable().getTextPieces();
     _parent = new WeakReference(null);
+    
+    sanityCheckStartEnd();
   }
 
 
@@ -175,6 +177,8 @@ public class Range
     _characters = parent._characters;
     _text = parent._text;
     _parent = new WeakReference(parent);
+    
+    sanityCheckStartEnd();
   }
 
   /**
@@ -226,6 +230,22 @@ public class Range
         _textRangeFound = true;
         break;
     }
+    
+    sanityCheckStartEnd();
+  }
+  
+  /**
+   * Ensures that the start and end were were given
+   *  are actually valid, to avoid issues later on
+   *  if they're not
+   */
+  private void sanityCheckStartEnd() {
+         if(_start < 0) {
+                 throw new IllegalArgumentException("Range start must not be negative. Given " + _start);
+         }
+         if(_end < _start) {
+                 throw new IllegalArgumentException("The end (" + _end + ") must not be before the start ("+_start+")");
+         }
   }
 
   /**
@@ -537,13 +557,17 @@ public class Range
     for (int x = _parStart; x < numParagraphs; x++)
     {
       PAPX papx = (PAPX)_paragraphs.get(x);
+      //System.err.println("Paragraph " + x + " was " + papx.getStart() + " -> " + papx.getEnd());
       papx.adjustForDelete(_start, _end - _start);
+      //System.err.println("Paragraph " + x + " is now " + papx.getStart() + " -> " + papx.getEnd());
     }
 
     for (int x = _sectionStart; x < numSections; x++)
     {
       SEPX sepx = (SEPX)_sections.get(x);
+      //System.err.println("Section " + x + " was " + sepx.getStart() + " -> " + sepx.getEnd());
       sepx.adjustForDelete(_start, _end - _start);
+      //System.err.println("Section " + x + " is now " + sepx.getStart() + " -> " + sepx.getEnd());
     }
     
     for (int x = _textStart; x < numTextPieces; x++)
@@ -650,14 +674,6 @@ public class Range
                 absPlaceHolderIndex, 
                                (absPlaceHolderIndex + pPlaceHolder.length()), getDocument()
     );
-    if (subRange.usesUnicode()) {
-                       absPlaceHolderIndex = getStartOffset() + (pOffset * 2);
-            subRange = new Range(
-                      absPlaceHolderIndex, 
-                      (absPlaceHolderIndex + (pPlaceHolder.length() * 2)), 
-                                         getDocument()
-            );
-    }
 
        // this Range isn't a proper parent of the subRange() so we'll have to keep
        // track of an updated endOffset on our own
@@ -674,12 +690,6 @@ public class Range
             (absPlaceHolderIndex + pPlaceHolder.length() + pValue.length()), 
                        getDocument()
     );
-    if (subRange.usesUnicode())
-            subRange = new Range(
-                      (absPlaceHolderIndex + (pValue.length() * 2)),
-                      (absPlaceHolderIndex + (pPlaceHolder.length() * 2) + 
-                                         (pValue.length() * 2)), getDocument()
-            );
 
        // deletes are automagically propagated
     subRange.delete();
@@ -820,6 +830,10 @@ public class Range
     {
       throw new ArrayIndexOutOfBoundsException("The table's bounds fall outside of this Range");
     }
+    if (tableEnd < 0)
+    {
+      throw new ArrayIndexOutOfBoundsException("The table's end is negative, which isn't allowed!");
+    }
     return new Table(r._parStart, tableEnd, r._doc.getRange(), paragraph.getTableLevel());
   }
 
index 07e8bfbf910e0b4ec369f3aa1d6b398b0cfdb003..d1f1451acd34a52794cc624ce09d0e1b97996024 100644 (file)
@@ -32,6 +32,8 @@ public class TestCHPBinTable
 {
   private CHPBinTable _cHPBinTable = null;
   private HWPFDocFixture _hWPFDocFixture;
+  
+  private TextPieceTable fakeTPT = new TextPieceTable();
 
   public TestCHPBinTable(String name)
   {
@@ -46,7 +48,7 @@ public class TestCHPBinTable
     byte[] tableStream = _hWPFDocFixture._tableStream;
     int fcMin = fib.getFcMin();
 
-    _cHPBinTable = new CHPBinTable(mainStream, tableStream, fib.getFcPlcfbteChpx(), fib.getLcbPlcfbteChpx(), fcMin);
+    _cHPBinTable = new CHPBinTable(mainStream, tableStream, fib.getFcPlcfbteChpx(), fib.getLcbPlcfbteChpx(), fcMin, fakeTPT);
 
     HWPFFileSystem fileSys = new HWPFFileSystem();
 
@@ -57,7 +59,7 @@ public class TestCHPBinTable
     byte[] newTableStream = tableOut.toByteArray();
     byte[] newMainStream = mainOut.toByteArray();
 
-    CHPBinTable newBinTable = new CHPBinTable(newMainStream, newTableStream, 0, newTableStream.length, 0);
+    CHPBinTable newBinTable = new CHPBinTable(newMainStream, newTableStream, 0, newTableStream.length, 0, fakeTPT);
 
     ArrayList oldTextRuns = _cHPBinTable._textRuns;
     ArrayList newTextRuns = newBinTable._textRuns;
index 4358cdef0973e35b4bbf901995cf08503851694a..446b5232a5a203fc358a4476db344a09860f84c2 100644 (file)
@@ -32,6 +32,8 @@ public class TestPAPBinTable
   private PAPBinTable _pAPBinTable = null;
   private HWPFDocFixture _hWPFDocFixture;
 
+  private TextPieceTable fakeTPT = new TextPieceTable();
+
   public TestPAPBinTable(String name)
   {
     super(name);
@@ -45,7 +47,7 @@ public class TestPAPBinTable
     byte[] tableStream = _hWPFDocFixture._tableStream;
     int fcMin = fib.getFcMin();
 
-    _pAPBinTable = new PAPBinTable(mainStream, tableStream, null, fib.getFcPlcfbtePapx(), fib.getLcbPlcfbtePapx(), fcMin);
+    _pAPBinTable = new PAPBinTable(mainStream, tableStream, null, fib.getFcPlcfbtePapx(), fib.getLcbPlcfbtePapx(), fcMin, fakeTPT);
 
     HWPFFileSystem fileSys = new HWPFFileSystem();
 
@@ -56,7 +58,7 @@ public class TestPAPBinTable
     byte[] newTableStream = tableOut.toByteArray();
     byte[] newMainStream = mainOut.toByteArray();
 
-    PAPBinTable newBinTable = new PAPBinTable(newMainStream, newTableStream, null,0, newTableStream.length, 0);
+    PAPBinTable newBinTable = new PAPBinTable(newMainStream, newTableStream, null,0, newTableStream.length, 0, fakeTPT);
 
     ArrayList oldTextRuns = _pAPBinTable.getParagraphs();
     ArrayList newTextRuns = newBinTable.getParagraphs();
index 0912daaf744edafcf61f1f83d2b42777d78b602d..2f5ad1ccbc78415d64df80cad0f773d382594101 100644 (file)
@@ -45,13 +45,15 @@ public class TestSectionTable
     byte[] tableStream = _hWPFDocFixture._tableStream;
     int fcMin = fib.getFcMin();
 
+    CPSplitCalculator cps = new CPSplitCalculator(fib);
+    
     ComplexFileTable cft = new ComplexFileTable(mainStream, tableStream, fib.getFcClx(), fcMin);
     TextPieceTable tpt = cft.getTextPieceTable();
 
     SectionTable sectionTable = new SectionTable(mainStream, tableStream,
                                                  fib.getFcPlcfsed(),
                                                  fib.getLcbPlcfsed(),
-                                                 fcMin, tpt.getTextPieces());
+                                                 fcMin, tpt, cps);
     HWPFFileSystem fileSys = new HWPFFileSystem();
 
     sectionTable.writeTo(fileSys, 0);
@@ -61,7 +63,9 @@ public class TestSectionTable
     byte[] newTableStream = tableOut.toByteArray();
     byte[] newMainStream = mainOut.toByteArray();
 
-    SectionTable newSectionTable = new SectionTable(newMainStream, newTableStream, 0, newTableStream.length, 0, tpt.getTextPieces());
+    SectionTable newSectionTable = new SectionTable(
+               newMainStream, newTableStream, 0, 
+               newTableStream.length, 0, tpt, cps);
 
     ArrayList oldSections = sectionTable.getSections();
     ArrayList newSections = newSectionTable.getSections();
index 764b3239dcd46c0759cf418c18f462c550402188..db28cbd45609294da86be9dce1b17f10799f2d02 100644 (file)
@@ -81,9 +81,16 @@ public class TestProblems extends TestCase {
        HWPFDocument doc = new HWPFDocument(new FileInputStream(
                        new File(dirname, "Bug44292.doc")));
                Range r = doc.getRange();
+               assertEquals(6, r.numParagraphs());
+               assertEquals(0, r.getStartOffset());
+               assertEquals(87, r.getEndOffset());
                        
-               //get the table
+               // Paragraph with table
                Paragraph p = r.getParagraph(0);
+               assertEquals(0, p.getStartOffset());
+               assertEquals(20, p.getEndOffset());
+               
+               // Get the table
                Table t = r.getTable(p);
                
                //get the only row
index 2994b6332d32e513b59667676164a9078e58bff8..4adc5b9cf8e08dddc6c32b622f8039bb2ac3a673 100644 (file)
 
 package org.apache.poi.hwpf.usermodel;
 
-import java.io.ByteArrayOutputStream;
 import java.io.FileInputStream;
-import java.util.List;
-
-import org.apache.poi.hwpf.HWPFDocument;
-import org.apache.poi.hwpf.model.PicturesTable;
-import org.apache.poi.hwpf.usermodel.Picture;
 
 import junit.framework.TestCase;
 
+import org.apache.poi.hwpf.HWPFDocument;
+import org.apache.poi.hwpf.model.PAPX;
+
 /**
  *     Test to see if Range.delete() works even if the Range contains a
  *     CharacterRun that uses Unicode characters.
- *
- * TODO - re-enable me when unicode paragraph stuff is fixed!
  */
-public abstract class TestRangeDelete extends TestCase {
+public class TestRangeDelete extends TestCase {
 
        // u201c and u201d are "smart-quotes"
+       private String introText = 
+               "Introduction\r";
+       private String fillerText = 
+               "${delete} This is an MS-Word 97 formatted document created using NeoOffice v. 2.2.4 Patch 0 (OpenOffice.org v. 2.2.1).\r";
        private String originalText =
                "It is used to confirm that text delete works even if Unicode characters (such as \u201c\u2014\u201d (U+2014), \u201c\u2e8e\u201d (U+2E8E), or \u201c\u2714\u201d (U+2714)) are present.  Everybody should be thankful to the ${organization} ${delete} and all the POI contributors for their assistance in this matter.\r";
+       private String lastText =
+               "Thank you, ${organization} ${delete}!\r";
        private String searchText = "${delete}";
        private String expectedText1 = " This is an MS-Word 97 formatted document created using NeoOffice v. 2.2.4 Patch 0 (OpenOffice.org v. 2.2.1).\r";
        private String expectedText2 =
@@ -68,32 +69,63 @@ public abstract class TestRangeDelete extends TestCase {
        public void testDocStructure() throws Exception {
 
                HWPFDocument daDoc = new HWPFDocument(new FileInputStream(illustrativeDocFile));
+               Range range;
+               Section section;
+               Paragraph para;
+               PAPX paraDef;
 
-               Range range = daDoc.getOverallRange();
-
+               // First, check overall
+               range = daDoc.getOverallRange();
                assertEquals(1, range.numSections());
-               Section section = range.getSection(0);
-
-               assertEquals(5, section.numParagraphs());
-               Paragraph para = section.getParagraph(2);
-
-               assertEquals(5, para.numCharacterRuns());
-
-               assertEquals(originalText, para.text());
+               assertEquals(5, range.numParagraphs());
                
                
-               // Now check on just the main text
+               // Now, onto just the doc bit
                range = daDoc.getRange();
-               
+
                assertEquals(1, range.numSections());
+               assertEquals(1, daDoc.getSectionTable().getSections().size());
                section = range.getSection(0);
-
+               
                assertEquals(5, section.numParagraphs());
+               
+               para = section.getParagraph(0);
+               assertEquals(1, para.numCharacterRuns());
+               assertEquals(introText, para.text());
+               
+               para = section.getParagraph(1);
+               assertEquals(5, para.numCharacterRuns());
+               assertEquals(fillerText, para.text());
+               
+               
+               paraDef = (PAPX)daDoc.getParagraphTable().getParagraphs().get(2);
+               assertEquals(132, paraDef.getStart());
+               assertEquals(400, paraDef.getEnd());
+               
                para = section.getParagraph(2);
-
                assertEquals(5, para.numCharacterRuns());
-
                assertEquals(originalText, para.text());
+               
+               
+               paraDef = (PAPX)daDoc.getParagraphTable().getParagraphs().get(3);
+               assertEquals(400, paraDef.getStart());
+               assertEquals(438, paraDef.getEnd());
+               
+               para = section.getParagraph(3);
+               assertEquals(1, para.numCharacterRuns());
+               assertEquals(lastText, para.text());
+               
+               
+               // Check things match on text length
+               assertEquals(439, range.text().length());
+               assertEquals(439, section.text().length());
+               assertEquals(439, 
+                               section.getParagraph(0).text().length() +
+                               section.getParagraph(1).text().length() +
+                               section.getParagraph(2).text().length() +
+                               section.getParagraph(3).text().length() +
+                               section.getParagraph(4).text().length()
+               );
        }
 
        /**
@@ -118,12 +150,7 @@ public abstract class TestRangeDelete extends TestCase {
                assertEquals(192, offset);
 
                int absOffset = para.getStartOffset() + offset;
-               if (para.usesUnicode())
-                       absOffset = para.getStartOffset() + (offset * 2);
-
                Range subRange = new Range(absOffset, (absOffset + searchText.length()), para.getDocument());
-               if (subRange.usesUnicode())
-                       subRange = new Range(absOffset, (absOffset + (searchText.length() * 2)), para.getDocument());
 
                assertEquals(searchText, subRange.text());
 
@@ -167,26 +194,23 @@ public abstract class TestRangeDelete extends TestCase {
 
                boolean keepLooking = true;
                while (keepLooking) {
-
+                       // Reload the range every time
+                       range = daDoc.getRange();
                        int offset = range.text().indexOf(searchText);
                        if (offset >= 0) {
 
                                int absOffset = range.getStartOffset() + offset;
-                               if (range.usesUnicode())
-                                       absOffset = range.getStartOffset() + (offset * 2);
 
                                Range subRange = new Range(
                                        absOffset, (absOffset + searchText.length()), range.getDocument());
-                               if (subRange.usesUnicode())
-                                       subRange = new Range(
-                                               absOffset, (absOffset + (searchText.length() * 2)), range.getDocument());
 
                                assertEquals(searchText, subRange.text());
 
                                subRange.delete();
 
-                       } else
+                       } else {
                                keepLooking = false;
+                       }
                }
 
                // we need to let the model re-calculate the Range before we use it
@@ -197,6 +221,10 @@ public abstract class TestRangeDelete extends TestCase {
 
                assertEquals(5, section.numParagraphs());
 
+               para = section.getParagraph(0);
+               text = para.text();
+               assertEquals(introText, text);
+
                para = section.getParagraph(1);
                text = para.text();
                assertEquals(expectedText1, text);
index 5f21508c9a3cea952ac02e94e4b587d6ea004c38..a520b953f7e3fbe1f79964a89e9f64edf749e8f5 100644 (file)
 
 package org.apache.poi.hwpf.usermodel;
 
-import java.io.ByteArrayOutputStream;
 import java.io.FileInputStream;
-import java.util.List;
-
-import org.apache.poi.hwpf.HWPFDocument;
-import org.apache.poi.hwpf.model.PicturesTable;
-import org.apache.poi.hwpf.usermodel.Picture;
 
 import junit.framework.TestCase;
 
+import org.apache.poi.hwpf.HWPFDocument;
+
 /**
  *     Test to see if Range.insertBefore() works even if the Range contains a
  *     CharacterRun that uses Unicode characters.
  *
  * TODO - re-enable me when unicode paragraph stuff is fixed!
  */
-public abstract class TestRangeInsertion extends TestCase {
+public class TestRangeInsertion extends TestCase {
 
        // u201c and u201d are "smart-quotes"
        private String originalText =
                "It is used to confirm that text insertion works even if Unicode characters (such as \u201c\u2014\u201d (U+2014), \u201c\u2e8e\u201d (U+2E8E), or \u201c\u2714\u201d (U+2714)) are present.\r";
        private String textToInsert = "Look at me!  I'm cool!  ";
-       private int insertionPoint = 244;
+       private int insertionPoint = 122;
 
        private String illustrativeDocFile;
 
@@ -73,12 +69,18 @@ public abstract class TestRangeInsertion extends TestCase {
 
                assertEquals(3, section.numParagraphs());
                Paragraph para = section.getParagraph(2);
+               assertEquals(originalText, para.text());
 
                assertEquals(3, para.numCharacterRuns());
-               String text = para.getCharacterRun(0).text() + para.getCharacterRun(1).text() +
-                       para.getCharacterRun(2).text();
+               String text = 
+                       para.getCharacterRun(0).text() + 
+                       para.getCharacterRun(1).text() +
+                       para.getCharacterRun(2).text()
+               ;
 
                assertEquals(originalText, text);
+               
+               assertEquals(insertionPoint, para.getStartOffset());
        }
 
        /**
@@ -109,10 +111,14 @@ public abstract class TestRangeInsertion extends TestCase {
 
                assertEquals(3, section.numParagraphs());
                Paragraph para = section.getParagraph(2);
+               assertEquals((textToInsert + originalText), para.text());
 
                assertEquals(3, para.numCharacterRuns());
-               String text = para.getCharacterRun(0).text() + para.getCharacterRun(1).text() +
-                       para.getCharacterRun(2).text();
+               String text = 
+                       para.getCharacterRun(0).text() + 
+                       para.getCharacterRun(1).text() +
+                       para.getCharacterRun(2).text()
+               ;
 
                // System.out.println(text);
 
index 1f0aad5aa5d9afd4ced4f807cfa8f517cc5cb1c7..1578ebdaf00bac09dd670be34d5987519093e7ab 100644 (file)
@@ -18,8 +18,10 @@ package org.apache.poi.hwpf.usermodel;
 
 import java.io.File;
 import java.io.FileInputStream;
+import java.util.List;
 
 import org.apache.poi.hwpf.HWPFDocument;
+import org.apache.poi.hwpf.model.PropertyNode;
 
 import junit.framework.TestCase;
 
@@ -30,7 +32,7 @@ import junit.framework.TestCase;
  *
  * TODO - re-enable me when unicode paragraph stuff is fixed!
  */
-public abstract class TestRangeProperties extends TestCase {
+public class TestRangeProperties extends TestCase {
        private static final char page_break = (char)12;
        
        private static final String u_page_1 =
@@ -85,6 +87,16 @@ public abstract class TestRangeProperties extends TestCase {
                                r.text()
                );
                
+               assertEquals(1, r.numSections());
+               assertEquals(1, a.getSectionTable().getSections().size());
+               Section s = r.getSection(0);
+               assertEquals(
+                               a_page_1 +
+                               page_break + "\r" + 
+                               a_page_2,
+                               s.text()
+               );
+               
                assertEquals(
                                7,
                                r.numParagraphs()
@@ -142,8 +154,102 @@ public abstract class TestRangeProperties extends TestCase {
                assertEquals(22, c1.getFontSize());
                assertEquals(32, c7.getFontSize());
        }
+
+       /**
+        * Tests the raw definitions of the paragraphs of
+        *  a unicode document
+        */
+       public void testUnicodeParagraphDefinitions() throws Exception {
+               Range r = u.getRange();
+               String[] p1_parts = u_page_1.split("\r");
+               String[] p2_parts = u_page_2.split("\r");
+               
+               assertEquals(
+                               u_page_1 + page_break + "\r" + u_page_2,
+                               r.text()
+               );
+               assertEquals(
+                               408, r.text().length()
+               );
        
+               
+               assertEquals(1, r.numSections());
+               assertEquals(1, u.getSectionTable().getSections().size());
+               Section s = r.getSection(0);
+               assertEquals(
+                               u_page_1 +
+                               page_break + "\r" + 
+                               u_page_2,
+                               s.text()
+               );
+               assertEquals(0, s.getStartOffset());
+               assertEquals(408, s.getEndOffset());
 
+               
+               List pDefs = r._paragraphs;
+               assertEquals(35, pDefs.size());
+               
+               // Check that the last paragraph ends where it should do
+               assertEquals(531, u.getOverallRange().text().length());
+               assertEquals(530, u.getCPSplitCalculator().getHeaderTextboxEnd());
+               PropertyNode pLast = (PropertyNode)pDefs.get(34);
+//             assertEquals(530, pLast.getEnd());
+               
+               // Only care about the first few really though
+               PropertyNode p0 = (PropertyNode)pDefs.get(0);
+               PropertyNode p1 = (PropertyNode)pDefs.get(1);
+               PropertyNode p2 = (PropertyNode)pDefs.get(2);
+               PropertyNode p3 = (PropertyNode)pDefs.get(3);
+               PropertyNode p4 = (PropertyNode)pDefs.get(4);
+               
+               // 5 paragraphs should get us to the end of our text
+               assertTrue(p0.getStart() < 408);
+               assertTrue(p0.getEnd() < 408);
+               assertTrue(p1.getStart() < 408);
+               assertTrue(p1.getEnd() < 408);
+               assertTrue(p2.getStart() < 408);
+               assertTrue(p2.getEnd() < 408);
+               assertTrue(p3.getStart() < 408);
+               assertTrue(p3.getEnd() < 408);
+               assertTrue(p4.getStart() < 408);
+               assertTrue(p4.getEnd() < 408);
+               
+               // Paragraphs should match with lines
+               assertEquals(
+                               0,
+                               p0.getStart()
+               );
+               assertEquals(
+                               p1_parts[0].length() + 1,
+                               p0.getEnd()
+               );
+               
+               assertEquals(
+                               p1_parts[0].length() + 1,
+                               p1.getStart()
+               );              
+               assertEquals(
+                               p1_parts[0].length() + 1 +
+                               p1_parts[1].length() + 1,
+                               p1.getEnd()
+               );
+               
+               assertEquals(
+                               p1_parts[0].length() + 1 +
+                               p1_parts[1].length() + 1,
+                               p2.getStart()
+               );
+               assertEquals(
+                               p1_parts[0].length() + 1 +
+                               p1_parts[1].length() + 1 +
+                               p1_parts[2].length() + 1,
+                               p2.getEnd()
+               );
+       }
+
+       /**
+        * Tests the paragraph text of a unicode document
+        */
        public void testUnicodeTextParagraphs() throws Exception {
                Range r = u.getRange();
                assertEquals(
@@ -154,16 +260,112 @@ public abstract class TestRangeProperties extends TestCase {
                );
                
                assertEquals(
-                               5,
+                               12,
                                r.numParagraphs()
                );
                String[] p1_parts = u_page_1.split("\r");
                String[] p2_parts = u_page_2.split("\r");
                
-               System.out.println(r.getParagraph(2).text());
-               // TODO
+               // Check text all matches up properly
+               assertEquals(p1_parts[0] + "\r", r.getParagraph(0).text());
+               assertEquals(p1_parts[1] + "\r", r.getParagraph(1).text());
+               assertEquals(p1_parts[2] + "\r", r.getParagraph(2).text());
+               assertEquals(p1_parts[3] + "\r", r.getParagraph(3).text());
+               assertEquals(p1_parts[4] + "\r", r.getParagraph(4).text());
+               assertEquals(p1_parts[5] + "\r", r.getParagraph(5).text());
+               assertEquals(p1_parts[6] + "\r", r.getParagraph(6).text());
+               assertEquals(p1_parts[7] + "\r", r.getParagraph(7).text());
+               assertEquals(p1_parts[8] + "\r", r.getParagraph(8).text());
+               assertEquals(p1_parts[9] + "\r", r.getParagraph(9).text());
+               assertEquals(page_break + "\r", r.getParagraph(10).text());
+               assertEquals(p2_parts[0] + "\r", r.getParagraph(11).text());
        }
        public void testUnicodeStyling() throws Exception {
-               // TODO
+               Range r = u.getRange();
+               String[] p1_parts = u_page_1.split("\r");
+               
+               Paragraph p1 = r.getParagraph(0);
+               Paragraph p7 = r.getParagraph(6);
+               
+               // Line ending in its own run each time!
+               assertEquals(2, p1.numCharacterRuns());
+               assertEquals(2, p7.numCharacterRuns());
+               
+               CharacterRun c1a = p1.getCharacterRun(0);
+               CharacterRun c1b = p1.getCharacterRun(1);
+               CharacterRun c7a = p7.getCharacterRun(0);
+               CharacterRun c7b = p7.getCharacterRun(1);
+               
+               assertEquals("Times New Roman", c1a.getFontName()); // No Calibri
+               assertEquals(22, c1a.getFontSize());
+               
+               assertEquals("Times New Roman", c1b.getFontName()); // No Calibri
+               assertEquals(22, c1b.getFontSize());
+               
+               assertEquals("Times New Roman", c7a.getFontName());
+               assertEquals(48, c7a.getFontSize());
+               
+               assertEquals("Times New Roman", c7b.getFontName());
+               assertEquals(48, c7b.getFontSize());
+               
+               // Now check where they crop up
+               assertEquals(
+                               0, 
+                               c1a.getStartOffset()
+               );
+               assertEquals(
+                               p1_parts[0].length(), 
+                               c1a.getEndOffset()
+               );
+               
+               assertEquals(
+                               p1_parts[0].length(), 
+                               c1b.getStartOffset()
+               );
+               assertEquals(
+                               p1_parts[0].length()+1, 
+                               c1b.getEndOffset()
+               );
+               
+               assertEquals(
+                               p1_parts[0].length() + 1 + 
+                               p1_parts[1].length() + 1 + 
+                               p1_parts[2].length() + 1 + 
+                               p1_parts[3].length() + 1 + 
+                               p1_parts[4].length() + 1 + 
+                               p1_parts[5].length() + 1, 
+                               c7a.getStartOffset()
+               );
+               assertEquals(
+                               p1_parts[0].length() + 1 + 
+                               p1_parts[1].length() + 1 + 
+                               p1_parts[2].length() + 1 + 
+                               p1_parts[3].length() + 1 + 
+                               p1_parts[4].length() + 1 + 
+                               p1_parts[5].length() + 1 +
+                               1,
+                               c7a.getEndOffset()
+               );
+               
+               assertEquals(
+                               p1_parts[0].length() + 1 + 
+                               p1_parts[1].length() + 1 + 
+                               p1_parts[2].length() + 1 + 
+                               p1_parts[3].length() + 1 + 
+                               p1_parts[4].length() + 1 + 
+                               p1_parts[5].length() + 1 +
+                               1, 
+                               c7b.getStartOffset()
+               );
+               assertEquals(
+                               p1_parts[0].length() + 1 + 
+                               p1_parts[1].length() + 1 + 
+                               p1_parts[2].length() + 1 + 
+                               p1_parts[3].length() + 1 + 
+                               p1_parts[4].length() + 1 + 
+                               p1_parts[5].length() + 1 +
+                               p1_parts[6].length() + 1,
+                               c7b.getEndOffset()
+               );
        }
 }
index 67aea65be996f616ed2dad316503a7310b01ac63..7c47668445ccc836038b43a474fd74ff98fa5263 100644 (file)
 
 package org.apache.poi.hwpf.usermodel;
 
-import java.io.ByteArrayOutputStream;
 import java.io.FileInputStream;
-import java.util.List;
-
-import org.apache.poi.hwpf.HWPFDocument;
-import org.apache.poi.hwpf.model.PicturesTable;
-import org.apache.poi.hwpf.usermodel.Picture;
 
 import junit.framework.TestCase;
 
+import org.apache.poi.hwpf.HWPFDocument;
+
 /**
  *     Test to see if Range.replaceText() works even if the Range contains a
  *     CharacterRun that uses Unicode characters.
  *
  * TODO - re-enable me when unicode paragraph stuff is fixed!
  */
-public abstract class TestRangeReplacement extends TestCase {
+public class TestRangeReplacement extends TestCase {
 
        // u201c and u201d are "smart-quotes"
        private String originalText =
@@ -70,16 +66,23 @@ public abstract class TestRangeReplacement extends TestCase {
                HWPFDocument daDoc = new HWPFDocument(new FileInputStream(illustrativeDocFile));
 
                Range range = daDoc.getRange();
+               assertEquals(414, range.text().length());
 
                assertEquals(1, range.numSections());
                Section section = range.getSection(0);
+               assertEquals(414, section.text().length());
 
                assertEquals(5, section.numParagraphs());
                Paragraph para = section.getParagraph(2);
 
                assertEquals(5, para.numCharacterRuns());
-               String text = para.getCharacterRun(0).text() + para.getCharacterRun(1).text() +
-                       para.getCharacterRun(2).text() + para.getCharacterRun(3).text() + para.getCharacterRun(4).text();
+               String text = 
+                       para.getCharacterRun(0).text() + 
+                       para.getCharacterRun(1).text() +
+                       para.getCharacterRun(2).text() +
+                       para.getCharacterRun(3).text() +
+                       para.getCharacterRun(4).text()
+               ;
 
                assertEquals(originalText, text);
        }
index eba6607ade6da210856ebd818f93e1676e9ce275..aa08040fcd2f61d67e37fab37d75a4b97e6dea7d 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
diff --git a/src/testcases/org/apache/poi/hssf/data/testNames.xls b/src/testcases/org/apache/poi/hssf/data/testNames.xls
new file mode 100644 (file)
index 0000000..7ebbb63
Binary files /dev/null and b/src/testcases/org/apache/poi/hssf/data/testNames.xls differ
index e1909baa0a9cc6d661f524f58694fe88d774846d..3584e37ea4e41f0c1ac230857ad3a34976f4c539 100644 (file)
@@ -20,6 +20,7 @@ package org.apache.poi.hssf.model;
 import junit.framework.AssertionFailedError;
 import junit.framework.TestCase;
 
+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;
@@ -123,12 +124,15 @@ public final class TestFormulaParser extends TestCase {
        }
 
        public void testMacroFunction() {
-               HSSFWorkbook w = new HSSFWorkbook();
-               Ptg[] ptg = FormulaParser.parse("FOO()", w);
+               // testNames.xls contains a VB function called 'myFunc'
+               HSSFWorkbook w = HSSFTestDataSamples.openSampleWorkbook("testNames.xls");
+
+               Ptg[] ptg = FormulaParser.parse("myFunc()", w);
+               // myFunc() actually takes 1 parameter.  Don't know if POI will ever be able to detect this problem
 
                // the name gets encoded as the first arg
                NamePtg tname = (NamePtg) ptg[0];
-               assertEquals("FOO", tname.toFormulaString(w));
+               assertEquals("myFunc", tname.toFormulaString(w));
 
                AbstractFunctionPtg tfunc = (AbstractFunctionPtg) ptg[1];
                assertTrue(tfunc.isExternalFunction());
index 6d35dcdec037be93158f4bb3f10a6a84e2b0e896..2e393d6107c262a63eacef96bad1ab3c87a3c99a 100755 (executable)
 
 package org.apache.poi.hssf.record.formula;
 
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
 import junit.framework.TestCase;
 
 import org.apache.poi.hssf.HSSFTestDataSamples;
+import org.apache.poi.hssf.model.FormulaParser;
+import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
 import org.apache.poi.hssf.usermodel.HSSFSheet;
 import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.usermodel.FormulaEvaluator.CellValue;
 /**
  * Tests for functions from external workbooks (e.g. YEARFRAC).
  * 
@@ -30,17 +38,45 @@ import org.apache.poi.hssf.usermodel.HSSFWorkbook;
  */
 public final class TestExternalFunctionFormulas extends TestCase {
 
-    
-    /**
-     * tests <tt>NameXPtg.toFormulaString(Workbook)</tt> and logic in Workbook below that   
-     */
-    public void testReadFormulaContainingExternalFunction() {
-        HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("externalFunctionExample.xls");
-        
-        String expectedFormula = "YEARFRAC(B1,C1)";
-        HSSFSheet sht = wb.getSheetAt(0);
-        String cellFormula = sht.getRow(0).getCell((short)0).getCellFormula();
-        assertEquals(expectedFormula, cellFormula);
-    }
-    
+       /**
+        * tests <tt>NameXPtg.toFormulaString(Workbook)</tt> and logic in Workbook below that   
+        */
+       public void testReadFormulaContainingExternalFunction() {
+               HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("externalFunctionExample.xls");
+               
+               String expectedFormula = "YEARFRAC(B1,C1)";
+               HSSFSheet sht = wb.getSheetAt(0);
+               String cellFormula = sht.getRow(0).getCell(0).getCellFormula();
+               assertEquals(expectedFormula, cellFormula);
+       }
+       
+       public void testParse() {
+               HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("externalFunctionExample.xls");
+               Ptg[] ptgs = FormulaParser.parse("YEARFRAC(B1,C1)", wb);
+               assertEquals(4, ptgs.length);
+               assertEquals(NameXPtg.class, ptgs[0].getClass());
+               
+               wb.getSheetAt(0).getRow(0).createCell(6).setCellFormula("YEARFRAC(C1,B1)");
+               if (false) {
+                       // In case you fancy checking in excel
+                       try {
+                               File tempFile = File.createTempFile("testExtFunc", ".xls");
+                               FileOutputStream fout = new FileOutputStream(tempFile);
+                               wb.write(fout);
+                               fout.close();
+                               System.out.println("check out " + tempFile.getAbsolutePath());
+                       } catch (IOException e) {
+                               throw new RuntimeException(e);
+                       }
+               }
+       }
+       
+       public void DISABLEDtestEvaluate() {
+               HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("externalFunctionExample.xls");
+               HSSFSheet sheet = wb.getSheetAt(0);
+               HSSFCell cell = sheet.getRow(0).getCell(0);
+               HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(sheet, wb);
+               CellValue evalResult = fe.evaluate(cell);
+               evalResult.toString();
+       }
 }
index 9e6c7bce6ad27ae0ed8861ee3c1ff6a9dd87eb74..e1bed55c516a247d6e11a777cc6fed525c05bc43 100755 (executable)
 
 package org.apache.poi.hssf.record.formula.eval;
 
+import java.io.IOException;
+
 import junit.framework.TestCase;
 
+import org.apache.poi.hssf.HSSFTestDataSamples;
 import org.apache.poi.hssf.usermodel.HSSFCell;
 import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
 import org.apache.poi.hssf.usermodel.HSSFName;
@@ -34,20 +37,33 @@ public final class TestExternalFunction extends TestCase {
 
        /**
         * Checks that an external function can get invoked from the formula evaluator. 
+        * @throws IOException 
+
         */
        public void testInvoke() {
-        HSSFWorkbook wb = new HSSFWorkbook();
-        HSSFSheet sheet = wb.createSheet();
-        wb.setSheetName(0, "Sheet1");
-        HSSFRow row = sheet.createRow(0);
-        HSSFCell cell = row.createCell(0);
-
-        HSSFName hssfName = wb.createName();
-        hssfName.setNameName("myFunc");
-        
-        cell.setCellFormula("myFunc()");
-        String actualFormula=cell.getCellFormula();
-        assertEquals("myFunc()", actualFormula);
+               
+               HSSFWorkbook wb;
+               HSSFSheet sheet;
+               HSSFCell cell;
+               if (false) {
+                       // TODO - this code won't work until we can create user-defined functions directly with POI
+                       wb = new HSSFWorkbook();
+                       sheet = wb.createSheet();
+                       wb.setSheetName(0, "Sheet1");
+                       HSSFName hssfName = wb.createName();
+                       hssfName.setNameName("myFunc");
+                       
+               } else {
+                       // This sample spreadsheet already has a VB function called 'myFunc'
+                       wb = HSSFTestDataSamples.openSampleWorkbook("testNames.xls");
+                       sheet = wb.getSheetAt(0);
+                       HSSFRow row = sheet.createRow(0);
+                       cell = row.createCell(1);
+               }
+               
+               cell.setCellFormula("myFunc()");
+               String actualFormula=cell.getCellFormula();
+               assertEquals("myFunc()", actualFormula);
                
                HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(sheet, wb);
                CellValue evalResult = fe.evaluate(cell);
index 08646b3e6460d41ebc7b041d33eb725a0ef29563..e7c79317662733bfe6f9a514947dfe4556d409cb 100644 (file)
@@ -417,6 +417,9 @@ public final class TestBugs extends TestCase {
         for(int i = 0 ; i < wb.getNumberOfNames(); i++){
           HSSFName name = wb.getNameAt(i);
           name.getNameName();
+          if (name.isFunctionName()) {
+              continue;
+          }
           name.getReference();
         }
     }
@@ -1004,7 +1007,6 @@ public final class TestBugs extends TestCase {
      * Test that we can delete sheets without
      *  breaking the build in named ranges
      *  used for printing stuff.
-     * Currently broken, as we change the Ptg
      */
     public void test30978() {
         HSSFWorkbook wb = openSample("30978-alt.xls");
@@ -1016,7 +1018,7 @@ public final class TestBugs extends TestCase {
         Workbook w = wb.getWorkbook();
         for(int i=0; i<w.getNumNames(); i++) {
             NameRecord r = w.getNameRecord(i);
-            assertTrue(r.getIndexToSheet() <= wb.getNumberOfSheets());
+            assertTrue(r.getSheetNumber() <= wb.getNumberOfSheets());
             
             List nd = r.getNameDefinition();
             assertEquals(1, nd.size());
@@ -1034,7 +1036,7 @@ public final class TestBugs extends TestCase {
         
         for(int i=0; i<w.getNumNames(); i++) {
             NameRecord r = w.getNameRecord(i);
-            assertTrue(r.getIndexToSheet() <= wb.getNumberOfSheets());
+            assertTrue(r.getSheetNumber() <= wb.getNumberOfSheets());
             
             List nd = r.getNameDefinition();
             assertEquals(1, nd.size());
@@ -1051,7 +1053,7 @@ public final class TestBugs extends TestCase {
         
         for(int i=0; i<w.getNumNames(); i++) {
             NameRecord r = w.getNameRecord(i);
-            assertTrue(r.getIndexToSheet() <= wb.getNumberOfSheets());
+            assertTrue(r.getSheetNumber() <= wb.getNumberOfSheets());
             
             List nd = r.getNameDefinition();
             assertEquals(1, nd.size());
index d8b7cde29223c8e388fa2a3ada11421b1b57c521..35a2d955fb12fe5d4764274b328237f151fb46f7 100644 (file)
@@ -50,7 +50,7 @@ public final class TestHSSFWorkbook extends TestCase {
         b.createSheet();
         b.setRepeatingRowsAndColumns( 2, 0,1,-1,-1 );
         NameRecord nameRecord = b.getWorkbook().getNameRecord( 0 );
-        assertEquals( 3, nameRecord.getIndexToSheet() );
+        assertEquals(3, nameRecord.getSheetNumber());
     }
 
     public void testCaseInsensitiveNames() {
@@ -411,84 +411,84 @@ public final class TestHSSFWorkbook extends TestCase {
      *  that point to deleted sheets
      */
     public void testNamesToDeleteSheets() throws Exception {
-       HSSFWorkbook b = openSample("30978-deleted.xls");
-       assertEquals(3, b.getNumberOfNames());
-       
-       // Sheet 2 is deleted
-       assertEquals("Sheet1", b.getSheetName(0));
-       assertEquals("Sheet3", b.getSheetName(1));
-       
-       Area3DPtg ptg;
-       NameRecord nr;
-       HSSFName n;
-       
-       /* ======= Name pointing to deleted sheet ====== */
-       
-       // First at low level
-       nr = b.getWorkbook().getNameRecord(0);
-       assertEquals("On2", nr.getNameText());
-       assertEquals(0, nr.getIndexToSheet());
-       assertEquals(1, nr.getExternSheetNumber());
-       assertEquals(1, nr.getNameDefinition().size());
-       
-       ptg = (Area3DPtg)nr.getNameDefinition().get(0);
-       assertEquals(1, ptg.getExternSheetIndex());
-       assertEquals(0, ptg.getFirstColumn());
-       assertEquals(0, ptg.getFirstRow());
-       assertEquals(0, ptg.getLastColumn());
-       assertEquals(2, ptg.getLastRow());
-       
-       // Now at high level
-       n = b.getNameAt(0);
-       assertEquals("On2", n.getNameName());
-       assertEquals("", n.getSheetName());
-       assertEquals("#REF!$A$1:$A$3", n.getReference());
-       
-       
-       /* ======= Name pointing to 1st sheet ====== */
-       
-       // First at low level
-       nr = b.getWorkbook().getNameRecord(1);
-       assertEquals("OnOne", nr.getNameText());
-       assertEquals(0, nr.getIndexToSheet());
-       assertEquals(0, nr.getExternSheetNumber());
-       assertEquals(1, nr.getNameDefinition().size());
-       
-       ptg = (Area3DPtg)nr.getNameDefinition().get(0);
-       assertEquals(0, ptg.getExternSheetIndex());
-       assertEquals(0, ptg.getFirstColumn());
-       assertEquals(2, ptg.getFirstRow());
-       assertEquals(0, ptg.getLastColumn());
-       assertEquals(3, ptg.getLastRow());
-       
-       // Now at high level
-       n = b.getNameAt(1);
-       assertEquals("OnOne", n.getNameName());
-       assertEquals("Sheet1", n.getSheetName());
-       assertEquals("Sheet1!$A$3:$A$4", n.getReference());
-       
-       
-       /* ======= Name pointing to 3rd sheet ====== */
-       
-       // First at low level
-       nr = b.getWorkbook().getNameRecord(2);
-       assertEquals("OnSheet3", nr.getNameText());
-       assertEquals(0, nr.getIndexToSheet());
-       assertEquals(2, nr.getExternSheetNumber());
-       assertEquals(1, nr.getNameDefinition().size());
-       
-       ptg = (Area3DPtg)nr.getNameDefinition().get(0);
-       assertEquals(2, ptg.getExternSheetIndex());
-       assertEquals(0, ptg.getFirstColumn());
-       assertEquals(0, ptg.getFirstRow());
-       assertEquals(0, ptg.getLastColumn());
-       assertEquals(1, ptg.getLastRow());
-       
-       // Now at high level
-       n = b.getNameAt(2);
-       assertEquals("OnSheet3", n.getNameName());
-       assertEquals("Sheet3", n.getSheetName());
-       assertEquals("Sheet3!$A$1:$A$2", n.getReference());
+        HSSFWorkbook b = openSample("30978-deleted.xls");
+        assertEquals(3, b.getNumberOfNames());
+        
+        // Sheet 2 is deleted
+        assertEquals("Sheet1", b.getSheetName(0));
+        assertEquals("Sheet3", b.getSheetName(1));
+        
+        Area3DPtg ptg;
+        NameRecord nr;
+        HSSFName n;
+        
+        /* ======= Name pointing to deleted sheet ====== */
+        
+        // First at low level
+        nr = b.getWorkbook().getNameRecord(0);
+        assertEquals("On2", nr.getNameText());
+        assertEquals(0, nr.getSheetNumber());
+        assertEquals(1, nr.getExternSheetNumber());
+        assertEquals(1, nr.getNameDefinition().size());
+        
+        ptg = (Area3DPtg)nr.getNameDefinition().get(0);
+        assertEquals(1, ptg.getExternSheetIndex());
+        assertEquals(0, ptg.getFirstColumn());
+        assertEquals(0, ptg.getFirstRow());
+        assertEquals(0, ptg.getLastColumn());
+        assertEquals(2, ptg.getLastRow());
+        
+        // Now at high level
+        n = b.getNameAt(0);
+        assertEquals("On2", n.getNameName());
+        assertEquals("", n.getSheetName());
+        assertEquals("#REF!$A$1:$A$3", n.getReference());
+        
+        
+        /* ======= Name pointing to 1st sheet ====== */
+        
+        // First at low level
+        nr = b.getWorkbook().getNameRecord(1);
+        assertEquals("OnOne", nr.getNameText());
+        assertEquals(0, nr.getSheetNumber());
+        assertEquals(0, nr.getExternSheetNumber());
+        assertEquals(1, nr.getNameDefinition().size());
+        
+        ptg = (Area3DPtg)nr.getNameDefinition().get(0);
+        assertEquals(0, ptg.getExternSheetIndex());
+        assertEquals(0, ptg.getFirstColumn());
+        assertEquals(2, ptg.getFirstRow());
+        assertEquals(0, ptg.getLastColumn());
+        assertEquals(3, ptg.getLastRow());
+        
+        // Now at high level
+        n = b.getNameAt(1);
+        assertEquals("OnOne", n.getNameName());
+        assertEquals("Sheet1", n.getSheetName());
+        assertEquals("Sheet1!$A$3:$A$4", n.getReference());
+        
+        
+        /* ======= Name pointing to 3rd sheet ====== */
+        
+        // First at low level
+        nr = b.getWorkbook().getNameRecord(2);
+        assertEquals("OnSheet3", nr.getNameText());
+        assertEquals(0, nr.getSheetNumber());
+        assertEquals(2, nr.getExternSheetNumber());
+        assertEquals(1, nr.getNameDefinition().size());
+        
+        ptg = (Area3DPtg)nr.getNameDefinition().get(0);
+        assertEquals(2, ptg.getExternSheetIndex());
+        assertEquals(0, ptg.getFirstColumn());
+        assertEquals(0, ptg.getFirstRow());
+        assertEquals(0, ptg.getLastColumn());
+        assertEquals(1, ptg.getLastRow());
+        
+        // Now at high level
+        n = b.getNameAt(2);
+        assertEquals("OnSheet3", n.getNameName());
+        assertEquals("Sheet3", n.getSheetName());
+        assertEquals("Sheet3!$A$1:$A$2", n.getReference());
     }
     
     /**
@@ -519,12 +519,12 @@ public final class TestHSSFWorkbook extends TestCase {
      * The sample file provided with bug 45582 seems to have one extra byte after the EOFRecord
      */
     public void testExtraDataAfterEOFRecord() {
-       try {
-               HSSFTestDataSamples.openSampleWorkbook("ex45582-22397.xls");
-       } catch (RecordFormatException e) {
-               if (e.getCause() instanceof LittleEndian.BufferUnderrunException) {
-                       throw new AssertionFailedError("Identified bug 45582");
-               }
-       }
-       }
+        try {
+            HSSFTestDataSamples.openSampleWorkbook("ex45582-22397.xls");
+        } catch (RecordFormatException e) {
+            if (e.getCause() instanceof LittleEndian.BufferUnderrunException) {
+                throw new AssertionFailedError("Identified bug 45582");
+            }
+        }
+    }
 }
index 0a508805db1e94f578817437a3bdfec37753cf29..2382a82359a22d8d28c3fa30820efe2a9253901b 100644 (file)
 
 package org.apache.poi.hssf.usermodel;
 
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileOutputStream;
+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.poifs.filesystem.POIFSFileSystem;
 
 /**
  * 
@@ -42,10 +40,6 @@ public final class TestNamedRange extends TestCase {
                return HSSFTestDataSamples.openSampleWorkbook(sampleFileName);
        }
 
-       public static void main(String[] args) {
-               junit.textui.TestRunner.run(TestNamedRange.class);
-       }
-
        /** Test of TestCase method, of class test.RangeTest. */
        public void testNamedRange() {
                HSSFWorkbook wb = openSample("Simple.xls");
@@ -411,7 +405,7 @@ public final class TestNamedRange extends TestCase {
                String cellValue = "TEST Value";
                HSSFWorkbook wb = new HSSFWorkbook();
                HSSFSheet sheet = wb.createSheet(sheetName);
-               sheet.createRow(0).createCell((short) 0).setCellValue(cellValue);
+               sheet.createRow(0).createCell(0).setCellValue(new HSSFRichTextString(cellValue));
                 
                // create named range for a single cell using areareference
                HSSFName namedCell = wb.createName();
@@ -447,7 +441,7 @@ public final class TestNamedRange extends TestCase {
                String sname = "TestSheet", cname = "TestName", cvalue = "TestVal";
                HSSFWorkbook wb = new HSSFWorkbook();
                HSSFSheet sheet = wb.createSheet(sname);
-               sheet.createRow(0).createCell((short) 0).setCellValue(cvalue);
+               sheet.createRow(0).createCell(0).setCellValue(new HSSFRichTextString(cvalue));
                 
                // create named range for a single cell using cellreference
                HSSFName namedCell = wb.createName();
@@ -492,56 +486,60 @@ public final class TestNamedRange extends TestCase {
                }
    }
        
-       public void testRepeatingRowsAndColumsNames() throws Exception {
+       public void testRepeatingRowsAndColumsNames() {
+               // First test that setting RR&C for same sheet more than once only creates a 
+               // single  Print_Titles built-in record
                HSSFWorkbook wb = new HSSFWorkbook();
-               HSSFSheet sheet = wb.createSheet();
+               HSSFSheet sheet = wb.createSheet("FirstSheet");
                
-               for (int rowItem = 0; rowItem < 10; rowItem++) {
-                       HSSFRow r = sheet.createRow(rowItem);
-                       for (int column = 0; column < 2; column++) {
-                               HSSFCell cellItem = r.createCell((short) column);
-                               cellItem.setCellType(HSSFCell.CELL_TYPE_STRING);
-                               cellItem.setCellValue(new HSSFRichTextString("Some value here"));
-                               if (rowItem == 2) {
-                                       wb.setRepeatingRowsAndColumns(0, 0, 0, 0, 3 - 1);
-                                       sheet.createFreezePane(0, 3);
-                               } 
-                       }
+               // set repeating rows and columns twice for the first sheet
+               for (int i = 0; i < 2; i++) {
+                       wb.setRepeatingRowsAndColumns(0, 0, 0, 0, 3-1);
+                       sheet.createFreezePane(0, 3);
                }
-
-               assertEquals(2, wb.getNumberOfNames());
+               assertEquals(1, wb.getNumberOfNames());
                HSSFName nr1 = wb.getNameAt(0);
-               HSSFName nr2 = wb.getNameAt(1);
                
                assertEquals("Print_Titles", nr1.getNameName());
-               assertEquals("Sheet0!$A$1:$A$0,Sheet0!$A$1:$IV$3", nr1.getReference());
-               
-               assertEquals("Excel_Name_Record_Titles_1_1", nr2.getNameName());
-               assertEquals("Sheet0!$A$1:$A$0,Sheet0!$A$1:$IV$3", nr2.getReference());
+               if (false) {
+                       //      TODO - full column references not rendering properly, absolute markers not present either
+                       assertEquals("FirstSheet!$A:$A,FirstSheet!$1:$3", nr1.getReference());
+               } else {
+                       assertEquals("FirstSheet!A:A,FirstSheet!$A$1:$IV$3", nr1.getReference());
+               }
                
                // Save and re-open
-               ByteArrayOutputStream baos = new ByteArrayOutputStream();
-               wb.write(baos);
-               ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
-               HSSFWorkbook nwb = new HSSFWorkbook(new POIFSFileSystem(bais));
+               HSSFWorkbook nwb = HSSFTestDataSamples.writeOutAndReadBack(wb);
 
-               assertEquals(2, nwb.getNumberOfNames());
+               assertEquals(1, nwb.getNumberOfNames());
                nr1 = nwb.getNameAt(0);
-               nr2 = nwb.getNameAt(1);
                
-               // TODO -
-               //  should these references really have been corrected?
-               //  and if so, why not also above?
                assertEquals("Print_Titles", nr1.getNameName());
-               assertEquals("Sheet0!A:A,Sheet0!$A$1:$IV$3", nr1.getReference());
+               assertEquals("FirstSheet!A:A,FirstSheet!$A$1:$IV$3", nr1.getReference());
+               
+               // check that setting RR&C on a second sheet causes a new Print_Titles built-in
+               // name to be created
+               sheet = nwb.createSheet("SecondSheet");
+               nwb.setRepeatingRowsAndColumns(1, 1, 2, 0, 0);
+
+               assertEquals(2, nwb.getNumberOfNames());
+               HSSFName nr2 = nwb.getNameAt(1);
                
-               assertEquals("Excel_Name_Record_Titles_1_1", nr2.getNameName());
-               assertEquals("Sheet0!A:A,Sheet0!$A$1:$IV$3", nr2.getReference());
+               assertEquals("Print_Titles", nr2.getNameName());
+               assertEquals("SecondSheet!B:C,SecondSheet!$A$1:$IV$1", nr2.getReference());
                
-               // In case you fancy checking in excel, to ensure it
-               //  won't complain about the file now
-               FileOutputStream fout = new FileOutputStream(File.createTempFile("POI-45126-", ".xls"));
-               wb.write(fout);
-               fout.close();
+               if (false) {
+                       // In case you fancy checking in excel, to ensure it
+                       //  won't complain about the file now
+                       try {
+                               File tempFile = File.createTempFile("POI-45126-", ".xls");
+                               FileOutputStream fout = new FileOutputStream(tempFile);
+                               nwb.write(fout);
+                               fout.close();
+                               System.out.println("check out " + tempFile.getAbsolutePath());
+                       } catch (IOException e) {
+                               throw new RuntimeException(e);
+                       }
+               }
        }
 }