diff --git a/src/java/org/apache/poi/hssf/model/FormulaParser.java b/src/java/org/apache/poi/hssf/model/FormulaParser.java index b89480e3c..c2a90e948 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 7367d08c2..9d1707558 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 12c5f90ec..5ad1ef28d 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 0d1823a7c..2b0744a91 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 java.util.ArrayList; +import java.util.List; + import org.apache.poi.util.LittleEndian; -import java.util.ArrayList; - /** - * 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 184895d35..000000000 --- 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 bfc2ac4ed..6c6c53a92 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; + //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(); - } + 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(); + 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()) { + 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 6755aa6f8..cb4eff840 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 f89e201bc..6b071c216 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 b4b698142..98ab39f05 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 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; - public NameXPtg(RecordInputStream in) { - field_1_ixals = in.readShort(); - field_2_ilbl = in.readShort(); - field_3_reserved = in.readShort(); - } + private NameXPtg(int sheetRefIndex, int nameNumber, int reserved) { + _sheetRefIndex = sheetRefIndex; + _nameNumber = nameNumber; + _reserved = reserved; + } - 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); - } + /** + * @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 int getSize() { - return SIZE; - } + public NameXPtg(RecordInputStream in) { + this(in.readUShort(), in.readUShort(), in.readUShort()); + } - 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 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 240be13f5..18aeaed8f 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 0f8a14446..1126e56c1 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java @@ -17,24 +17,6 @@ package org.apache.poi.hssf.usermodel; -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.hssf.model.Sheet; -import org.apache.poi.hssf.model.Workbook; -import org.apache.poi.hssf.record.*; -import org.apache.poi.hssf.record.formula.Area3DPtg; -import org.apache.poi.hssf.record.formula.MemFuncPtg; -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.util.POILogFactory; -import org.apache.poi.util.POILogger; - import java.io.ByteArrayInputStream; import java.io.FileNotFoundException; import java.io.IOException; @@ -47,6 +29,40 @@ 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.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.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.DirectoryNode; +import org.apache.poi.poifs.filesystem.POIFSFileSystem; +import org.apache.poi.util.POILogFactory; +import org.apache.poi.util.POILogger; + /** * 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 eba6607ad..aa08040fc 100644 Binary files a/src/testcases/org/apache/poi/hssf/data/FormulaEvalTestData.xls and b/src/testcases/org/apache/poi/hssf/data/FormulaEvalTestData.xls differ diff --git a/src/testcases/org/apache/poi/hssf/data/testNames.xls b/src/testcases/org/apache/poi/hssf/data/testNames.xls new file mode 100644 index 000000000..7ebbb633a Binary files /dev/null and b/src/testcases/org/apache/poi/hssf/data/testNames.xls differ diff --git a/src/testcases/org/apache/poi/hssf/model/TestFormulaParser.java b/src/testcases/org/apache/poi/hssf/model/TestFormulaParser.java index e1909baa0..3584e37ea 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 6d35dcdec..1f7fb42ad 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 f0cf09912..01aa5a36c 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 caec8e897..2ee3cd5f3 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(); } }