From 829b2eb084e12b53f58f409349497e3ba2805f79 Mon Sep 17 00:00:00 2001 From: Josh Micich Date: Mon, 11 Aug 2008 21:24:19 +0000 Subject: [PATCH] Refinements to fix for bug 45126. Excel does not produce any records like 'Excel_Name_Record_Titles_*' git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@684938 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/poi/hssf/model/LinkTable.java | 58 +- .../org/apache/poi/hssf/model/Workbook.java | 285 ++-- .../apache/poi/hssf/record/NameRecord.java | 1234 ++++++++--------- .../poi/hssf/usermodel/HSSFWorkbook.java | 127 +- .../apache/poi/hssf/usermodel/TestBugs.java | 6 +- .../poi/hssf/usermodel/TestHSSFWorkbook.java | 174 +-- .../poi/hssf/usermodel/TestNamedRange.java | 94 +- 7 files changed, 980 insertions(+), 998 deletions(-) diff --git a/src/java/org/apache/poi/hssf/model/LinkTable.java b/src/java/org/apache/poi/hssf/model/LinkTable.java index 1d8781d971..7367d08c2a 100755 --- a/src/java/org/apache/poi/hssf/model/LinkTable.java +++ b/src/java/org/apache/poi/hssf/model/LinkTable.java @@ -192,14 +192,18 @@ final class LinkTable { } - public NameRecord getSpecificBuiltinRecord(byte name, int sheetIndex) { + /** + * @param builtInCode a BUILTIN_~ constant from {@link NameRecord} + * @param sheetNumber 1-based sheet number + */ + public NameRecord getSpecificBuiltinRecord(byte builtInCode, int sheetNumber) { Iterator iterator = _definedNames.iterator(); while (iterator.hasNext()) { NameRecord record = ( NameRecord ) iterator.next(); //print areas are one based - if (record.getBuiltInName() == name && record.getIndexToSheet() == sheetIndex) { + if (record.getBuiltInName() == builtInCode && record.getSheetNumber() == sheetNumber) { return record; } } @@ -241,33 +245,31 @@ final class LinkTable { _definedNames.remove(namenum); } - /** - * checks if the given name is already included in the linkTable - */ - public boolean nameAlreadyExists(NameRecord name) - { - // Check to ensure no other names have the same case-insensitive name - for ( int i = getNumNames()-1; i >=0; i-- ) { - NameRecord rec = getNameRecord(i); - if (rec != name) { - if (isDuplicatedNames(name, rec)) - return true; - } - } - return false; - } - - private boolean isDuplicatedNames(NameRecord firstName, NameRecord lastName) - { - return lastName.getNameText().equalsIgnoreCase(firstName.getNameText()) - && isSameSheetNames(firstName, lastName); - } - private boolean isSameSheetNames(NameRecord firstName, NameRecord lastName) - { - return lastName.getEqualsToIndexToSheet() == firstName.getEqualsToIndexToSheet(); - } + /** + * checks if the given name is already included in the linkTable + */ + public boolean nameAlreadyExists(NameRecord name) + { + // Check to ensure no other names have the same case-insensitive name + for ( int i = getNumNames()-1; i >=0; i-- ) { + NameRecord rec = getNameRecord(i); + if (rec != name) { + if (isDuplicatedNames(name, rec)) + return true; + } + } + return false; + } + + private static boolean isDuplicatedNames(NameRecord firstName, NameRecord lastName) { + return lastName.getNameText().equalsIgnoreCase(firstName.getNameText()) + && isSameSheetNames(firstName, lastName); + } + private static boolean isSameSheetNames(NameRecord firstName, NameRecord lastName) { + return lastName.getSheetNumber() == firstName.getSheetNumber(); + } - + public short getIndexToSheet(short num) { return _externSheetRecord.getREFRecordAt(num).getIndexToFirstSupBook(); } diff --git a/src/java/org/apache/poi/hssf/model/Workbook.java b/src/java/org/apache/poi/hssf/model/Workbook.java index f80c41661d..12c5f90ec3 100644 --- a/src/java/org/apache/poi/hssf/model/Workbook.java +++ b/src/java/org/apache/poi/hssf/model/Workbook.java @@ -54,18 +54,13 @@ import java.util.Locale; * @see org.apache.poi.hssf.usermodel.HSSFWorkbook * @version 1.0-pre */ - -public class Workbook implements Model -{ - private static final int DEBUG = POILogger.DEBUG; - -// public static Workbook currentBook = null; +public final class Workbook implements Model { + private static final int DEBUG = POILogger.DEBUG; /** * constant used to set the "codepage" wherever "codepage" is set in records - * (which is duplciated in more than one record) + * (which is duplicated in more than one record) */ - private final static short CODEPAGE = ( short ) 0x4b0; /** @@ -105,8 +100,6 @@ public class Workbook implements Model private static POILogger log = POILogFactory.getLogger(Workbook.class); - protected static final String EXCEL_REPEATING_NAME_PREFIX_ = "Excel_Name_Record_Titles_"; - /** * Creates new Workbook with no intitialization --useless right now * @see #createWorkbook(List) @@ -250,9 +243,9 @@ public class Workbook implements Model for ( ; k < recs.size(); k++) { Record rec = ( Record ) recs.get(k); switch (rec.getSid()) { - case HyperlinkRecord.sid: - retval.hyperlinks.add(rec); - break; + case HyperlinkRecord.sid: + retval.hyperlinks.add(rec); + break; } } @@ -358,22 +351,22 @@ public class Workbook implements Model } - /**Retrieves the Builtin NameRecord that matches the name and index - * There shouldn't be too many names to make the sequential search too slow - * @param name byte representation of the builtin name to match - * @param sheetIndex Index to match - * @return null if no builtin NameRecord matches - */ - public NameRecord getSpecificBuiltinRecord(byte name, int sheetIndex) + /**Retrieves the Builtin NameRecord that matches the name and index + * There shouldn't be too many names to make the sequential search too slow + * @param name byte representation of the builtin name to match + * @param sheetNumber 1-based sheet number + * @return null if no builtin NameRecord matches + */ + public NameRecord getSpecificBuiltinRecord(byte name, int sheetNumber) { - return getOrCreateLinkTable().getSpecificBuiltinRecord(name, sheetIndex); + return getOrCreateLinkTable().getSpecificBuiltinRecord(name, sheetNumber); } - /** - * Removes the specified Builtin NameRecord that matches the name and index - * @param name byte representation of the builtin to match - * @param sheetIndex zero-based sheet reference - */ + /** + * Removes the specified Builtin NameRecord that matches the name and index + * @param name byte representation of the builtin to match + * @param sheetIndex zero-based sheet reference + */ public void removeBuiltinRecord(byte name, int sheetIndex) { linkTable.removeBuiltinRecord(name, sheetIndex); // TODO - do we need "this.records.remove(...);" similar to that in this.removeName(int namenum) {}? @@ -413,18 +406,18 @@ public class Workbook implements Model * Retrieves the index of the given font */ public int getFontIndex(FontRecord font) { - for(int i=0; i<=numfonts; i++) { + for(int i=0; i<=numfonts; i++) { FontRecord thisFont = ( FontRecord ) records.get((records.getFontpos() - (numfonts - 1)) + i); if(thisFont == font) { - // There is no 4! - if(i > 3) { - return (i+1); - } - return i; + // There is no 4! + if(i > 3) { + return (i+1); + } + return i; } - } - throw new IllegalArgumentException("Could not find that font!"); + } + throw new IllegalArgumentException("Could not find that font!"); } /** @@ -451,7 +444,7 @@ public class Workbook implements Model * so you'll need to update those yourself! */ public void removeFontRecord(FontRecord rec) { - records.remove(rec); // this updates FontPos for us + records.remove(rec); // this updates FontPos for us numfonts--; } @@ -536,20 +529,20 @@ public class Workbook implements Model BoundSheetRecord sheet = (BoundSheetRecord)boundsheets.get( sheetnum ); sheet.setSheetname(sheetname); sheet.setSheetnameLength( (byte)sheetname.length() ); - sheet.setCompressedUnicodeFlag( (byte)encoding ); + sheet.setCompressedUnicodeFlag( (byte)encoding ); } /** - * sets the order of appearance for a given sheet. - * - * @param sheetname the name of the sheet to reorder - * @param pos the position that we want to insert the sheet into (0 based) - */ + * sets the order of appearance for a given sheet. + * + * @param sheetname the name of the sheet to reorder + * @param pos the position that we want to insert the sheet into (0 based) + */ public void setSheetOrder(String sheetname, int pos ) { - int sheetNumber = getSheetIndex(sheetname); - //remove the sheet that needs to be reordered and place it in the spot we want - boundsheets.add(pos, boundsheets.remove(sheetNumber)); + int sheetNumber = getSheetIndex(sheetname); + //remove the sheet that needs to be reordered and place it in the spot we want + boundsheets.add(pos, boundsheets.remove(sheetNumber)); } /** @@ -627,11 +620,13 @@ public class Workbook implements Model } } - public void removeSheet(int sheetnum) { - if (boundsheets.size() > sheetnum) { - records.remove(records.getBspos() - (boundsheets.size() - 1) + sheetnum); -// records.bspos--; - boundsheets.remove(sheetnum); + /** + * @param sheetIndex zero based sheet index + */ + public void removeSheet(int sheetIndex) { + if (boundsheets.size() > sheetIndex) { + records.remove(records.getBspos() - (boundsheets.size() - 1) + sheetIndex); + boundsheets.remove(sheetIndex); fixTabIdRecord(); } @@ -642,20 +637,18 @@ public class Workbook implements Model // However, the sheet index must be adjusted, or // excel will break. (Sheet index is either 0 for // global, or 1 based index to sheet) - int sheetNum1Based = sheetnum + 1; + int sheetNum1Based = sheetIndex + 1; for(int i=0; i sheetNum1Based) { - // Bump down by one, so still points - // at the same sheet - nr.setEqualsToIndexToSheet((short)( - nr.getEqualsToIndexToSheet()-1 - )); - } + NameRecord nr = getNameRecord(i); + + if(nr.getSheetNumber() == sheetNum1Based) { + // Excel re-writes these to point to no sheet + nr.setSheetNumber(0); + } else if(nr.getSheetNumber() > sheetNum1Based) { + // Bump down by one, so still points + // at the same sheet + nr.setSheetNumber(nr.getSheetNumber()-1); + } } } @@ -721,7 +714,7 @@ public class Workbook implements Model * so you'll need to update those yourself! */ public void removeExFormatRecord(ExtendedFormatRecord rec) { - records.remove(rec); // this updates XfPos for us + records.remove(rec); // this updates XfPos for us numxfs--; } @@ -813,9 +806,9 @@ public class Workbook implements Model // // Record record = records.get(k); //// Let's skip RECALCID records, as they are only use for optimization -// if(record.getSid() != RecalcIdRecord.sid || ((RecalcIdRecord)record).isNeeded()) { +// if(record.getSid() != RecalcIdRecord.sid || ((RecalcIdRecord)record).isNeeded()) { // pos += record.serialize(pos, retval); // rec.length; -// } +// } // } // log.log(DEBUG, "Exiting serialize workbook"); // return retval; @@ -1821,10 +1814,10 @@ public class Workbook implements Model // from Russia with love ;) if ( Locale.getDefault().toString().equals( "ru_RU" ) ) { - retval.setCurrentCountry(( short ) 7); + retval.setCurrentCountry(( short ) 7); } else { - retval.setCurrentCountry(( short ) 1); + retval.setCurrentCountry(( short ) 1); } return retval; @@ -1950,10 +1943,10 @@ public class Workbook implements Model */ public NameRecord addName(NameRecord name) { - + LinkTable linkTable = getOrCreateLinkTable(); if(linkTable.nameAlreadyExists(name)) { - throw new IllegalArgumentException( + throw new IllegalArgumentException( "You are trying to assign a duplicated name record: " + name.getNameText()); } @@ -1964,27 +1957,18 @@ public class Workbook implements Model /** * Generates a NameRecord to represent a built-in region - * @return a new NameRecord unless the index is invalid + * @return a new NameRecord */ - public NameRecord createBuiltInName(byte builtInName, int index) - { - if (index == -1 || index+1 > Short.MAX_VALUE) - throw new IllegalArgumentException("Index is not valid ["+index+"]"); + public NameRecord createBuiltInName(byte builtInName, int sheetNumber) { + if (sheetNumber < 0 || sheetNumber+1 > Short.MAX_VALUE) { + throw new IllegalArgumentException("Sheet number ["+sheetNumber+"]is not valid "); + } - NameRecord name = new NameRecord(builtInName, (short)(index)); + NameRecord name = new NameRecord(builtInName, sheetNumber); - String prefix = EXCEL_REPEATING_NAME_PREFIX_ + index + "_"; - int cont = 0; while(linkTable.nameAlreadyExists(name)) { - cont++; - String altNameName = prefix + cont; - - // It would be better to set a different builtInName here. - // It does not seem possible, so we create it as a - // non built-in name from this point on - name = new NameRecord(); - name.setNameText(altNameName); - name.setNameTextLength((byte)altNameName.length()); + throw new RuntimeException("Builtin (" + builtInName + + ") already exists for sheet (" + sheetNumber + ")"); } addName(name); return name; @@ -1992,16 +1976,15 @@ public class Workbook implements Model /** removes the name - * @param namenum name index + * @param nameIndex name index */ - public void removeName(int namenum){ + public void removeName(int nameIndex){ - if (linkTable.getNumNames() > namenum) { + if (linkTable.getNumNames() > nameIndex) { int idx = findFirstRecordLocBySid(NameRecord.sid); - records.remove(idx + namenum); - linkTable.removeName(namenum); + records.remove(idx + nameIndex); + linkTable.removeName(nameIndex); } - } /** @@ -2011,19 +1994,19 @@ public class Workbook implements Model * @return the format id of a format that matches or -1 if none found and createIfNotFound */ public short getFormat(String format, boolean createIfNotFound) { - Iterator iterator; - for (iterator = formats.iterator(); iterator.hasNext();) { - FormatRecord r = (FormatRecord)iterator.next(); - if (r.getFormatString().equals(format)) { - return r.getIndexCode(); - } - } + Iterator iterator; + for (iterator = formats.iterator(); iterator.hasNext();) { + FormatRecord r = (FormatRecord)iterator.next(); + if (r.getFormatString().equals(format)) { + return r.getIndexCode(); + } + } - if (createIfNotFound) { - return createFormat(format); - } + if (createIfNotFound) { + return createFormat(format); + } - return -1; + return -1; } /** @@ -2031,7 +2014,7 @@ public class Workbook implements Model * @return ArrayList of FormatRecords in the notebook */ public ArrayList getFormats() { - return formats; + return formats; } /** @@ -2043,7 +2026,7 @@ public class Workbook implements Model */ public short createFormat( String format ) { -// ++xfpos; //These are to ensure that positions are updated properly +// ++xfpos; //These are to ensure that positions are updated properly // ++palettepos; // ++bspos; FormatRecord rec = new FormatRecord(); @@ -2113,7 +2096,7 @@ public class Workbook implements Model public List getHyperlinks() { - return hyperlinks; + return hyperlinks; } public List getRecords() @@ -2170,54 +2153,54 @@ public class Workbook implements Model * Finds the primary drawing group, if one already exists */ public void findDrawingGroup() { - // Need to find a DrawingGroupRecord that - // contains a EscherDggRecord - for(Iterator rit = records.iterator(); rit.hasNext();) { - Record r = (Record)rit.next(); - - if(r instanceof DrawingGroupRecord) { - DrawingGroupRecord dg = (DrawingGroupRecord)r; - dg.processChildRecords(); - - EscherContainerRecord cr = - dg.getEscherContainer(); - if(cr == null) { - continue; - } - - EscherDggRecord dgg = null; - for(Iterator it = cr.getChildRecords().iterator(); it.hasNext();) { - Object er = it.next(); - if(er instanceof EscherDggRecord) { - dgg = (EscherDggRecord)er; - } - } - - if(dgg != null) { - drawingManager = new DrawingManager2(dgg); - return; - } - } - } + // Need to find a DrawingGroupRecord that + // contains a EscherDggRecord + for(Iterator rit = records.iterator(); rit.hasNext();) { + Record r = (Record)rit.next(); + + if(r instanceof DrawingGroupRecord) { + DrawingGroupRecord dg = (DrawingGroupRecord)r; + dg.processChildRecords(); + + EscherContainerRecord cr = + dg.getEscherContainer(); + if(cr == null) { + continue; + } + + EscherDggRecord dgg = null; + for(Iterator it = cr.getChildRecords().iterator(); it.hasNext();) { + Object er = it.next(); + if(er instanceof EscherDggRecord) { + dgg = (EscherDggRecord)er; + } + } + + if(dgg != null) { + drawingManager = new DrawingManager2(dgg); + return; + } + } + } - // Look for the DrawingGroup record + // Look for the DrawingGroup record int dgLoc = findFirstRecordLocBySid(DrawingGroupRecord.sid); - // If there is one, does it have a EscherDggRecord? + // If there is one, does it have a EscherDggRecord? if(dgLoc != -1) { - DrawingGroupRecord dg = - (DrawingGroupRecord)records.get(dgLoc); - EscherDggRecord dgg = null; - for(Iterator it = dg.getEscherRecords().iterator(); it.hasNext();) { - Object er = it.next(); - if(er instanceof EscherDggRecord) { - dgg = (EscherDggRecord)er; - } - } - - if(dgg != null) { - drawingManager = new DrawingManager2(dgg); - } + DrawingGroupRecord dg = + (DrawingGroupRecord)records.get(dgLoc); + EscherDggRecord dgg = null; + for(Iterator it = dg.getEscherRecords().iterator(); it.hasNext();) { + Object er = it.next(); + if(er instanceof EscherDggRecord) { + dgg = (EscherDggRecord)er; + } + } + + if(dgg != null) { + drawingManager = new DrawingManager2(dgg); + } } } @@ -2379,7 +2362,7 @@ public class Workbook implements Model */ public boolean isWriteProtected() { if (this.fileShare == null) { - return false; + return false; } FileSharingRecord frec = getFileSharing(); return (frec.getReadOnly() == 1); diff --git a/src/java/org/apache/poi/hssf/record/NameRecord.java b/src/java/org/apache/poi/hssf/record/NameRecord.java index dbd796991c..bfc2ac4ed2 100644 --- a/src/java/org/apache/poi/hssf/record/NameRecord.java +++ b/src/java/org/apache/poi/hssf/record/NameRecord.java @@ -43,10 +43,10 @@ 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 = 0x18; //Docs says that it is 0x218 + /**Included for completeness sake, not implemented */ public final static byte BUILTIN_CONSOLIDATE_AREA = (byte)1; @@ -91,68 +91,68 @@ public final class NameRecord extends Record { /**Included for completeness sake, not implemented */ public final static byte BUILTIN_SHEET_TITLE = (byte)12; - - public static final short OPT_HIDDEN_NAME = (short) 0x0001; - public static final short OPT_FUNCTION_NAME = (short) 0x0002; - public static final short OPT_COMMAND_NAME = (short) 0x0004; - public static final short OPT_MACRO = (short) 0x0008; - public static final short OPT_COMPLEX = (short) 0x0010; - public static final short OPT_BUILTIN = (short) 0x0020; - public static final short OPT_BINDATA = (short) 0x1000; + + public static final short OPT_HIDDEN_NAME = (short) 0x0001; + public static final short OPT_FUNCTION_NAME = (short) 0x0002; + public static final short OPT_COMMAND_NAME = (short) 0x0004; + public static final short OPT_MACRO = (short) 0x0008; + public static final short OPT_COMPLEX = (short) 0x0010; + public static final short OPT_BUILTIN = (short) 0x0020; + public static final short OPT_BINDATA = (short) 0x1000; - - private short field_1_option_flag; - private byte field_2_keyboard_shortcut; - private byte field_3_length_name_text; - private short field_4_length_name_definition; - private short field_5_index_to_sheet; // unused: see field_6 - private short field_6_equals_to_index_to_sheet; - private byte field_7_length_custom_menu; - private byte field_8_length_description_text; - private byte field_9_length_help_topic_text; - private byte field_10_length_status_bar_text; - private byte field_11_compressed_unicode_flag; // not documented - private byte field_12_builtIn_name; - private String field_12_name_text; - private Stack field_13_name_definition; - private String field_14_custom_menu_text; - private String field_15_description_text; - private String field_16_help_topic_text; - private String field_17_status_bar_text; + + private short field_1_option_flag; + private byte field_2_keyboard_shortcut; + private byte field_3_length_name_text; + private short field_4_length_name_definition; + private short field_5_index_to_sheet; // unused: see field_6 + /** the one based sheet number. Zero if this is a global name */ + private int field_6_sheetNumber; + private byte field_7_length_custom_menu; + private byte field_8_length_description_text; + private byte field_9_length_help_topic_text; + private byte field_10_length_status_bar_text; + private byte field_11_compressed_unicode_flag; // not documented + private byte field_12_builtIn_name; + private String field_12_name_text; + private Stack field_13_name_definition; + private String field_14_custom_menu_text; + private String field_15_description_text; + private String field_16_help_topic_text; + private String field_17_status_bar_text; - /** Creates new NameRecord */ - public NameRecord() { - field_13_name_definition = new Stack(); + /** Creates new NameRecord */ + public NameRecord() { + field_13_name_definition = new Stack(); - field_12_name_text = new String(); - field_14_custom_menu_text = new String(); - field_15_description_text = new String(); - field_16_help_topic_text = new String(); - field_17_status_bar_text = new String(); - } + field_12_name_text = new String(); + field_14_custom_menu_text = new String(); + field_15_description_text = new String(); + field_16_help_topic_text = new String(); + field_17_status_bar_text = new String(); + } - /** - * Constructs a Name record and sets its fields appropriately. - * - * @param in the RecordInputstream to read the record from - */ - public NameRecord(RecordInputStream in) { - super(in); - } + /** + * Constructs a Name record and sets its fields appropriately. + * + * @param in the RecordInputstream to read the record from + */ + public NameRecord(RecordInputStream in) { + super(in); + } /** * Constructor to create a built-in named region * @param builtin Built-in byte representation for the name record, use the public constants - * @param index */ - public NameRecord(byte builtin, short index) + public NameRecord(byte builtin, int sheetNumber) { this(); this.field_12_builtIn_name = builtin; this.setOptionFlag((short)(this.getOptionFlag() | OPT_BUILTIN)); this.setNameTextLength((byte)1); - this.setEqualsToIndexToSheet(index); //the extern sheets are set through references + 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); @@ -163,268 +163,260 @@ public final class NameRecord extends Record { } - /** sets the option flag for the named range - * @param flag option flag - */ - public void setOptionFlag(short flag){ - field_1_option_flag = flag; - } - - - /** sets the keyboard shortcut - * @param shortcut keyboard shortcut - */ - public void setKeyboardShortcut(byte shortcut){ - field_2_keyboard_shortcut = shortcut; - } - - /** sets the name of the named range length - * @param length name length - */ - public void setNameTextLength(byte length){ - field_3_length_name_text = length; - } - - /** sets the definition (reference - formula) length - * @param length defenition length - */ - public void setDefinitionTextLength(short length){ - field_4_length_name_definition = length; - } - - /** sets the index number to the extern sheet (thats is what writen in documentation - * but as i saw , it works differently) - * @param index extern sheet index - */ - public void setUnused(short index){ - field_5_index_to_sheet = index; - - // field_6_equals_to_index_to_sheet is equal to field_5_index_to_sheet -// field_6_equals_to_index_to_sheet = index; - } - - public short getEqualsToIndexToSheet() - { - return field_6_equals_to_index_to_sheet; - } - - /** - * Convenience method to retrieve the index the name refers to. - * @see #getEqualsToIndexToSheet() - * @return short + /** sets the option flag for the named range + * @param flag option flag */ - public short getIndexToSheet() { - return getEqualsToIndexToSheet(); + public void setOptionFlag(short flag){ + field_1_option_flag = flag; } - /** - * @return function group - * @see FnGroupCountRecord - */ - public byte getFnGroup() { - int masked = field_1_option_flag & 0x0fc0; - return (byte) (masked >> 4); - } - public void setEqualsToIndexToSheet(short value) - { - field_6_equals_to_index_to_sheet = value; - } + /** sets the keyboard shortcut + * @param shortcut keyboard shortcut + */ + public void setKeyboardShortcut(byte shortcut){ + field_2_keyboard_shortcut = shortcut; + } + + /** sets the name of the named range length + * @param length name length + */ + public void setNameTextLength(byte length){ + field_3_length_name_text = length; + } + + /** sets the definition (reference - formula) length + * @param length defenition length + */ + public void setDefinitionTextLength(short length){ + field_4_length_name_definition = length; + } + + /** sets the index number to the extern sheet (thats is what writen in documentation + * but as i saw , it works differently) + * @param index extern sheet index + */ + public void setUnused(short index){ + field_5_index_to_sheet = index; + + // field_6_equals_to_index_to_sheet is equal to field_5_index_to_sheet +// field_6_equals_to_index_to_sheet = index; + } + + /** + * For named ranges, and built-in names + * @return the 1-based sheet number. Zero if this is a global name + */ + public int getSheetNumber() + { + return field_6_sheetNumber; + } + + /** + * @return function group + * @see FnGroupCountRecord + */ + public byte getFnGroup() { + int masked = field_1_option_flag & 0x0fc0; + return (byte) (masked >> 4); + } - /** sets the custom menu length - * @param length custom menu length - */ - public void setCustomMenuLength(byte length){ - field_7_length_custom_menu = length; - } + public void setSheetNumber(int value) + { + field_6_sheetNumber = value; + } - /** sets the length of named range description - * @param length description length - */ - public void setDescriptionTextLength(byte length){ - field_8_length_description_text = length; - } - /** sets the help topic length - * @param length help topic length - */ - public void setHelpTopicLength(byte length){ - field_9_length_help_topic_text = length; - } + /** sets the custom menu length + * @param length custom menu length + */ + public void setCustomMenuLength(byte length){ + field_7_length_custom_menu = length; + } - /** sets the length of the status bar text - * @param length status bar text length - */ - public void setStatusBarLength(byte length){ - field_10_length_status_bar_text = length; - } + /** sets the length of named range description + * @param length description length + */ + public void setDescriptionTextLength(byte length){ + field_8_length_description_text = length; + } - /** sets the compressed unicode flag - * @param flag unicode flag - */ - public void setCompressedUnicodeFlag(byte flag) { - field_11_compressed_unicode_flag = flag; - } + /** sets the help topic length + * @param length help topic length + */ + public void setHelpTopicLength(byte length){ + field_9_length_help_topic_text = length; + } - /** sets the name of the named range - * @param name named range name - */ - public void setNameText(String name){ - field_12_name_text = name; - setCompressedUnicodeFlag( - StringUtil.hasMultibyte(name) ? (byte)1 : (byte)0 - ); - } + /** sets the length of the status bar text + * @param length status bar text length + */ + public void setStatusBarLength(byte length){ + field_10_length_status_bar_text = length; + } - // public void setNameDefintion(String definition){ - // test = definition; - // } + /** sets the compressed unicode flag + * @param flag unicode flag + */ + public void setCompressedUnicodeFlag(byte flag) { + field_11_compressed_unicode_flag = flag; + } - /** sets the custom menu text - * @param text custom menu text - */ - public void setCustomMenuText(String text){ - field_14_custom_menu_text = text; - } + /** sets the name of the named range + * @param name named range name + */ + public void setNameText(String name){ + field_12_name_text = name; + setCompressedUnicodeFlag( + StringUtil.hasMultibyte(name) ? (byte)1 : (byte)0 + ); + } - /** sets the description text - * @param text the description text - */ - public void setDescriptionText(String text){ - field_15_description_text = text; - } + /** sets the custom menu text + * @param text custom menu text + */ + public void setCustomMenuText(String text){ + field_14_custom_menu_text = text; + } - /** sets the help topic text - * @param text help topix text - */ - public void setHelpTopicText(String text){ - field_16_help_topic_text = text; - } + /** sets the description text + * @param text the description text + */ + public void setDescriptionText(String text){ + field_15_description_text = text; + } - /** sets the status bar text - * @param text status bar text - */ - public void setStatusBarText(String text){ - field_17_status_bar_text = text; - } + /** sets the help topic text + * @param text help topix text + */ + public void setHelpTopicText(String text){ + field_16_help_topic_text = text; + } - /** gets the option flag - * @return option flag - */ - public short getOptionFlag(){ - return field_1_option_flag; - } + /** sets the status bar text + * @param text status bar text + */ + public void setStatusBarText(String text){ + field_17_status_bar_text = text; + } - /** returns the keyboard shortcut - * @return keyboard shortcut - */ - public byte getKeyboardShortcut(){ - return field_2_keyboard_shortcut ; - } + /** gets the option flag + * @return option flag + */ + public short getOptionFlag(){ + return field_1_option_flag; + } - /** - * gets the name length, in characters - * @return name length - */ - public byte getNameTextLength(){ - return field_3_length_name_text; - } - - /** - * gets the name length, in bytes - * @return raw name length - */ - public byte getRawNameTextLength(){ - if( (field_11_compressed_unicode_flag & 0x01) == 1 ) { - return (byte)(2 * field_3_length_name_text); - } - return field_3_length_name_text; - } + /** returns the keyboard shortcut + * @return keyboard shortcut + */ + public byte getKeyboardShortcut(){ + return field_2_keyboard_shortcut ; + } - /** get the definition length - * @return definition length - */ - public short getDefinitionLength(){ - return field_4_length_name_definition; - } + /** + * gets the name length, in characters + * @return name length + */ + public byte getNameTextLength(){ + return field_3_length_name_text; + } + + /** + * gets the name length, in bytes + * @return raw name length + */ + public byte getRawNameTextLength(){ + if( (field_11_compressed_unicode_flag & 0x01) == 1 ) { + return (byte)(2 * field_3_length_name_text); + } + return field_3_length_name_text; + } - /** gets the index to extern sheet - * @return index to extern sheet - */ - public short getUnused(){ - return field_5_index_to_sheet; - } + /** get the definition length + * @return definition length + */ + public short getDefinitionLength(){ + return field_4_length_name_definition; + } - /** gets the custom menu length - * @return custom menu length - */ - public byte getCustomMenuLength(){ - return field_7_length_custom_menu; - } + /** gets the index to extern sheet + * @return index to extern sheet + */ + public short getUnused(){ + return field_5_index_to_sheet; + } - /** gets the description text length - * @return description text length - */ - public byte getDescriptionTextLength(){ - return field_8_length_description_text; - } + /** gets the custom menu length + * @return custom menu length + */ + public byte getCustomMenuLength(){ + return field_7_length_custom_menu; + } - /** gets the help topic length - * @return help topic length - */ - public byte getHelpTopicLength(){ - return field_9_length_help_topic_text; - } + /** gets the description text length + * @return description text length + */ + public byte getDescriptionTextLength(){ + return field_8_length_description_text; + } - /** get the status bar text length - * @return satus bar length - */ - public byte getStatusBarLength(){ - return field_10_length_status_bar_text; - } + /** gets the help topic length + * @return help topic length + */ + public byte getHelpTopicLength(){ + return field_9_length_help_topic_text; + } - /** gets the name compressed Unicode flag - * @return compressed unicode flag - */ - public byte getCompressedUnicodeFlag() { - return field_11_compressed_unicode_flag; - } + /** get the status bar text length + * @return satus bar length + */ + public byte getStatusBarLength(){ + return field_10_length_status_bar_text; + } - /** - * @return true if name is hidden - */ - public boolean isHiddenName() { - return (field_1_option_flag & OPT_HIDDEN_NAME) != 0; - } + /** gets the name compressed Unicode flag + * @return compressed unicode flag + */ + public byte getCompressedUnicodeFlag() { + return field_11_compressed_unicode_flag; + } - /** - * @return true if name is a function - */ - public boolean isFunctionName() { - return (field_1_option_flag & OPT_FUNCTION_NAME) != 0; - } + /** + * @return true if name is hidden + */ + public boolean isHiddenName() { + return (field_1_option_flag & OPT_HIDDEN_NAME) != 0; + } - /** - * @return true if name is a command - */ - public boolean isCommandName() { - return (field_1_option_flag & OPT_COMMAND_NAME) != 0; - } + /** + * @return true if name is a function + */ + public boolean isFunctionName() { + return (field_1_option_flag & OPT_FUNCTION_NAME) != 0; + } - /** - * @return true if function macro or command macro - */ - public boolean isMacro() { - return (field_1_option_flag & OPT_MACRO) != 0; - } + /** + * @return true if name is a command + */ + public boolean isCommandName() { + return (field_1_option_flag & OPT_COMMAND_NAME) != 0; + } - /** - * @return true if array formula or user defined - */ - public boolean isComplexFunction() { - return (field_1_option_flag & OPT_COMPLEX) != 0; - } + /** + * @return true if function macro or command macro + */ + public boolean isMacro() { + return (field_1_option_flag & OPT_MACRO) != 0; + } + + /** + * @return true if array formula or user defined + */ + public boolean isComplexFunction() { + return (field_1_option_flag & OPT_COMPLEX) != 0; + } /**Convenience Function to determine if the name is a built-in name @@ -440,7 +432,7 @@ public final class NameRecord extends Record { */ public String getNameText(){ - return this.isBuiltInName() ? this.translateBuiltInName(this.getBuiltInName()) : field_12_name_text; + return this.isBuiltInName() ? this.translateBuiltInName(this.getBuiltInName()) : field_12_name_text; } /** Gets the Built In Name @@ -452,81 +444,81 @@ public final class NameRecord extends Record { } - /** gets the definition, reference (Formula) - * @return definition -- can be null if we cant parse ptgs - */ - public List getNameDefinition() { - return field_13_name_definition; - } + /** gets the definition, reference (Formula) + * @return definition -- can be null if we cant parse ptgs + */ + public List getNameDefinition() { + return field_13_name_definition; + } - public void setNameDefinition(Stack nameDefinition) { - field_13_name_definition = nameDefinition; - } + public void setNameDefinition(Stack nameDefinition) { + field_13_name_definition = nameDefinition; + } - /** get the custom menu text - * @return custom menu text - */ - public String getCustomMenuText(){ - return field_14_custom_menu_text; - } + /** get the custom menu text + * @return custom menu text + */ + public String getCustomMenuText(){ + return field_14_custom_menu_text; + } - /** gets the description text - * @return description text - */ - public String getDescriptionText(){ - return field_15_description_text; - } + /** gets the description text + * @return description text + */ + public String getDescriptionText(){ + return field_15_description_text; + } - /** get the help topic text - * @return gelp topic text - */ - public String getHelpTopicText(){ - return field_16_help_topic_text; - } + /** get the help topic text + * @return gelp topic text + */ + public String getHelpTopicText(){ + return field_16_help_topic_text; + } - /** gets the status bar text - * @return status bar text - */ - public String getStatusBarText(){ - return field_17_status_bar_text; - } + /** gets the status bar text + * @return status bar text + */ + public String getStatusBarText(){ + return field_17_status_bar_text; + } - /** - * called by constructor, should throw runtime exception in the event of a - * record passed with a differing ID. - * - * @param id alleged id for this record - */ - protected void validateSid(short id) { - if (id != sid) { - throw new RecordFormatException("NOT A valid Name RECORD"); - } - } - - /** - * called by the class that is responsible for writing this sucker. - * Subclasses should implement this so that their data is passed back in a + /** + * called by constructor, should throw runtime exception in the event of a + * record passed with a differing ID. + * + * @param id alleged id for this record + */ + protected void validateSid(short id) { + if (id != sid) { + throw new RecordFormatException("NOT A valid Name RECORD"); + } + } + + /** + * called by the class that is responsible for writing this sucker. + * Subclasses should implement this so that their data is passed back in a * @param offset to begin writing at * @param data byte array containing instance data - * @return number of bytes written - */ - public int serialize( int offset, byte[] data ) - { - LittleEndian.putShort( data, 0 + offset, sid ); - short size = (short)( 15 + getTextsLength() + getNameDefinitionSize()); - LittleEndian.putShort( data, 2 + offset, size ); - // size defined below - LittleEndian.putShort( data, 4 + offset, getOptionFlag() ); - data[6 + offset] = getKeyboardShortcut(); - data[7 + offset] = getNameTextLength(); - LittleEndian.putShort( data, 8 + offset, getDefinitionLength() ); - LittleEndian.putShort( data, 10 + offset, getUnused() ); - LittleEndian.putShort( data, 12 + offset, getEqualsToIndexToSheet() ); - data[14 + offset] = getCustomMenuLength(); - data[15 + offset] = getDescriptionTextLength(); - data[16 + offset] = getHelpTopicLength(); - data[17 + offset] = getStatusBarLength(); - data[18 + offset] = getCompressedUnicodeFlag(); + * @return number of bytes written + */ + public int serialize( int offset, byte[] data ) + { + LittleEndian.putShort( data, 0 + offset, sid ); + short size = (short)( 15 + getTextsLength() + getNameDefinitionSize()); + LittleEndian.putShort( data, 2 + offset, size ); + // size defined below + LittleEndian.putShort( data, 4 + offset, getOptionFlag() ); + data[6 + offset] = getKeyboardShortcut(); + data[7 + offset] = getNameTextLength(); + LittleEndian.putShort( data, 8 + offset, getDefinitionLength() ); + LittleEndian.putShort( data, 10 + offset, getUnused() ); + LittleEndian.putUShort( data, 12 + offset, field_6_sheetNumber); + data[14 + offset] = getCustomMenuLength(); + data[15 + offset] = getDescriptionTextLength(); + data[16 + offset] = getHelpTopicLength(); + data[17 + offset] = getStatusBarLength(); + data[18 + offset] = getCompressedUnicodeFlag(); int start_of_name_definition = 19 + field_3_length_name_text; @@ -544,320 +536,320 @@ 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(); + /* } */ + } - /** - * Gets the length of all texts, in bytes - * @return total length - */ - public int getTextsLength(){ - int result; + /** + * Gets the length of all texts, in bytes + * @return total length + */ + public int getTextsLength(){ + int result; - result = getRawNameTextLength() + getDescriptionTextLength() + - getHelpTopicLength() + getStatusBarLength(); + result = getRawNameTextLength() + getDescriptionTextLength() + + getHelpTopicLength() + getStatusBarLength(); - return result; - } - - private int getNameDefinitionSize() { - int result = 0; - List list = field_13_name_definition; - - for (int k = 0; k < list.size(); k++) - { - Ptg ptg = ( Ptg ) list.get(k); - - result += ptg.getSize(); - } - return result; - } + return result; + } + + private int getNameDefinitionSize() { + int result = 0; + List list = field_13_name_definition; + + for (int k = 0; k < list.size(); k++) + { + Ptg ptg = ( Ptg ) list.get(k); + + result += ptg.getSize(); + } + return result; + } - /** returns the record size - */ - public int getRecordSize(){ - int result; + /** returns the record size + */ + public int getRecordSize(){ + 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; + /** gets the extern sheet number + * @return extern sheet index + */ + public short getExternSheetNumber(){ + if (field_13_name_definition == null || field_13_name_definition.isEmpty()) return 0; + Ptg ptg = (Ptg) field_13_name_definition.peek(); + short result = 0; - if (ptg.getClass() == Area3DPtg.class){ - result = ((Area3DPtg) ptg).getExternSheetIndex(); + 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; + /** sets the extern sheet number + * @param externSheetNumber extern sheet number + */ + public void setExternSheetNumber(short externSheetNumber){ + Ptg ptg; - if (field_13_name_definition == null || field_13_name_definition.isEmpty()){ - field_13_name_definition = new Stack(); - ptg = createNewPtg(); - } else { - ptg = (Ptg) field_13_name_definition.peek(); - } + if (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); + private Ptg createNewPtg(){ + Ptg ptg = new Area3DPtg(); + field_13_name_definition.push(ptg); - return ptg; - } + return ptg; + } - /** gets the reference , the area only (range) - * @return area reference - */ + /** gets the reference , the area only (range) + * @return area reference + */ public String getAreaReference(HSSFWorkbook book){ return FormulaParser.toFormulaString(book, field_13_name_definition); } - /** sets the reference , the area only (range) - * @param ref area reference - */ - public void setAreaReference(String ref){ - //Trying to find if what ptg do we need - RangeAddress ra = new RangeAddress(ref); - Ptg oldPtg; - Ptg ptg; + /** sets the reference , the area only (range) + * @param ref area reference + */ + public void setAreaReference(String ref){ + //Trying to find if what ptg do we need + RangeAddress ra = new RangeAddress(ref); + Ptg oldPtg; + Ptg ptg; - if (field_13_name_definition==null ||field_13_name_definition.isEmpty()){ - field_13_name_definition = new Stack(); - oldPtg = createNewPtg(); - } else { - //Trying to find extern sheet index - oldPtg = (Ptg) field_13_name_definition.pop(); - } + 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()) { - // Is it contiguous or not? - AreaReference[] refs = - AreaReference.generateContiguous(ref); - this.setDefinitionTextLength((short)0); + if (ra.hasRange()) { + // Is it contiguous or not? + AreaReference[] refs = + AreaReference.generateContiguous(ref); + this.setDefinitionTextLength((short)0); - // Add the area reference(s) - for(int i=0; i 1) { - ptg = UnionPtg.instance; - field_13_name_definition.push(ptg); + } + // And then a union if we had more than one area + if(refs.length > 1) { + ptg = UnionPtg.instance; + field_13_name_definition.push(ptg); this.setDefinitionTextLength( (short)(getDefinitionLength() + ptg.getSize()) ); - } - } else { - ptg = new Ref3DPtg(); - ((Ref3DPtg) ptg).setExternSheetIndex(externSheetIndex); - ((Ref3DPtg) ptg).setArea(ref); - field_13_name_definition.push(ptg); - this.setDefinitionTextLength((short)ptg.getSize()); - } - } + } + } else { + ptg = new Ref3DPtg(); + ((Ref3DPtg) ptg).setExternSheetIndex(externSheetIndex); + ((Ref3DPtg) ptg).setArea(ref); + field_13_name_definition.push(ptg); + this.setDefinitionTextLength((short)ptg.getSize()); + } + } - /** - * called by the constructor, should set class level fields. Should throw - * runtime exception for bad/icomplete data. - * - * @param in the RecordInputstream to read the record from - */ - protected void fillFields(RecordInputStream in) { - field_1_option_flag = in.readShort(); - field_2_keyboard_shortcut = in.readByte(); - field_3_length_name_text = in.readByte(); - field_4_length_name_definition = in.readShort(); - field_5_index_to_sheet = in.readShort(); - field_6_equals_to_index_to_sheet= in.readShort(); - field_7_length_custom_menu = in.readByte(); - field_8_length_description_text = in.readByte(); - field_9_length_help_topic_text = in.readByte(); - field_10_length_status_bar_text = in.readByte(); - - //store the name in byte form if it's a builtin name - field_11_compressed_unicode_flag= in.readByte(); - if (this.isBuiltInName()) { - field_12_builtIn_name = in.readByte(); - } else { - if (field_11_compressed_unicode_flag == 1) { - field_12_name_text = in.readUnicodeLEString(field_3_length_name_text); - } else { - field_12_name_text = in.readCompressedUnicode(field_3_length_name_text); - } - } - - field_13_name_definition = Ptg.createParsedExpressionTokens(field_4_length_name_definition, in); - - //Who says that this can only ever be compressed unicode??? - field_14_custom_menu_text = in.readCompressedUnicode(LittleEndian.ubyteToInt(field_7_length_custom_menu)); - - field_15_description_text = in.readCompressedUnicode(LittleEndian.ubyteToInt(field_8_length_description_text)); - - field_16_help_topic_text = in.readCompressedUnicode(LittleEndian.ubyteToInt(field_9_length_help_topic_text)); - - field_17_status_bar_text = in.readCompressedUnicode(LittleEndian.ubyteToInt(field_10_length_status_bar_text)); - /*} */ - } + /** + * called by the constructor, should set class level fields. Should throw + * runtime exception for bad/icomplete data. + * + * @param in the RecordInputstream to read the record from + */ + protected void fillFields(RecordInputStream in) { + field_1_option_flag = in.readShort(); + field_2_keyboard_shortcut = in.readByte(); + field_3_length_name_text = in.readByte(); + field_4_length_name_definition = in.readShort(); + field_5_index_to_sheet = in.readShort(); + field_6_sheetNumber = in.readUShort(); + field_7_length_custom_menu = in.readByte(); + field_8_length_description_text = in.readByte(); + field_9_length_help_topic_text = in.readByte(); + field_10_length_status_bar_text = in.readByte(); + + //store the name in byte form if it's a builtin name + field_11_compressed_unicode_flag= in.readByte(); + if (this.isBuiltInName()) { + field_12_builtIn_name = in.readByte(); + } else { + if (field_11_compressed_unicode_flag == 1) { + field_12_name_text = in.readUnicodeLEString(field_3_length_name_text); + } else { + field_12_name_text = in.readCompressedUnicode(field_3_length_name_text); + } + } + + field_13_name_definition = Ptg.createParsedExpressionTokens(field_4_length_name_definition, in); + + //Who says that this can only ever be compressed unicode??? + field_14_custom_menu_text = in.readCompressedUnicode(LittleEndian.ubyteToInt(field_7_length_custom_menu)); + + field_15_description_text = in.readCompressedUnicode(LittleEndian.ubyteToInt(field_8_length_description_text)); + + field_16_help_topic_text = in.readCompressedUnicode(LittleEndian.ubyteToInt(field_9_length_help_topic_text)); + + field_17_status_bar_text = in.readCompressedUnicode(LittleEndian.ubyteToInt(field_10_length_status_bar_text)); + /*} */ + } - /** - * return the non static version of the id for this record. - */ - public short getSid() { - return sid; - } - /* - 20 00 - 00 - 01 - 1A 00 // sz = 0x1A = 26 - 00 00 - 01 00 - 00 - 00 - 00 - 00 - 00 // unicode flag - 07 // name - - 29 17 00 3B 00 00 00 00 FF FF 00 00 02 00 3B 00 //{ 26 - 00 07 00 07 00 00 00 FF 00 10 // } - - - - 20 00 - 00 - 01 - 0B 00 // sz = 0xB = 11 - 00 00 - 01 00 - 00 - 00 - 00 - 00 - 00 // unicode flag - 07 // name - - 3B 00 00 07 00 07 00 00 00 FF 00 // { 11 } + /** + * return the non static version of the id for this record. + */ + public short getSid() { + return sid; + } + /* + 20 00 + 00 + 01 + 1A 00 // sz = 0x1A = 26 + 00 00 + 01 00 + 00 + 00 + 00 + 00 + 00 // unicode flag + 07 // name + + 29 17 00 3B 00 00 00 00 FF FF 00 00 02 00 3B 00 //{ 26 + 00 07 00 07 00 00 00 FF 00 10 // } + + + + 20 00 + 00 + 01 + 0B 00 // sz = 0xB = 11 + 00 00 + 01 00 + 00 + 00 + 00 + 00 + 00 // unicode flag + 07 // name + + 3B 00 00 07 00 07 00 00 00 FF 00 // { 11 } */ - /* - 18, 00, - 1B, 00, - - 20, 00, - 00, - 01, - 0B, 00, - 00, - 00, - 00, - 00, - 00, - 07, - 3B 00 00 07 00 07 00 00 00 FF 00 ] - */ + /* + 18, 00, + 1B, 00, + + 20, 00, + 00, + 01, + 0B, 00, + 00, + 00, + 00, + 00, + 00, + 07, + 3B 00 00 07 00 07 00 00 00 FF 00 ] + */ - /** - * @see Object#toString() - */ - public String toString() { - StringBuffer buffer = new StringBuffer(); + /** + * @see Object#toString() + */ + public String toString() { + StringBuffer buffer = new StringBuffer(); - buffer.append("[NAME]\n"); - buffer.append(" .option flags = ").append( HexDump.toHex( field_1_option_flag ) ) - .append("\n"); - buffer.append(" .keyboard shortcut = ").append( HexDump.toHex( field_2_keyboard_shortcut ) ) - .append("\n"); - buffer.append(" .length of the name = ").append( field_3_length_name_text ) - .append("\n"); - buffer.append(" .size of the formula data = ").append( field_4_length_name_definition ) - .append("\n"); - buffer.append(" .unused = ").append( field_5_index_to_sheet ) - .append("\n"); - buffer.append(" .index to sheet (1-based, 0=Global) = ").append( field_6_equals_to_index_to_sheet ) - .append("\n"); - buffer.append(" .Length of menu text (character count) = ").append( field_7_length_custom_menu ) - .append("\n"); - buffer.append(" .Length of description text (character count) = ").append( field_8_length_description_text ) - .append("\n"); - buffer.append(" .Length of help topic text (character count) = ").append( field_9_length_help_topic_text ) - .append("\n"); - buffer.append(" .Length of status bar text (character count) = ").append( field_10_length_status_bar_text ) - .append("\n"); - buffer.append(" .Name (Unicode flag) = ").append( field_11_compressed_unicode_flag ) - .append("\n"); - buffer.append(" .Name (Unicode text) = ").append( getNameText() ) - .append("\n"); - - buffer.append(" .Parts (" + field_13_name_definition.size() +"):") - .append("\n"); - Iterator it = field_13_name_definition.iterator(); - while(it.hasNext()) { - Ptg ptg = (Ptg)it.next(); - buffer.append(" " + ptg.toString()).append("\n"); - } - - buffer.append(" .Menu text (Unicode string without length field) = ").append( field_14_custom_menu_text ) - .append("\n"); - buffer.append(" .Description text (Unicode string without length field) = ").append( field_15_description_text ) - .append("\n"); - buffer.append(" .Help topic text (Unicode string without length field) = ").append( field_16_help_topic_text ) - .append("\n"); - buffer.append(" .Status bar text (Unicode string without length field) = ").append( field_17_status_bar_text ) - .append("\n"); - buffer.append("[/NAME]\n"); - - return buffer.toString(); - } + buffer.append("[NAME]\n"); + buffer.append(" .option flags = ").append( HexDump.toHex( field_1_option_flag ) ) + .append("\n"); + buffer.append(" .keyboard shortcut = ").append( HexDump.toHex( field_2_keyboard_shortcut ) ) + .append("\n"); + buffer.append(" .length of the name = ").append( field_3_length_name_text ) + .append("\n"); + buffer.append(" .size of the formula data = ").append( field_4_length_name_definition ) + .append("\n"); + buffer.append(" .unused = ").append( field_5_index_to_sheet ) + .append("\n"); + buffer.append(" .index to sheet (1-based, 0=Global) = ").append( field_6_sheetNumber ) + .append("\n"); + buffer.append(" .Length of menu text (character count) = ").append( field_7_length_custom_menu ) + .append("\n"); + buffer.append(" .Length of description text (character count) = ").append( field_8_length_description_text ) + .append("\n"); + buffer.append(" .Length of help topic text (character count) = ").append( field_9_length_help_topic_text ) + .append("\n"); + buffer.append(" .Length of status bar text (character count) = ").append( field_10_length_status_bar_text ) + .append("\n"); + buffer.append(" .Name (Unicode flag) = ").append( field_11_compressed_unicode_flag ) + .append("\n"); + buffer.append(" .Name (Unicode text) = ").append( getNameText() ) + .append("\n"); + + buffer.append(" .Parts (" + field_13_name_definition.size() +"):") + .append("\n"); + Iterator it = field_13_name_definition.iterator(); + while(it.hasNext()) { + Ptg ptg = (Ptg)it.next(); + buffer.append(" " + ptg.toString()).append("\n"); + } + + buffer.append(" .Menu text (Unicode string without length field) = ").append( field_14_custom_menu_text ) + .append("\n"); + buffer.append(" .Description text (Unicode string without length field) = ").append( field_15_description_text ) + .append("\n"); + buffer.append(" .Help topic text (Unicode string without length field) = ").append( field_16_help_topic_text ) + .append("\n"); + buffer.append(" .Status bar text (Unicode string without length field) = ").append( field_17_status_bar_text ) + .append("\n"); + buffer.append("[/NAME]\n"); + + return buffer.toString(); + } /**Creates a human readable name for built in types * @return Unknown if the built-in name cannot be translated diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java b/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java index 5966c0d80f..0f8a14446a 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java @@ -61,6 +61,9 @@ import java.util.Stack; */ public class HSSFWorkbook extends POIDocument { + private static final int MAX_ROW = 0xFFFF; + private static final short MAX_COLUMN = (short)0x00FF; + private static final int DEBUG = POILogger.DEBUG; /** @@ -835,7 +838,8 @@ public class HSSFWorkbook extends POIDocument /** * Sets the repeating rows and columns for a sheet (as found in - * File->PageSetup->Sheet). This is function is included in the workbook + * 2003:File->PageSetup->Sheet, 2007:Page Layout->Print Titles). + * This is function is included in the workbook * because it creates/modifies name records which are stored at the * workbook level. *

@@ -865,10 +869,10 @@ public class HSSFWorkbook extends POIDocument // Check arguments if (startColumn == -1 && endColumn != -1) throw new IllegalArgumentException("Invalid column range specification"); if (startRow == -1 && endRow != -1) throw new IllegalArgumentException("Invalid row range specification"); - if (startColumn < -1 || startColumn >= 0xFF) throw new IllegalArgumentException("Invalid column range specification"); - if (endColumn < -1 || endColumn >= 0xFF) throw new IllegalArgumentException("Invalid column range specification"); - if (startRow < -1 || startRow > 65535) throw new IllegalArgumentException("Invalid row range specification"); - if (endRow < -1 || endRow > 65535) throw new IllegalArgumentException("Invalid row range specification"); + if (startColumn < -1 || startColumn >= MAX_COLUMN) throw new IllegalArgumentException("Invalid column range specification"); + if (endColumn < -1 || endColumn >= MAX_COLUMN) throw new IllegalArgumentException("Invalid column range specification"); + if (startRow < -1 || startRow > MAX_ROW) throw new IllegalArgumentException("Invalid row range specification"); + if (endRow < -1 || endRow > MAX_ROW) throw new IllegalArgumentException("Invalid row range specification"); if (startColumn > endColumn) throw new IllegalArgumentException("Invalid column range specification"); if (startRow > endRow) throw new IllegalArgumentException("Invalid row range specification"); @@ -880,50 +884,60 @@ public class HSSFWorkbook extends POIDocument boolean removingRange = startColumn == -1 && endColumn == -1 && startRow == -1 && endRow == -1; - boolean isNewRecord = false; - NameRecord nameRecord; - nameRecord = findExistingRowColHeaderNameRecord(sheetIndex); - if (removingRange ) - { - if (nameRecord != null) - workbook.removeName(findExistingRowColHeaderNameRecordIdx(sheetIndex+1)); + int rowColHeaderNameIndex = findExistingRowColHeaderNameRecordIdx(sheetIndex); + if (removingRange) { + if (rowColHeaderNameIndex >= 0) { + workbook.removeName(rowColHeaderNameIndex); + } return; } - if ( nameRecord == null ) - { - nameRecord = workbook.createBuiltInName(NameRecord.BUILTIN_PRINT_TITLE, sheetIndex+1); + boolean isNewRecord; + NameRecord nameRecord; + if (rowColHeaderNameIndex < 0) { //does a lot of the house keeping for builtin records, like setting lengths to zero etc + nameRecord = workbook.createBuiltInName(NameRecord.BUILTIN_PRINT_TITLE, sheetIndex+1); isNewRecord = true; + } else { + nameRecord = workbook.getNameRecord(rowColHeaderNameIndex); + isNewRecord = false; } short definitionTextLength = settingRowAndColumn ? (short)0x001a : (short)0x000b; - nameRecord.setDefinitionTextLength(definitionTextLength); + nameRecord.setDefinitionTextLength(definitionTextLength); // TODO - remove Stack ptgs = new Stack(); - if (settingRowAndColumn) - { - ptgs.add(new MemFuncPtg(23)); // TODO - where did constant '23' come from? + if (settingRowAndColumn) { + final int exprsSize = 2 * 11 + 1; // Area3DPtg.SIZE + UnionPtg.SIZE + ptgs.add(new MemFuncPtg(exprsSize)); } if (startColumn >= 0) { - Area3DPtg area3DPtg1 = new Area3DPtg(); - area3DPtg1.setExternSheetIndex(externSheetIndex); - area3DPtg1.setFirstColumn((short)startColumn); - area3DPtg1.setLastColumn((short)endColumn); - area3DPtg1.setFirstRow((short)0); - area3DPtg1.setLastRow((short)0xFFFF); - ptgs.add(area3DPtg1); + Area3DPtg colArea = new Area3DPtg(); + colArea.setExternSheetIndex(externSheetIndex); + colArea.setFirstColumn((short)startColumn); + colArea.setLastColumn((short)endColumn); + colArea.setFirstRow(0); + colArea.setLastRow(MAX_ROW); + colArea.setFirstColRelative(false); + colArea.setLastColRelative(false); + colArea.setFirstRowRelative(false); + colArea.setLastRowRelative(false); + ptgs.add(colArea); } if (startRow >= 0) { - Area3DPtg area3DPtg2 = new Area3DPtg(); - area3DPtg2.setExternSheetIndex(externSheetIndex); - area3DPtg2.setFirstColumn((short)0); - area3DPtg2.setLastColumn((short)0x00FF); - area3DPtg2.setFirstRow((short)startRow); - area3DPtg2.setLastRow((short)endRow); - ptgs.add(area3DPtg2); + Area3DPtg rowArea = new Area3DPtg(); + rowArea.setExternSheetIndex(externSheetIndex); + rowArea.setFirstColumn((short)0); + rowArea.setLastColumn(MAX_COLUMN); + rowArea.setFirstRow(startRow); + rowArea.setLastRow(endRow); + rowArea.setFirstColRelative(false); + rowArea.setLastColRelative(false); + rowArea.setFirstRowRelative(false); + rowArea.setLastRowRelative(false); + ptgs.add(rowArea); } if (settingRowAndColumn) { @@ -943,38 +957,31 @@ public class HSSFWorkbook extends POIDocument sheet.setActive(true); } - private NameRecord findExistingRowColHeaderNameRecord( int sheetIndex ) - { - int index = findExistingRowColHeaderNameRecordIdx(sheetIndex); - if (index == -1) - return null; - else - return (NameRecord)workbook.findNextRecordBySid(NameRecord.sid, index); - } - private int findExistingRowColHeaderNameRecordIdx( int sheetIndex ) - { - int index = 0; - NameRecord r = null; - while ((r = (NameRecord) workbook.findNextRecordBySid(NameRecord.sid, index)) != null) - { - int indexToSheet = r.getEqualsToIndexToSheet() -1; - if(indexToSheet > -1) { //ignore "GLOBAL" name records - int nameRecordSheetIndex = workbook.getSheetIndexFromExternSheetIndex(indexToSheet); - if (isRowColHeaderRecord( r ) && nameRecordSheetIndex == sheetIndex) - { - return index; - } + private int findExistingRowColHeaderNameRecordIdx(int sheetIndex) { + for(int defNameIndex =0; defNameIndex