From 647522fef87fecd9a71dc4e7771ed071c28c9d61 Mon Sep 17 00:00:00 2001 From: Josh Micich Date: Mon, 11 Aug 2008 22:55:38 +0000 Subject: [PATCH] initial work on supporting calls to add-in functions git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@684971 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/poi/hssf/model/FormulaParser.java | 35 +- .../org/apache/poi/hssf/model/LinkTable.java | 76 ++- .../org/apache/poi/hssf/model/Workbook.java | 123 ++-- .../poi/hssf/record/ExternSheetRecord.java | 210 +++++-- .../poi/hssf/record/ExternSheetSubRecord.java | 154 ----- .../apache/poi/hssf/record/NameRecord.java | 538 +++++++++--------- .../apache/poi/hssf/record/SupBookRecord.java | 2 +- .../record/formula/AbstractFunctionPtg.java | 2 +- .../poi/hssf/record/formula/NameXPtg.java | 80 +-- .../apache/poi/hssf/usermodel/HSSFName.java | 87 ++- .../poi/hssf/usermodel/HSSFWorkbook.java | 61 +- .../poi/hssf/data/FormulaEvalTestData.xls | Bin 137728 -> 153088 bytes .../org/apache/poi/hssf/data/testNames.xls | Bin 0 -> 27648 bytes .../poi/hssf/model/TestFormulaParser.java | 10 +- .../formula/TestExternalFunctionFormulas.java | 62 +- .../formula/eval/TestExternalFunction.java | 40 +- .../apache/poi/hssf/usermodel/TestBugs.java | 3 + 17 files changed, 796 insertions(+), 687 deletions(-) delete mode 100644 src/java/org/apache/poi/hssf/record/ExternSheetSubRecord.java create mode 100644 src/testcases/org/apache/poi/hssf/data/testNames.xls diff --git a/src/java/org/apache/poi/hssf/model/FormulaParser.java b/src/java/org/apache/poi/hssf/model/FormulaParser.java index b89480e3c6..c2a90e9486 100644 --- a/src/java/org/apache/poi/hssf/model/FormulaParser.java +++ b/src/java/org/apache/poi/hssf/model/FormulaParser.java @@ -26,6 +26,7 @@ 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.hssf.usermodel.HSSFFormulaEvaluator; +import org.apache.poi.hssf.usermodel.HSSFName; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.hssf.util.AreaReference; import org.apache.poi.hssf.util.CellReference; @@ -369,13 +370,31 @@ 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) { + HSSFName 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 { + + nameToken = book.getNameXPtg(name); + if (nameToken == null) { + throw new FormulaParseException("Name '" + name + + "' is completely unknown in the current workbook"); + } + } } Match('('); @@ -389,11 +408,11 @@ public final class FormulaParser { * Generates the variable function ptg for the formula. *

* For IF Formulas, additional PTGs are added to the tokens - * @param name + * @param name a {@link NamePtg} or {@link NameXPtg} or null * @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 7367d08c2a..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 )

@@ -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; @@ -270,42 +283,31 @@ final class LinkTable { } - public short getIndexToSheet(short num) { - return _externSheetRecord.getREFRecordAt(num).getIndexToFirstSupBook(); + 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); } @@ -326,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 12c5f90ec3..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. @@ -55,7 +104,7 @@ import java.util.Locale; * @version 1.0-pre */ public final class Workbook implements Model { - private static final int DEBUG = POILogger.DEBUG; + private static final int DEBUG = POILogger.DEBUG; /** * constant used to set the "codepage" wherever "codepage" is set in records @@ -461,19 +510,23 @@ public final 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. */ @@ -509,7 +562,7 @@ public final 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; } @@ -526,7 +579,7 @@ public final 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 ); @@ -548,13 +601,11 @@ public final class Workbook implements Model { /** * 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(); } /** @@ -565,8 +616,7 @@ public final class Workbook implements Model { */ public boolean isSheetHidden(int sheetnum) { - BoundSheetRecord bsr = ( BoundSheetRecord ) boundsheets.get(sheetnum); - return bsr.isHidden(); + return getBoundSheetRec(sheetnum).isHidden(); } /** @@ -577,8 +627,7 @@ public final 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 @@ -851,7 +900,7 @@ public final 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; @@ -1134,8 +1183,8 @@ public final 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; @@ -1882,15 +1931,15 @@ public final 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); } /** @@ -2402,6 +2451,8 @@ public final 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

- * Description: A List of Inndexes to SupBook

- * REFERENCE:

+ * EXTERNSHEET (0x0017)
+ * A List of Indexes to EXTERNALBOOK (supplemental book) Records

+ * * @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

- * Description: Defines a named range within a workbook.

- * REFERENCE:

- * @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 bfc2ac4ed2..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)

+ * Title: DEFINEDNAME Record (0x0018)

* Description: Defines a named range within a workbook.

* REFERENCE:

* @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; @@ -92,14 +89,15 @@ public final class NameRecord extends Record { */ 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 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; @@ -124,13 +122,13 @@ public final class NameRecord extends Record { /** Creates new NameRecord */ public NameRecord() { - field_13_name_definition = new Stack(); + 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(); + 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(); } /** @@ -139,7 +137,7 @@ public final class NameRecord extends Record { * @param in the RecordInputstream to read the record from */ public NameRecord(RecordInputStream in) { - super(in); + super(in); } /** @@ -148,26 +146,26 @@ public final class NameRecord extends Record { */ public NameRecord(byte builtin, int sheetNumber) { - this(); - this.field_12_builtIn_name = builtin; - this.setOptionFlag((short)(this.getOptionFlag() | 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(); + 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; + field_1_option_flag = flag; } @@ -175,21 +173,21 @@ public final class NameRecord extends Record { * @param shortcut keyboard shortcut */ public void setKeyboardShortcut(byte shortcut){ - field_2_keyboard_shortcut = 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; + 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; + field_4_length_name_definition = length; } /** sets the index number to the extern sheet (thats is what writen in documentation @@ -197,9 +195,9 @@ public final class NameRecord extends Record { * @param index extern sheet index */ public void setUnused(short index){ - field_5_index_to_sheet = 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 is equal to field_5_index_to_sheet // field_6_equals_to_index_to_sheet = index; } @@ -209,7 +207,7 @@ public final class NameRecord extends Record { */ public int getSheetNumber() { - return field_6_sheetNumber; + return field_6_sheetNumber; } /** @@ -217,14 +215,14 @@ public final class NameRecord extends Record { * @see FnGroupCountRecord */ public byte getFnGroup() { - int masked = field_1_option_flag & 0x0fc0; - return (byte) (masked >> 4); + int masked = field_1_option_flag & 0x0fc0; + return (byte) (masked >> 4); } public void setSheetNumber(int value) { - field_6_sheetNumber = value; + field_6_sheetNumber = value; } @@ -232,87 +230,87 @@ public final class NameRecord extends Record { * @param length custom menu length */ public void setCustomMenuLength(byte length){ - field_7_length_custom_menu = 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; + 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; + 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; + 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; + 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( + 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; + 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; + 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; + 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; + field_17_status_bar_text = text; } /** gets the option flag * @return option flag */ public short getOptionFlag(){ - return field_1_option_flag; + return field_1_option_flag; } /** returns the keyboard shortcut * @return keyboard shortcut */ public byte getKeyboardShortcut(){ - return field_2_keyboard_shortcut ; + return field_2_keyboard_shortcut ; } /** @@ -320,7 +318,7 @@ public final class NameRecord extends Record { * @return name length */ public byte getNameTextLength(){ - return field_3_length_name_text; + return field_3_length_name_text; } /** @@ -338,92 +336,90 @@ public final class NameRecord extends Record { * @return definition length */ public short getDefinitionLength(){ - return field_4_length_name_definition; + 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; + return field_5_index_to_sheet; } /** gets the custom menu length * @return custom menu length */ public byte getCustomMenuLength(){ - return field_7_length_custom_menu; + return field_7_length_custom_menu; } /** gets the description text length * @return description text length */ public byte getDescriptionTextLength(){ - return field_8_length_description_text; + 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; + 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; + 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 field_11_compressed_unicode_flag; } + /** * @return true if name is hidden */ public boolean isHiddenName() { - return (field_1_option_flag & OPT_HIDDEN_NAME) != 0; + 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 & OPT_FUNCTION_NAME) != 0; + 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 & OPT_COMMAND_NAME) != 0; + 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 & OPT_MACRO) != 0; + 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 & OPT_COMPLEX) != 0; + 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 +436,7 @@ public final class NameRecord extends Record { */ public byte getBuiltInName() { - return this.field_12_builtIn_name; + return this.field_12_builtIn_name; } @@ -448,39 +444,39 @@ public final class NameRecord extends Record { * @return definition -- can be null if we cant parse ptgs */ public List getNameDefinition() { - return field_13_name_definition; + return field_13_name_definition; } public void setNameDefinition(Stack nameDefinition) { - field_13_name_definition = nameDefinition; + field_13_name_definition = nameDefinition; } /** get the custom menu text * @return custom menu text */ public String getCustomMenuText(){ - return field_14_custom_menu_text; + return field_14_custom_menu_text; } /** gets the description text * @return description text */ public String getDescriptionText(){ - return field_15_description_text; + return field_15_description_text; } /** get the help topic text * @return gelp topic text */ public String getHelpTopicText(){ - return field_16_help_topic_text; + return field_16_help_topic_text; } /** gets the status bar text * @return status bar text */ public String getStatusBarText(){ - return field_17_status_bar_text; + return field_17_status_bar_text; } /** @@ -490,9 +486,9 @@ public final class NameRecord extends Record { * @param id alleged id for this record */ protected void validateSid(short id) { - if (id != sid) { - throw new RecordFormatException("NOT A valid Name RECORD"); - } + if (id != sid) { + throw new RecordFormatException("NOT A valid Name RECORD"); + } } /** @@ -504,21 +500,21 @@ public final class NameRecord extends Record { */ 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(); + 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; @@ -536,20 +532,20 @@ 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_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_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_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 ); + 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(); - /* } */ + return getRecordSize(); + /* } */ } /** @@ -557,83 +553,83 @@ public final class NameRecord extends Record { * @return total length */ public int getTextsLength(){ - int result; + int result; - result = getRawNameTextLength() + getDescriptionTextLength() + + result = getRawNameTextLength() + getDescriptionTextLength() + getHelpTopicLength() + getStatusBarLength(); - return result; + return result; } private int getNameDefinitionSize() { int result = 0; - List list = field_13_name_definition; - - for (int k = 0; k < list.size(); k++) - { + 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; + } + return result; } /** returns the record size */ public int getRecordSize(){ - int result; + int result; - result = 19 + getTextsLength() + getNameDefinitionSize(); - + result = 19 + getTextsLength() + getNameDefinitionSize(); + - return result; + 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 (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(); + if (ptg.getClass() == Area3DPtg.class){ + result = ((Area3DPtg) ptg).getExternSheetIndex(); - } else if (ptg.getClass() == Ref3DPtg.class){ - result = ((Ref3DPtg) ptg).getExternSheetIndex(); - } + } else if (ptg.getClass() == Ref3DPtg.class){ + result = ((Ref3DPtg) ptg).getExternSheetIndex(); + } - return result; + return result; } /** sets the extern sheet number * @param externSheetNumber extern sheet number */ public void setExternSheetNumber(short externSheetNumber){ - Ptg ptg; + 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 (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); + if (ptg.getClass() == Area3DPtg.class){ + ((Area3DPtg) ptg).setExternSheetIndex(externSheetNumber); - } else if (ptg.getClass() == Ref3DPtg.class){ - ((Ref3DPtg) 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); + Ptg ptg = new Area3DPtg(); + field_13_name_definition.push(ptg); - return ptg; + return ptg; } /** gets the reference , the area only (range) @@ -647,55 +643,55 @@ public final class NameRecord extends Record { * @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(); - } + //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; + short externSheetIndex = 0; - if (oldPtg.getClass() == Area3DPtg.class){ - externSheetIndex = ((Area3DPtg) oldPtg).getExternSheetIndex(); + if (oldPtg.getClass() == Area3DPtg.class){ + externSheetIndex = ((Area3DPtg) oldPtg).getExternSheetIndex(); - } else if (oldPtg.getClass() == Ref3DPtg.class){ - externSheetIndex = ((Ref3DPtg) oldPtg).getExternSheetIndex(); - } + } else if (oldPtg.getClass() == Ref3DPtg.class){ + externSheetIndex = ((Ref3DPtg) oldPtg).getExternSheetIndex(); + } - if (ra.hasRange()) { + if (ra.hasRange()) { // Is it contiguous or not? AreaReference[] refs = AreaReference.generateContiguous(ref); - this.setDefinitionTextLength((short)0); + this.setDefinitionTextLength((short)0); - // Add the area reference(s) + // Add the area reference(s) for(int i=0; i 1) { ptg = UnionPtg.instance; - field_13_name_definition.push(ptg); - this.setDefinitionTextLength( (short)(getDefinitionLength() + ptg.getSize()) ); + 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()); - } + } else { + ptg = new Ref3DPtg(); + ((Ref3DPtg) ptg).setExternSheetIndex(externSheetIndex); + ((Ref3DPtg) ptg).setArea(ref); + field_13_name_definition.push(ptg); + this.setDefinitionTextLength((short)ptg.getSize()); + } } /** @@ -705,47 +701,47 @@ public final class NameRecord extends Record { * @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); + 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)); + //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_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_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)); - /*} */ + 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; + return sid; } /* 20 00 @@ -802,53 +798,53 @@ public final class NameRecord extends Record { * @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()) { + 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(); + } + + 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 @@ -856,23 +852,23 @@ public final class NameRecord extends Record { */ 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)

- * Description: A External Workbook Description (Suplemental Book) + * Description: A External Workbook Description (Supplemental Book) * Its only a dummy record for making new ExternSheet Record

* REFERENCE: 5.38

* @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 f89e201bc9..6b071c216d 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 true if the name specifies a standard worksheet function, * false 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 b4b698142e..98ab39f05b 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.hssf.usermodel.HSSFWorkbook; 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(HSSFWorkbook 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(HSSFWorkbook 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 240be13f58..18aeaed8fd 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFName.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFName.java @@ -22,67 +22,57 @@ import org.apache.poi.hssf.record.NameRecord; import org.apache.poi.hssf.util.RangeAddress; /** - * Title: High Level Represantion of Named Range

- * REFERENCE:

+ * 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 { - private HSSFWorkbook book; - private NameRecord name; +public final class HSSFName { + 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)"); } @@ -90,31 +80,24 @@ public class HSSFName { } /** - * 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); - - short externSheetNumber = book.getExternalSheetIndex(sheetNumber); - name.setExternSheetNumber(externSheetNumber); -// name.setIndexToSheet(externSheetNumber); - + int sheetNumber = _book.getSheetIndex(sheetName); + short externSheetNumber = _book.getExternalSheetIndex(sheetNumber); + _definedNameRec.setExternSheetNumber(externSheetNumber); } @@ -122,7 +105,6 @@ public class HSSFName { * sets the reference of this named range * @param ref the reference to set */ - public void setReference(String ref){ RangeAddress ra = new RangeAddress(ref); @@ -134,8 +116,7 @@ public class HSSFName { } //allow the poi utilities to parse it out - name.setAreaReference(ref); - + _definedNameRec.setAreaReference(ref); } /** @@ -147,4 +128,14 @@ public class HSSFName { 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 0f8a14446a..1126e56c1c 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java @@ -17,36 +17,52 @@ package org.apache.poi.hssf.usermodel; +import java.io.ByteArrayInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.List; +import java.util.Stack; + import org.apache.poi.POIDocument; import org.apache.poi.ddf.EscherBSERecord; import org.apache.poi.ddf.EscherBitmapBlip; -import org.apache.poi.ddf.EscherRecord; import org.apache.poi.ddf.EscherBlipRecord; +import org.apache.poi.ddf.EscherRecord; import org.apache.poi.hssf.model.Sheet; import org.apache.poi.hssf.model.Workbook; -import org.apache.poi.hssf.record.*; +import org.apache.poi.hssf.record.AbstractEscherHolderRecord; +import org.apache.poi.hssf.record.BackupRecord; +import org.apache.poi.hssf.record.DrawingGroupRecord; +import org.apache.poi.hssf.record.EmbeddedObjectRefSubRecord; +import org.apache.poi.hssf.record.ExtendedFormatRecord; +import org.apache.poi.hssf.record.FontRecord; +import org.apache.poi.hssf.record.LabelRecord; +import org.apache.poi.hssf.record.LabelSSTRecord; +import org.apache.poi.hssf.record.NameRecord; +import org.apache.poi.hssf.record.ObjRecord; +import org.apache.poi.hssf.record.Record; +import org.apache.poi.hssf.record.RecordFactory; +import org.apache.poi.hssf.record.SSTRecord; +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.usermodel.HSSFRow.MissingCellPolicy; import org.apache.poi.hssf.util.CellReference; import org.apache.poi.hssf.util.SheetReferences; -import org.apache.poi.poifs.filesystem.*; +import org.apache.poi.poifs.filesystem.DirectoryNode; +import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogger; -import java.io.ByteArrayInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.Hashtable; -import java.util.Iterator; -import java.util.List; -import java.util.Stack; - /** * High level representation of a workbook. This is the first object most users * will construct whether they are reading or writing a workbook. It is also the @@ -1640,9 +1656,16 @@ public class HSSFWorkbook extends POIDocument } } - 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); + } + } diff --git a/src/testcases/org/apache/poi/hssf/data/FormulaEvalTestData.xls b/src/testcases/org/apache/poi/hssf/data/FormulaEvalTestData.xls index eba6607ade6da210856ebd818f93e1676e9ce275..aa08040fcd2f61d67e37fab37d75a4b97e6dea7d 100644 GIT binary patch delta 13787 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 delta 3113 zcmZ9O3se;6702(LZ+QrmhUtBx8C>#2>jP^*;)R)ZR~iW-AQYd8_5|M78>cF%#|fA4(XeSLRk zw)l^h;)9-LaVAeD;_^`e{7Cvbl-QcQJg!hw_Hvn&IZE*8^^ebfT~WvG8}>u}uh+2! zs}qFwGj*c3N<^J6KU%q|msx?Kz(bKwCMs`wV;zZ?D{!@sT%DvO$uVKdU=I(N9jtw4 zI_9ePuq%8_yJmH0PdqIzRfy$<3f4wgyq?>FwK=bpw?cL*GrTMGe52L>`>*FLfwlq6 zG>ncL$rvlnS$e*7VX?k&=FkROUxi9}rL1w^d%0!}M*1Uv=p)dU^S^FutuNf-ze{+X z8WeqC83K|oja#)~d0~D|?$YeE1uODbtVOns*Nk+1DKU3x=F+SM$+`1hUJ9ax+Oy#f zUZ&Y&(!0NAIPfz5z5HaYT)uq4()_Fiix;~##Mp-yJ&Ypq#>M<0M4Q0}pcTH?3?17e5P{ z_d)4FMf4ED+f1}Lj%Y1-6MP1yjUZa$Npu>#3XYB^nrR{W1gr;#jU<|Eg;VfT@W%;6 z@hEjScnl00MKlPNZ3Pd29-|T1hv)DB%-{oL``5DI3a~7 z6DR%|*aQwq#Zh!ahrmxk`(&bs?nnfz0ez>S&^{sP0K^XPA?W=&QO?^$PVhF!J&4lN zh?awA!B#MJDiMmMIt@ z?Q@81n2C?U3NT;qn9mDYmhP&X(c^E_t$35^mn4LxR4rb#f zcp02ApC|=0(FC3WQx*^ap17^eXr+6TO72pQUM#y5^W|)a>;ASv*3HD10o)nqEu;`Z4W~VCovrl$*%(I0g1uO!jQ1z(q_Ai+Lo~ zzJ|F}?j4IB#Hbp2xL|Oj|B9Rkz5N4&LdS zTlmOR45*BBO)rU8MHIyL5Aua@Z_RM|ZVYD;R~e~|`Y=pf?I_W*KfE9sw`OPwn+B^i zCvRUfTWt4kwI8kY_gx3MFpbgP#ehR#l+81j&z zHpT9GP%4DTGds0!D|)Nl4Szq%(mo zby1&u-oW1f!ENyrFS5s=)_l6JYe?PSLq#z>np(p};I<4cx;0A7ZO_n_wkC)^s#~jR zjT76?JGHjfp=ufex%%Dtn?v1>%w)U5{nZ9T^%hXghMH!m8-`j7CFp61bP1lUwizZ* z)i4zY$)PGo2=C$`Jy+#T{l(P?w`>pRMkT_npNZh;F5FZ17{lpikyaTg=S}3k!Viu< zn#j@CKHD->qbK1)mX&j$ygrdb#Co$+iX@H_We_n*94WR#yqm;Rt+Og$^e|e;(h9cg zHKEKj8KP?7V@EFT+U7dC`va6iQvBxi!68e+X6NOj9Y89Y=iM)~ra4E}|> z<(XNPc{6#iS_P$7&Sbl%sDg*uEDjfL?0k@g3g;vHUh{dNSX>#Yr_JX{fy{F6YK{V$ zU%;o3W0>^`g?!PjV0laHS)qCo-88Zso!BP5D5^!J}AHS>y~?Oakd%4w5wu`?th#6GhdM-S~dzzl%fne2teUG!aJa4tK^MUc4dm`iS@}G6S&&zGbo?h}Feu|%LuqwSw zKYz#+uYcLW2YmkTl6f8Dm#9gRS33AzeW90ffJF|PWcN{KiR6+XxyncBD|Vs&JwD0` zF#{HdP3bSHU`ezonW7qEzfIXK=9dKNlYEs_ejY(b@WCwG{FIz+fl6RkBW1jB2`^c) z;14fTGHl**RIE~4lNZQ(LW+{W7Fw@7|1mGLYlYFeJ5?FYx{{{E^R_8Uz6tMIT8=A8 K`l%^O9RC-QD0zbb diff --git a/src/testcases/org/apache/poi/hssf/data/testNames.xls b/src/testcases/org/apache/poi/hssf/data/testNames.xls new file mode 100644 index 0000000000000000000000000000000000000000..7ebbb633af8bd6a0a951f1d4335c9242fe2c3f20 GIT binary patch literal 27648 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 literal 0 HcmV?d00001 diff --git a/src/testcases/org/apache/poi/hssf/model/TestFormulaParser.java b/src/testcases/org/apache/poi/hssf/model/TestFormulaParser.java index e1909baa0a..3584e37ea4 100644 --- a/src/testcases/org/apache/poi/hssf/model/TestFormulaParser.java +++ b/src/testcases/org/apache/poi/hssf/model/TestFormulaParser.java @@ -20,6 +20,7 @@ package org.apache.poi.hssf.model; import junit.framework.AssertionFailedError; import junit.framework.TestCase; +import org.apache.poi.hssf.HSSFTestDataSamples; import org.apache.poi.hssf.model.FormulaParser.FormulaParseException; import org.apache.poi.hssf.record.formula.AbstractFunctionPtg; import org.apache.poi.hssf.record.formula.AddPtg; @@ -123,12 +124,15 @@ public final class TestFormulaParser extends TestCase { } public void testMacroFunction() { - HSSFWorkbook w = new HSSFWorkbook(); - Ptg[] ptg = FormulaParser.parse("FOO()", w); + // testNames.xls contains a VB function called 'myFunc' + HSSFWorkbook w = HSSFTestDataSamples.openSampleWorkbook("testNames.xls"); + + Ptg[] ptg = FormulaParser.parse("myFunc()", w); + // myFunc() actually takes 1 parameter. Don't know if POI will ever be able to detect this problem // the name gets encoded as the first arg NamePtg tname = (NamePtg) ptg[0]; - assertEquals("FOO", tname.toFormulaString(w)); + assertEquals("myFunc", tname.toFormulaString(w)); AbstractFunctionPtg tfunc = (AbstractFunctionPtg) ptg[1]; assertTrue(tfunc.isExternalFunction()); diff --git a/src/testcases/org/apache/poi/hssf/record/formula/TestExternalFunctionFormulas.java b/src/testcases/org/apache/poi/hssf/record/formula/TestExternalFunctionFormulas.java index 6d35dcdec0..1f7fb42ad3 100755 --- a/src/testcases/org/apache/poi/hssf/record/formula/TestExternalFunctionFormulas.java +++ b/src/testcases/org/apache/poi/hssf/record/formula/TestExternalFunctionFormulas.java @@ -17,11 +17,19 @@ package org.apache.poi.hssf.record.formula; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + import junit.framework.TestCase; import org.apache.poi.hssf.HSSFTestDataSamples; +import org.apache.poi.hssf.model.FormulaParser; +import org.apache.poi.hssf.usermodel.HSSFCell; +import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator; import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator.CellValue; /** * Tests for functions from external workbooks (e.g. YEARFRAC). * @@ -30,17 +38,45 @@ import org.apache.poi.hssf.usermodel.HSSFWorkbook; */ public final class TestExternalFunctionFormulas extends TestCase { - - /** - * tests NameXPtg.toFormulaString(Workbook) and logic in Workbook below that - */ - public void testReadFormulaContainingExternalFunction() { - HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("externalFunctionExample.xls"); - - String expectedFormula = "YEARFRAC(B1,C1)"; - HSSFSheet sht = wb.getSheetAt(0); - String cellFormula = sht.getRow(0).getCell((short)0).getCellFormula(); - assertEquals(expectedFormula, cellFormula); - } - + /** + * tests NameXPtg.toFormulaString(Workbook) and logic in Workbook below that + */ + public void testReadFormulaContainingExternalFunction() { + HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("externalFunctionExample.xls"); + + String expectedFormula = "YEARFRAC(B1,C1)"; + HSSFSheet sht = wb.getSheetAt(0); + String cellFormula = sht.getRow(0).getCell(0).getCellFormula(); + assertEquals(expectedFormula, cellFormula); + } + + public void testParse() { + HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("externalFunctionExample.xls"); + Ptg[] ptgs = FormulaParser.parse("YEARFRAC(B1,C1)", wb); + assertEquals(4, ptgs.length); + assertEquals(NameXPtg.class, ptgs[0].getClass()); + + wb.getSheetAt(0).getRow(0).createCell(6).setCellFormula("YEARFRAC(C1,B1)"); + if (false) { + // In case you fancy checking in excel + try { + File tempFile = File.createTempFile("testExtFunc", ".xls"); + FileOutputStream fout = new FileOutputStream(tempFile); + wb.write(fout); + fout.close(); + System.out.println("check out " + tempFile.getAbsolutePath()); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } + + public void DISABLEDtestEvaluate() { + HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("externalFunctionExample.xls"); + HSSFSheet sheet = wb.getSheetAt(0); + HSSFCell cell = sheet.getRow(0).getCell(0); + HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(sheet, wb); + CellValue evalResult = fe.evaluate(cell); + evalResult.toString(); + } } diff --git a/src/testcases/org/apache/poi/hssf/record/formula/eval/TestExternalFunction.java b/src/testcases/org/apache/poi/hssf/record/formula/eval/TestExternalFunction.java index f0cf099128..01aa5a36cc 100755 --- a/src/testcases/org/apache/poi/hssf/record/formula/eval/TestExternalFunction.java +++ b/src/testcases/org/apache/poi/hssf/record/formula/eval/TestExternalFunction.java @@ -17,8 +17,11 @@ package org.apache.poi.hssf.record.formula.eval; +import java.io.IOException; + import junit.framework.TestCase; +import org.apache.poi.hssf.HSSFTestDataSamples; import org.apache.poi.hssf.usermodel.HSSFCell; import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator; import org.apache.poi.hssf.usermodel.HSSFName; @@ -34,20 +37,33 @@ public final class TestExternalFunction extends TestCase { /** * Checks that an external function can get invoked from the formula evaluator. + * @throws IOException + */ public void testInvoke() { - HSSFWorkbook wb = new HSSFWorkbook(); - HSSFSheet sheet = wb.createSheet(); - wb.setSheetName(0, "Sheet1"); - HSSFRow row = sheet.createRow(0); - HSSFCell cell = row.createCell(0); - - HSSFName hssfName = wb.createName(); - hssfName.setNameName("myFunc"); - - cell.setCellFormula("myFunc()"); - String actualFormula=cell.getCellFormula(); - assertEquals("myFunc()", actualFormula); + + HSSFWorkbook wb; + HSSFSheet sheet; + HSSFCell cell; + if (false) { + // TODO - this code won't work until we can create user-defined functions directly with POI + wb = new HSSFWorkbook(); + sheet = wb.createSheet(); + wb.setSheetName(0, "Sheet1"); + HSSFName hssfName = wb.createName(); + hssfName.setNameName("myFunc"); + + } else { + // This sample spreadsheet already has a VB function called 'myFunc' + wb = HSSFTestDataSamples.openSampleWorkbook("testNames.xls"); + sheet = wb.getSheetAt(0); + HSSFRow row = sheet.createRow(0); + cell = row.createCell(1); + } + + cell.setCellFormula("myFunc()"); + String actualFormula=cell.getCellFormula(); + assertEquals("myFunc()", actualFormula); HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(sheet, wb); CellValue evalResult = fe.evaluate(cell); diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java b/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java index caec8e897f..2ee3cd5f34 100644 --- a/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java @@ -415,6 +415,9 @@ public final class TestBugs extends TestCase { for(int i = 0 ; i < wb.getNumberOfNames(); i++){ HSSFName name = wb.getNameAt(i); name.getNameName(); + if (name.isFunctionName()) { + continue; + } name.getReference(); } } -- 2.39.5