diff options
author | Nick Burch <nick@apache.org> | 2008-08-11 23:58:54 +0000 |
---|---|---|
committer | Nick Burch <nick@apache.org> | 2008-08-11 23:58:54 +0000 |
commit | 1073cfb53d419fb9f91faec7e99d9b99448f6507 (patch) | |
tree | f3f718d6843036cad4a360f10d5004942bcc0560 /src/java/org/apache/poi/hssf | |
parent | 821aad8c70b89f7b6030110d0c2b2737c4aa8ec4 (diff) | |
download | poi-1073cfb53d419fb9f91faec7e99d9b99448f6507.tar.gz poi-1073cfb53d419fb9f91faec7e99d9b99448f6507.zip |
Merged revisions 638786-638802,638805-638811,638813-638814,638816-639230,639233-639241,639243-639253,639255-639486,639488-639601,639603-639835,639837-639917,639919-640056,640058-640710,640712-641156,641158-641184,641186-641795,641797-641798,641800-641933,641935-641963,641965-641966,641968-641995,641997-642230,642232-642562,642564-642565,642568-642570,642572-642573,642576-642736,642739-642877,642879,642881-642890,642892-642903,642905-642945,642947-643624,643626-643653,643655-643669,643671,643673-643830,643832-643833,643835-644342,644344-644472,644474-644508,644510-645347,645349-645351,645353-645559,645561-645565,645568-645951,645953-646193,646195-646311,646313-646404,646406-646665,646667-646853,646855-646869,646871-647151,647153-647185,647187-647277,647279-647566,647568-647573,647575,647578-647711,647714-647737,647739-647823,647825-648155,648157-648202,648204-648273,648275,648277-648302,648304-648333,648335-648588,648590-648622,648625-648673,648675-649141,649144,649146-649556,649558-649795,649799,649801-649910,649912-649913,649915-650128,650131-650132,650134-650137,650140-650914,650916-651991,651993-652284,652286-652287,652289,652291,652293-652297,652299-652328,652330-652425,652427-652445,652447-652560,652562-652933,652935,652937-652993,652995-653116,653118-653124,653126-653483,653487-653519,653522-653550,653552-653607,653609-653667,653669-653674,653676-653814,653817-653830,653832-653891,653893-653944,653946-654055,654057-654355,654357-654365,654367-654648,654651-655215,655217-655277,655279-655281,655283-655911,655913-656212,656214,656216-656251,656253-656698,656700-656756,656758-656892,656894-657135,657137-657165,657168-657179,657181-657354,657356-657357,657359-657701,657703-657874,657876-658032,658034-658284,658286,658288-658301,658303-658307,658309-658321,658323-658335,658337-658348,658351,658353-658832,658834-658983,658985,658987-659066,659068-659402,659404-659428,659430-659451,659453-659454,659456-659461,659463-659477,659479-659524,659526-659571,659574,659576-660255,660257-660262,660264-660279,660281-660343,660345-660473,660475-660827,660829-660833,660835-660888,660890-663321,663323-663435,663437-663764,663766-663854,663856-664219,664221-664489,664494-664514,664516-668013,668015-668142,668144-668152,668154,668156-668256,668258,668260-669139,669141-669455,669457-669657,669659-669808,669810-670189,670191-671321,671323-672229,672231-672549,672551-672552,672554-672561,672563-672566,672568,672571-673049,673051-673852,673854-673862,673864-673986,673988-673996,673998-674347,674349-674890,674892-674910,674912-674936,674938-674952,674954-675078,675080-675085,675087-675217,675219-675660,675662-675670,675672-675716,675718-675726,675728-675733,675735-675775,675777-675782,675784,675786-675791,675794-675852,675854-676200,676202,676204,676206-676220,676222-676309,676311-676456,676458-676994,676996-677027,677030-677040,677042-677056,677058-677375,677377-677968,677970-677971,677973,677975-677994,677996-678286,678288-678538,678540-680393,680395-680469,680471-680529,680531-680852,680854-681529,681531-681571,681573-682224,682226,682228,682231-682281,682283-682335,682337-682507,682509,682512-682517,682519-682532,682534-682619,682622-682777,682779-682998,683000-683019,683021-683022,683024-683080,683082-683092,683094-683095,683097-683127,683129-683131,683133-683166,683168-683698,683700-683705,683707-683757,683759-683787,683789-683870,683872-683879,683881-683900,683902-684066,684068-684074,684076-684222,684224-684254,684257-684281,684283-684286,684288-684292,684294-684298,684300-684301,684303-684308,684310-684317,684320,684323-684335,684337-684348,684350-684354,684356-684361,684363-684369,684371-684453,684455-684986 via svnmerge from
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
Diffstat (limited to 'src/java/org/apache/poi/hssf')
11 files changed, 1361 insertions, 1341 deletions
diff --git a/src/java/org/apache/poi/hssf/model/FormulaParser.java b/src/java/org/apache/poi/hssf/model/FormulaParser.java index e229f0358f..5fd30d06e0 100644 --- a/src/java/org/apache/poi/hssf/model/FormulaParser.java +++ b/src/java/org/apache/poi/hssf/model/FormulaParser.java @@ -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; diff --git a/src/java/org/apache/poi/hssf/model/LinkTable.java b/src/java/org/apache/poi/hssf/model/LinkTable.java index 1d8781d971..9d1707558d 100755 --- a/src/java/org/apache/poi/hssf/model/LinkTable.java +++ b/src/java/org/apache/poi/hssf/model/LinkTable.java @@ -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); + } } diff --git a/src/java/org/apache/poi/hssf/model/Workbook.java b/src/java/org/apache/poi/hssf/model/Workbook.java index f80c41661d..5ad1ef28d3 100644 --- a/src/java/org/apache/poi/hssf/model/Workbook.java +++ b/src/java/org/apache/poi/hssf/model/Workbook.java @@ -15,21 +15,70 @@ 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); + } +} diff --git a/src/java/org/apache/poi/hssf/record/ExternSheetRecord.java b/src/java/org/apache/poi/hssf/record/ExternSheetRecord.java index 0d1823a7c4..2b0744a91e 100644 --- a/src/java/org/apache/poi/hssf/record/ExternSheetRecord.java +++ b/src/java/org/apache/poi/hssf/record/ExternSheetRecord.java @@ -1,4 +1,3 @@ - /* ==================================================================== Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with @@ -15,29 +14,85 @@ 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 index 184895d35f..0000000000 --- a/src/java/org/apache/poi/hssf/record/ExternSheetSubRecord.java +++ /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; - } -} diff --git a/src/java/org/apache/poi/hssf/record/NameRecord.java b/src/java/org/apache/poi/hssf/record/NameRecord.java index dbd796991c..6c6c53a92b 100644 --- a/src/java/org/apache/poi/hssf/record/NameRecord.java +++ b/src/java/org/apache/poi/hssf/record/NameRecord.java @@ -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"; } } diff --git a/src/java/org/apache/poi/hssf/record/SupBookRecord.java b/src/java/org/apache/poi/hssf/record/SupBookRecord.java index 6755aa6f8b..cb4eff8406 100644 --- a/src/java/org/apache/poi/hssf/record/SupBookRecord.java +++ b/src/java/org/apache/poi/hssf/record/SupBookRecord.java @@ -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) diff --git a/src/java/org/apache/poi/hssf/record/formula/AbstractFunctionPtg.java b/src/java/org/apache/poi/hssf/record/formula/AbstractFunctionPtg.java index fabc85ce52..800f45dbf5 100644 --- a/src/java/org/apache/poi/hssf/record/formula/AbstractFunctionPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/AbstractFunctionPtg.java @@ -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; } diff --git a/src/java/org/apache/poi/hssf/record/formula/NameXPtg.java b/src/java/org/apache/poi/hssf/record/formula/NameXPtg.java index 0a99ff140e..b6076e1ea8 100644 --- a/src/java/org/apache/poi/hssf/record/formula/NameXPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/NameXPtg.java @@ -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; } } diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFName.java b/src/java/org/apache/poi/hssf/usermodel/HSSFName.java index 31af2b773a..8d7c0ada81 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFName.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFName.java @@ -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(); + } } diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java b/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java index e663f38f2a..c77c8266b0 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java @@ -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); + } + } |