* 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 1d8781d97..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 )
sheetNum1Based) {
- // Bump down by one, so still points
- // at the same sheet
- nr.setEqualsToIndexToSheet((short)(
- nr.getEqualsToIndexToSheet()-1
- ));
- }
+ NameRecord nr = getNameRecord(i);
+
+ if(nr.getSheetNumber() == sheetNum1Based) {
+ // Excel re-writes these to point to no sheet
+ nr.setSheetNumber(0);
+ } else if(nr.getSheetNumber() > sheetNum1Based) {
+ // Bump down by one, so still points
+ // at the same sheet
+ nr.setSheetNumber(nr.getSheetNumber()-1);
+ }
}
}
@@ -721,7 +763,7 @@ public class Workbook implements Model
* so you'll need to update those yourself!
*/
public void removeExFormatRecord(ExtendedFormatRecord rec) {
- records.remove(rec); // this updates XfPos for us
+ records.remove(rec); // this updates XfPos for us
numxfs--;
}
@@ -813,9 +855,9 @@ public class Workbook implements Model
//
// Record record = records.get(k);
//// Let's skip RECALCID records, as they are only use for optimization
-// if(record.getSid() != RecalcIdRecord.sid || ((RecalcIdRecord)record).isNeeded()) {
+// if(record.getSid() != RecalcIdRecord.sid || ((RecalcIdRecord)record).isNeeded()) {
// pos += record.serialize(pos, retval); // rec.length;
-// }
+// }
// }
// log.log(DEBUG, "Exiting serialize workbook");
// return retval;
@@ -858,7 +900,7 @@ public class Workbook implements Model
if (record instanceof BoundSheetRecord) {
if(!wroteBoundSheets) {
for (int i = 0; i < boundsheets.size(); i++) {
- len+= ((BoundSheetRecord)boundsheets.get(i))
+ len+= getBoundSheetRec(i)
.serialize(pos+offset+len, data);
}
wroteBoundSheets = true;
@@ -1141,8 +1183,8 @@ public class Workbook implements Model
retval.setWidth(( short ) 0x3a5c);
retval.setHeight(( short ) 0x23be);
retval.setOptions(( short ) 0x38);
- retval.setSelectedTab(( short ) 0x0);
- retval.setDisplayedTab(( short ) 0x0);
+ retval.setActiveSheetIndex( 0x0);
+ retval.setFirstVisibleTab(0x0);
retval.setNumSelectedTabs(( short ) 1);
retval.setTabWidthRatio(( short ) 0x258);
return retval;
@@ -1821,10 +1863,10 @@ public class Workbook implements Model
// from Russia with love ;)
if ( Locale.getDefault().toString().equals( "ru_RU" ) ) {
- retval.setCurrentCountry(( short ) 7);
+ retval.setCurrentCountry(( short ) 7);
}
else {
- retval.setCurrentCountry(( short ) 1);
+ retval.setCurrentCountry(( short ) 1);
}
return retval;
@@ -1889,15 +1931,15 @@ public class Workbook implements Model
* @return sheet name
*/
public String findSheetNameFromExternSheet(short num){
- String result="";
- short indexToSheet = linkTable.getIndexToSheet(num);
+ int indexToSheet = linkTable.getIndexToSheet(num);
- if (indexToSheet>-1) { //error check, bail out gracefully!
- result = getSheetName(indexToSheet);
+ if (indexToSheet < 0) {
+ // TODO - what does '-1' mean here?
+ //error check, bail out gracefully!
+ return "";
}
-
- return result;
+ return getSheetName(indexToSheet);
}
/**
@@ -1950,10 +1992,10 @@ public class Workbook implements Model
*/
public NameRecord addName(NameRecord name)
{
-
+
LinkTable linkTable = getOrCreateLinkTable();
if(linkTable.nameAlreadyExists(name)) {
- throw new IllegalArgumentException(
+ throw new IllegalArgumentException(
"You are trying to assign a duplicated name record: "
+ name.getNameText());
}
@@ -1964,27 +2006,18 @@ public class Workbook implements Model
/**
* Generates a NameRecord to represent a built-in region
- * @return a new NameRecord unless the index is invalid
+ * @return a new NameRecord
*/
- public NameRecord createBuiltInName(byte builtInName, int index)
- {
- if (index == -1 || index+1 > Short.MAX_VALUE)
- throw new IllegalArgumentException("Index is not valid ["+index+"]");
+ public NameRecord createBuiltInName(byte builtInName, int sheetNumber) {
+ if (sheetNumber < 0 || sheetNumber+1 > Short.MAX_VALUE) {
+ throw new IllegalArgumentException("Sheet number ["+sheetNumber+"]is not valid ");
+ }
- NameRecord name = new NameRecord(builtInName, (short)(index));
+ NameRecord name = new NameRecord(builtInName, sheetNumber);
- String prefix = EXCEL_REPEATING_NAME_PREFIX_ + index + "_";
- int cont = 0;
while(linkTable.nameAlreadyExists(name)) {
- cont++;
- String altNameName = prefix + cont;
-
- // It would be better to set a different builtInName here.
- // It does not seem possible, so we create it as a
- // non built-in name from this point on
- name = new NameRecord();
- name.setNameText(altNameName);
- name.setNameTextLength((byte)altNameName.length());
+ throw new RuntimeException("Builtin (" + builtInName
+ + ") already exists for sheet (" + sheetNumber + ")");
}
addName(name);
return name;
@@ -1992,16 +2025,15 @@ public class Workbook implements Model
/** removes the name
- * @param namenum name index
+ * @param nameIndex name index
*/
- public void removeName(int namenum){
+ public void removeName(int nameIndex){
- if (linkTable.getNumNames() > namenum) {
+ if (linkTable.getNumNames() > nameIndex) {
int idx = findFirstRecordLocBySid(NameRecord.sid);
- records.remove(idx + namenum);
- linkTable.removeName(namenum);
+ records.remove(idx + nameIndex);
+ linkTable.removeName(nameIndex);
}
-
}
/**
@@ -2011,19 +2043,19 @@ public class Workbook implements Model
* @return the format id of a format that matches or -1 if none found and createIfNotFound
*/
public short getFormat(String format, boolean createIfNotFound) {
- Iterator iterator;
- for (iterator = formats.iterator(); iterator.hasNext();) {
- FormatRecord r = (FormatRecord)iterator.next();
- if (r.getFormatString().equals(format)) {
- return r.getIndexCode();
- }
- }
+ Iterator iterator;
+ for (iterator = formats.iterator(); iterator.hasNext();) {
+ FormatRecord r = (FormatRecord)iterator.next();
+ if (r.getFormatString().equals(format)) {
+ return r.getIndexCode();
+ }
+ }
- if (createIfNotFound) {
- return createFormat(format);
- }
+ if (createIfNotFound) {
+ return createFormat(format);
+ }
- return -1;
+ return -1;
}
/**
@@ -2031,7 +2063,7 @@ public class Workbook implements Model
* @return ArrayList of FormatRecords in the notebook
*/
public ArrayList getFormats() {
- return formats;
+ return formats;
}
/**
@@ -2043,7 +2075,7 @@ public class Workbook implements Model
*/
public short createFormat( String format )
{
-// ++xfpos; //These are to ensure that positions are updated properly
+// ++xfpos; //These are to ensure that positions are updated properly
// ++palettepos;
// ++bspos;
FormatRecord rec = new FormatRecord();
@@ -2113,7 +2145,7 @@ public class Workbook implements Model
public List getHyperlinks()
{
- return hyperlinks;
+ return hyperlinks;
}
public List getRecords()
@@ -2170,54 +2202,54 @@ public class Workbook implements Model
* Finds the primary drawing group, if one already exists
*/
public void findDrawingGroup() {
- // Need to find a DrawingGroupRecord that
- // contains a EscherDggRecord
- for(Iterator rit = records.iterator(); rit.hasNext();) {
- Record r = (Record)rit.next();
-
- if(r instanceof DrawingGroupRecord) {
- DrawingGroupRecord dg = (DrawingGroupRecord)r;
- dg.processChildRecords();
-
- EscherContainerRecord cr =
- dg.getEscherContainer();
- if(cr == null) {
- continue;
- }
-
- EscherDggRecord dgg = null;
- for(Iterator it = cr.getChildRecords().iterator(); it.hasNext();) {
- Object er = it.next();
- if(er instanceof EscherDggRecord) {
- dgg = (EscherDggRecord)er;
- }
- }
-
- if(dgg != null) {
- drawingManager = new DrawingManager2(dgg);
- return;
- }
- }
- }
+ // 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 +2411,7 @@ public class Workbook implements Model
*/
public boolean isWriteProtected() {
if (this.fileShare == null) {
- return false;
+ return false;
}
FileSharingRecord frec = getFileSharing();
return (frec.getReadOnly() == 1);
@@ -2419,6 +2451,8 @@ public class Workbook implements Model
public String resolveNameXText(int refIndex, int definedNameIndex) {
return linkTable.resolveNameXText(refIndex, definedNameIndex);
}
+
+ public NameXPtg getNameXPtg(String name) {
+ return getOrCreateLinkTable().getNameXPtg(name);
+ }
}
-
-
diff --git a/src/java/org/apache/poi/hssf/record/ExternSheetRecord.java b/src/java/org/apache/poi/hssf/record/ExternSheetRecord.java
index 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 dbd796991..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;
@@ -91,347 +88,338 @@ public final class NameRecord extends Record {
/**Included for completeness sake, not implemented
*/
public final static byte BUILTIN_SHEET_TITLE = (byte)12;
-
- public static final short OPT_HIDDEN_NAME = (short) 0x0001;
- public static final short OPT_FUNCTION_NAME = (short) 0x0002;
- public static final short OPT_COMMAND_NAME = (short) 0x0004;
- public static final short OPT_MACRO = (short) 0x0008;
- public static final short OPT_COMPLEX = (short) 0x0010;
- public static final short OPT_BUILTIN = (short) 0x0020;
- public static final short OPT_BINDATA = (short) 0x1000;
-
-
- private short field_1_option_flag;
- private byte field_2_keyboard_shortcut;
- private byte field_3_length_name_text;
- private short field_4_length_name_definition;
- private short field_5_index_to_sheet; // unused: see field_6
- private short field_6_equals_to_index_to_sheet;
- private byte field_7_length_custom_menu;
- private byte field_8_length_description_text;
- private byte field_9_length_help_topic_text;
- private byte field_10_length_status_bar_text;
- private byte field_11_compressed_unicode_flag; // not documented
- private byte field_12_builtIn_name;
- private String field_12_name_text;
- private Stack field_13_name_definition;
- private String field_14_custom_menu_text;
- private String field_15_description_text;
- private String field_16_help_topic_text;
- private String field_17_status_bar_text;
+
+ private static final class Option {
+ public static final int OPT_HIDDEN_NAME = 0x0001;
+ public static final int OPT_FUNCTION_NAME = 0x0002;
+ public static final int OPT_COMMAND_NAME = 0x0004;
+ public static final int OPT_MACRO = 0x0008;
+ public static final int OPT_COMPLEX = 0x0010;
+ public static final int OPT_BUILTIN = 0x0020;
+ public static final int OPT_BINDATA = 0x1000;
+ }
+
+ private short field_1_option_flag;
+ private byte field_2_keyboard_shortcut;
+ private byte field_3_length_name_text;
+ private short field_4_length_name_definition;
+ private short field_5_index_to_sheet; // unused: see field_6
+ /** the one based sheet number. Zero if this is a global name */
+ private int field_6_sheetNumber;
+ private byte field_7_length_custom_menu;
+ private byte field_8_length_description_text;
+ private byte field_9_length_help_topic_text;
+ private byte field_10_length_status_bar_text;
+ private byte field_11_compressed_unicode_flag; // not documented
+ private byte field_12_builtIn_name;
+ private String field_12_name_text;
+ private Stack field_13_name_definition;
+ private String field_14_custom_menu_text;
+ private String field_15_description_text;
+ private String field_16_help_topic_text;
+ private String field_17_status_bar_text;
- /** Creates new NameRecord */
- public NameRecord() {
- field_13_name_definition = new Stack();
+ /** 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
-
- //clearing these because they are not used with builtin records
+ this();
+ this.field_12_builtIn_name = builtin;
+ this.setOptionFlag((short)(this.field_1_option_flag | Option.OPT_BUILTIN));
+ this.setNameTextLength((byte)1);
+ field_6_sheetNumber = sheetNumber; //the extern sheets are set through references
+
+ //clearing these because they are not used with builtin records
this.setCustomMenuLength((byte)0);
this.setDescriptionTextLength((byte)0);
this.setHelpTopicLength((byte)0);
this.setStatusBarLength((byte)0);
-
+
}
- /** sets the option flag for the named range
- * @param flag option flag
- */
- public void setOptionFlag(short flag){
- field_1_option_flag = flag;
- }
+ /** sets the 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 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 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 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;
+ /** 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 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
+ * For named ranges, and built-in names
+ * @return the 1-based sheet number. Zero if this is a global name
*/
- public short getIndexToSheet() {
- return getEqualsToIndexToSheet();
+ 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);
- }
-
- public void setEqualsToIndexToSheet(short value)
- {
- field_6_equals_to_index_to_sheet = value;
- }
+ /**
+ * @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 a command
- */
- public boolean isCommandName() {
- return (field_1_option_flag & OPT_COMMAND_NAME) != 0;
- }
+ /**
+ * @return true if name is hidden
+ */
+ public boolean isHiddenName() {
+ return (field_1_option_flag & Option.OPT_HIDDEN_NAME) != 0;
+ }
+ /**
+ * @return true if name is a function
+ */
+ public boolean isFunctionName() {
+ return (field_1_option_flag & Option.OPT_FUNCTION_NAME) != 0;
+ }
- /**
- * @return true if function macro or command macro
- */
- public boolean isMacro() {
- return (field_1_option_flag & OPT_MACRO) != 0;
- }
-
- /**
- * @return true if array formula or user defined
- */
- public boolean isComplexFunction() {
- return (field_1_option_flag & OPT_COMPLEX) != 0;
- }
+ /**
+ * @return true if name is a command
+ */
+ public boolean isCommandName() {
+ return (field_1_option_flag & Option.OPT_COMMAND_NAME) != 0;
+ }
+ /**
+ * @return true if function macro or command macro
+ */
+ public boolean isMacro() {
+ return (field_1_option_flag & Option.OPT_MACRO) != 0;
+ }
+ /**
+ * @return true if array formula or user defined
+ */
+ public boolean isComplexFunction() {
+ return (field_1_option_flag & Option.OPT_COMPLEX) != 0;
+ }
/**Convenience Function to determine if the name is a built-in name
*/
public boolean isBuiltInName()
{
- return ((this.getOptionFlag() & OPT_BUILTIN) != 0);
+ return ((this.field_1_option_flag & Option.OPT_BUILTIN) != 0);
}
@@ -440,7 +428,7 @@ public final class NameRecord extends Record {
*/
public String getNameText(){
- return this.isBuiltInName() ? this.translateBuiltInName(this.getBuiltInName()) : field_12_name_text;
+ return this.isBuiltInName() ? this.translateBuiltInName(this.getBuiltInName()) : field_12_name_text;
}
/** Gets the Built In Name
@@ -448,85 +436,85 @@ public final class NameRecord extends Record {
*/
public byte getBuiltInName()
{
- return this.field_12_builtIn_name;
+ return this.field_12_builtIn_name;
}
- /** gets the definition, reference (Formula)
- * @return definition -- can be null if we cant parse ptgs
- */
- public List getNameDefinition() {
- return field_13_name_definition;
- }
+ /** 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,343 +532,343 @@ public final class NameRecord extends Record {
Ptg.serializePtgStack(field_13_name_definition, data, start_of_name_definition + offset );
- int start_of_custom_menu_text = start_of_name_definition + field_4_length_name_definition;
- StringUtil.putCompressedUnicode( getCustomMenuText(), data, start_of_custom_menu_text + offset );
+ int start_of_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);
- 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());
- }
- }
+ // 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()) );
+ }
+ } 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
*/
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 fabc85ce5..800f45dbf 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 0a99ff140..b6076e1ea 100644
--- a/src/java/org/apache/poi/hssf/record/formula/NameXPtg.java
+++ b/src/java/org/apache/poi/hssf/record/formula/NameXPtg.java
@@ -22,41 +22,55 @@ import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.hssf.record.RecordInputStream;
/**
- *
- * @author aviks
+ *
+ * @author aviks
*/
public final class NameXPtg extends OperandPtg {
- public final static short sid = 0x39;
- private final static int SIZE = 7;
- private short field_1_ixals; // index to REF entry in externsheet record
- private short field_2_ilbl; //index to defined name or externname table(1 based)
- private short field_3_reserved; // reserved must be 0
+ public 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(Workbook book)
- {
- // -1 to convert definedNameIndex from 1-based to zero-based
- return book.resolveNameXText(field_1_ixals, field_2_ilbl-1);
- }
-
- public byte getDefaultOperandClass() {
+ public void writeBytes(byte[] array, int offset) {
+ LittleEndian.putByte(array, offset + 0, sid + getPtgClass());
+ LittleEndian.putUShort(array, offset + 1, _sheetRefIndex);
+ LittleEndian.putUShort(array, offset + 3, _nameNumber);
+ LittleEndian.putUShort(array, offset + 5, _reserved);
+ }
+
+ public int getSize() {
+ return SIZE;
+ }
+
+ public String toFormulaString(Workbook book) {
+ // -1 to convert definedNameIndex from 1-based to zero-based
+ return book.resolveNameXText(_sheetRefIndex, _nameNumber - 1);
+ }
+
+ public byte getDefaultOperandClass() {
return Ptg.CLASS_VALUE;
}
}
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFName.java b/src/java/org/apache/poi/hssf/usermodel/HSSFName.java
index 31af2b773..8d7c0ada8 100644
--- a/src/java/org/apache/poi/hssf/usermodel/HSSFName.java
+++ b/src/java/org/apache/poi/hssf/usermodel/HSSFName.java
@@ -23,67 +23,57 @@ import org.apache.poi.hssf.util.RangeAddress;
import org.apache.poi.ss.usermodel.Name;
/**
- * Title: High Level Represantion of Named Range
- * 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 implements Name {
- private HSSFWorkbook book;
- private NameRecord name;
+ private HSSFWorkbook _book;
+ private NameRecord _definedNameRec;
/** Creates new HSSFName - called by HSSFWorkbook to create a sheet from
* scratch.
*
* @see org.apache.poi.hssf.usermodel.HSSFWorkbook#createName()
* @param name the Name Record
- * @param book lowlevel Workbook object associated with the sheet.
+ * @param book workbook object associated with the sheet.
*/
-
- protected HSSFName(HSSFWorkbook book, NameRecord name) {
- this.book = book;
- this.name = name;
+ /* package */ HSSFName(HSSFWorkbook book, NameRecord name) {
+ _book = book;
+ _definedNameRec = name;
}
/** Get the sheets name which this named range is referenced to
- * @return sheet name, which this named range refered to
+ * @return sheet name, which this named range referred to
*/
-
public String getSheetName() {
- String result ;
- short indexToExternSheet = name.getExternSheetNumber();
+ short indexToExternSheet = _definedNameRec.getExternSheetNumber();
- result = book.getWorkbook().findSheetNameFromExternSheet(indexToExternSheet);
-
- return result;
+ return _book.getWorkbook().findSheetNameFromExternSheet(indexToExternSheet);
}
/**
- * gets the name of the named range
- * @return named range name
+ * @return text name of this defined name
*/
-
public String getNameName(){
- String result = name.getNameText();
-
- return result;
+ return _definedNameRec.getNameText();
}
/**
* sets the name of the named range
* @param nameName named range name to set
*/
-
public void setNameName(String nameName){
- name.setNameText(nameName);
- name.setNameTextLength((byte)nameName.length());
- Workbook wb = book.getWorkbook();
+ _definedNameRec.setNameText(nameName);
+ _definedNameRec.setNameTextLength((byte)nameName.length());
+ Workbook wb = _book.getWorkbook();
//Check to ensure no other names have the same case-insensitive name
for ( int i = wb.getNumNames()-1; i >=0; i-- )
{
NameRecord rec = wb.getNameRecord(i);
- if (rec != name) {
+ if (rec != _definedNameRec) {
if (rec.getNameText().equalsIgnoreCase(getNameName()))
throw new IllegalArgumentException("The workbook already contains this name (case-insensitive)");
}
@@ -91,32 +81,25 @@ public class HSSFName implements Name {
}
/**
- * gets the reference of the named range
- * @return reference of the named range
+ * Note - this method only applies to named ranges
+ * @return the formula text defining the named range
*/
-
public String getReference() {
- String result;
- result = name.getAreaReference(book);
-
- return result;
+ if (_definedNameRec.isFunctionName()) {
+ throw new IllegalStateException("Only applicable to named ranges");
+ }
+ return _definedNameRec.getAreaReference(_book);
}
-
-
/**
* sets the sheet name which this named range referenced to
* @param sheetName the sheet name of the reference
*/
-
private void setSheetName(String sheetName){
- int sheetNumber = book.getSheetIndex(sheetName);
-
+ int sheetNumber = _book.getSheetIndex(sheetName);
short externSheetNumber = (short)
- book.getExternalSheetIndex(sheetNumber);
- name.setExternSheetNumber(externSheetNumber);
-// name.setIndexToSheet(externSheetNumber);
-
+ _book.getExternalSheetIndex(sheetNumber);
+ _definedNameRec.setExternSheetNumber(externSheetNumber);
}
@@ -124,7 +107,6 @@ public class HSSFName implements Name {
* sets the reference of this named range
* @param ref the reference to set
*/
-
public void setReference(String ref){
RangeAddress ra = new RangeAddress(ref);
@@ -136,8 +118,7 @@ public class HSSFName implements Name {
}
//allow the poi utilities to parse it out
- name.setAreaReference(ref);
-
+ _definedNameRec.setAreaReference(ref);
}
/**
@@ -149,4 +130,14 @@ public class HSSFName implements Name {
String ref = getReference();
return "#REF!".endsWith(ref);
}
+ public boolean isFunctionName() {
+ return _definedNameRec.isFunctionName();
+ }
+ public String toString() {
+ StringBuffer sb = new StringBuffer(64);
+ sb.append(getClass().getName()).append(" [");
+ sb.append(_definedNameRec.getNameText());
+ sb.append("]");
+ return sb.toString();
+ }
}
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java b/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java
index e663f38f2..c77c8266b 100644
--- a/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java
+++ b/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java
@@ -53,6 +53,7 @@ import org.apache.poi.hssf.record.UnicodeString;
import org.apache.poi.hssf.record.UnknownRecord;
import org.apache.poi.hssf.record.formula.Area3DPtg;
import org.apache.poi.hssf.record.formula.MemFuncPtg;
+import org.apache.poi.hssf.record.formula.NameXPtg;
import org.apache.poi.hssf.record.formula.UnionPtg;
import org.apache.poi.hssf.util.CellReference;
import org.apache.poi.hssf.util.SheetReferences;
@@ -77,6 +78,9 @@ import org.apache.poi.util.POILogger;
*/
public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.usermodel.Workbook
{
+ private static final int MAX_ROW = 0xFFFF;
+ private static final short MAX_COLUMN = (short)0x00FF;
+
private static final int DEBUG = POILogger.DEBUG;
/**
@@ -856,7 +860,8 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
/**
* Sets the repeating rows and columns for a sheet (as found in
- * File->PageSetup->Sheet). This is function is included in the workbook
+ * 2003:File->PageSetup->Sheet, 2007:Page Layout->Print Titles).
+ * This is function is included in the workbook
* because it creates/modifies name records which are stored at the
* workbook level.
*
@@ -886,10 +891,10 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
// Check arguments
if (startColumn == -1 && endColumn != -1) throw new IllegalArgumentException("Invalid column range specification");
if (startRow == -1 && endRow != -1) throw new IllegalArgumentException("Invalid row range specification");
- if (startColumn < -1 || startColumn >= 0xFF) throw new IllegalArgumentException("Invalid column range specification");
- if (endColumn < -1 || endColumn >= 0xFF) throw new IllegalArgumentException("Invalid column range specification");
- if (startRow < -1 || startRow > 65535) throw new IllegalArgumentException("Invalid row range specification");
- if (endRow < -1 || endRow > 65535) throw new IllegalArgumentException("Invalid row range specification");
+ if (startColumn < -1 || startColumn >= MAX_COLUMN) throw new IllegalArgumentException("Invalid column range specification");
+ if (endColumn < -1 || endColumn >= MAX_COLUMN) throw new IllegalArgumentException("Invalid column range specification");
+ if (startRow < -1 || startRow > MAX_ROW) throw new IllegalArgumentException("Invalid row range specification");
+ if (endRow < -1 || endRow > MAX_ROW) throw new IllegalArgumentException("Invalid row range specification");
if (startColumn > endColumn) throw new IllegalArgumentException("Invalid column range specification");
if (startRow > endRow) throw new IllegalArgumentException("Invalid row range specification");
@@ -901,50 +906,60 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
boolean removingRange =
startColumn == -1 && endColumn == -1 && startRow == -1 && endRow == -1;
- boolean isNewRecord = false;
- NameRecord nameRecord;
- nameRecord = findExistingRowColHeaderNameRecord(sheetIndex);
- if (removingRange )
- {
- if (nameRecord != null)
- workbook.removeName(findExistingRowColHeaderNameRecordIdx(sheetIndex+1));
+ int rowColHeaderNameIndex = findExistingRowColHeaderNameRecordIdx(sheetIndex);
+ if (removingRange) {
+ if (rowColHeaderNameIndex >= 0) {
+ workbook.removeName(rowColHeaderNameIndex);
+ }
return;
}
- if ( nameRecord == null )
- {
- nameRecord = workbook.createBuiltInName(NameRecord.BUILTIN_PRINT_TITLE, sheetIndex+1);
+ boolean isNewRecord;
+ NameRecord nameRecord;
+ if (rowColHeaderNameIndex < 0) {
//does a lot of the house keeping for builtin records, like setting lengths to zero etc
+ nameRecord = workbook.createBuiltInName(NameRecord.BUILTIN_PRINT_TITLE, sheetIndex+1);
isNewRecord = true;
+ } else {
+ nameRecord = workbook.getNameRecord(rowColHeaderNameIndex);
+ isNewRecord = false;
}
short definitionTextLength = settingRowAndColumn ? (short)0x001a : (short)0x000b;
- nameRecord.setDefinitionTextLength(definitionTextLength);
+ nameRecord.setDefinitionTextLength(definitionTextLength); // TODO - remove
Stack ptgs = new Stack();
- if (settingRowAndColumn)
- {
- ptgs.add(new MemFuncPtg(23)); // TODO - where did constant '23' come from?
+ if (settingRowAndColumn) {
+ final int exprsSize = 2 * 11 + 1; // Area3DPtg.SIZE + UnionPtg.SIZE
+ ptgs.add(new MemFuncPtg(exprsSize));
}
if (startColumn >= 0)
{
- Area3DPtg area3DPtg1 = new Area3DPtg();
- area3DPtg1.setExternSheetIndex(externSheetIndex);
- area3DPtg1.setFirstColumn((short)startColumn);
- area3DPtg1.setLastColumn((short)endColumn);
- area3DPtg1.setFirstRow((short)0);
- area3DPtg1.setLastRow((short)0xFFFF);
- ptgs.add(area3DPtg1);
+ Area3DPtg colArea = new Area3DPtg();
+ colArea.setExternSheetIndex(externSheetIndex);
+ colArea.setFirstColumn((short)startColumn);
+ colArea.setLastColumn((short)endColumn);
+ colArea.setFirstRow(0);
+ colArea.setLastRow(MAX_ROW);
+ colArea.setFirstColRelative(false);
+ colArea.setLastColRelative(false);
+ colArea.setFirstRowRelative(false);
+ colArea.setLastRowRelative(false);
+ ptgs.add(colArea);
}
if (startRow >= 0)
{
- Area3DPtg area3DPtg2 = new Area3DPtg();
- area3DPtg2.setExternSheetIndex(externSheetIndex);
- area3DPtg2.setFirstColumn((short)0);
- area3DPtg2.setLastColumn((short)0x00FF);
- area3DPtg2.setFirstRow((short)startRow);
- area3DPtg2.setLastRow((short)endRow);
- ptgs.add(area3DPtg2);
+ Area3DPtg rowArea = new Area3DPtg();
+ rowArea.setExternSheetIndex(externSheetIndex);
+ rowArea.setFirstColumn((short)0);
+ rowArea.setLastColumn(MAX_COLUMN);
+ rowArea.setFirstRow(startRow);
+ rowArea.setLastRow(endRow);
+ rowArea.setFirstColRelative(false);
+ rowArea.setLastColRelative(false);
+ rowArea.setFirstRowRelative(false);
+ rowArea.setLastRowRelative(false);
+ ptgs.add(rowArea);
}
if (settingRowAndColumn)
{
@@ -964,38 +979,31 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
sheet.setActive(true);
}
- private NameRecord findExistingRowColHeaderNameRecord( int sheetIndex )
- {
- int index = findExistingRowColHeaderNameRecordIdx(sheetIndex);
- if (index == -1)
- return null;
- else
- return (NameRecord)workbook.findNextRecordBySid(NameRecord.sid, index);
- }
- private int findExistingRowColHeaderNameRecordIdx( int sheetIndex )
- {
- int index = 0;
- NameRecord r = null;
- while ((r = (NameRecord) workbook.findNextRecordBySid(NameRecord.sid, index)) != null)
- {
- int indexToSheet = r.getEqualsToIndexToSheet() -1;
- if(indexToSheet > -1) { //ignore "GLOBAL" name records
- int nameRecordSheetIndex = workbook.getSheetIndexFromExternSheetIndex(indexToSheet);
- if (isRowColHeaderRecord( r ) && nameRecordSheetIndex == sheetIndex)
- {
- return index;
- }
+ private int findExistingRowColHeaderNameRecordIdx(int sheetIndex) {
+ for(int defNameIndex =0; defNameIndex 0)
- {
- _cbt.adjustForDelete(0, 0, cpMin);
- _pbt.adjustForDelete(0, 0, cpMin);
- }
+
+ // Now load the rest of the properties, which need to be adjusted
+ // for where text really begin
+ _cbt = new CHPBinTable(_mainStream, _tableStream, _fib.getFcPlcfbteChpx(), _fib.getLcbPlcfbteChpx(), cpMin, _tpt);
+ _pbt = new PAPBinTable(_mainStream, _tableStream, _dataStream, _fib.getFcPlcfbtePapx(), _fib.getLcbPlcfbtePapx(), cpMin, _tpt);
// Read FSPA and Escher information
_fspa = new FSPATable(_tableStream, _fib.getFcPlcspaMom(), _fib.getLcbPlcspaMom(), getTextTable().getTextPieces());
@@ -252,7 +253,7 @@ public class HWPFDocument extends POIDocument
// read in the pictures stream
_pictures = new PicturesTable(this, _dataStream, _mainStream, _fspa, _dgg);
- _st = new SectionTable(_mainStream, _tableStream, _fib.getFcPlcfsed(), _fib.getLcbPlcfsed(), fcMin, getTextTable().getTextPieces());
+ _st = new SectionTable(_mainStream, _tableStream, _fib.getFcPlcfsed(), _fib.getLcbPlcfsed(), fcMin, _tpt, _cpSplit);
_ss = new StyleSheet(_tableStream, _fib.getFcStshf());
_ft = new FontTable(_tableStream, _fib.getFcSttbfffn(), _fib.getLcbSttbfffn());
@@ -316,6 +317,11 @@ public class HWPFDocument extends POIDocument
* document, but excludes any headers and footers.
*/
public Range getRange() {
+ // First up, trigger a full-recalculate
+ // Needed in case of deletes etc
+ getOverallRange();
+
+ // Now, return the real one
return new Range(
_cpSplit.getMainDocumentStart(),
_cpSplit.getMainDocumentEnd(),
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/BytePropertyNode.java b/src/scratchpad/src/org/apache/poi/hwpf/model/BytePropertyNode.java
new file mode 100644
index 000000000..d22edb632
--- /dev/null
+++ b/src/scratchpad/src/org/apache/poi/hwpf/model/BytePropertyNode.java
@@ -0,0 +1,60 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+package org.apache.poi.hwpf.model;
+
+/**
+ * Normally PropertyNodes only ever work in characters, but
+ * a few cases actually store bytes, and this lets everything
+ * still work despite that.
+ * It handles the conversion as required between bytes
+ * and characters.
+ */
+public abstract class BytePropertyNode extends PropertyNode {
+ private boolean isUnicode;
+
+ /**
+ * @param fcStart The start of the text for this property, in _bytes_
+ * @param fcEnd The end of the text for this property, in _bytes_
+ */
+ public BytePropertyNode(int fcStart, int fcEnd, Object buf, boolean isUnicode) {
+ super(
+ generateCp(fcStart, isUnicode),
+ generateCp(fcEnd, isUnicode),
+ buf
+ );
+ this.isUnicode = isUnicode;
+ }
+ private static int generateCp(int val, boolean isUnicode) {
+ if(isUnicode)
+ return val/2;
+ return val;
+ }
+
+ public boolean isUnicode() {
+ return isUnicode;
+ }
+ public int getStartBytes() {
+ if(isUnicode)
+ return getStart()*2;
+ return getStart();
+ }
+ public int getEndBytes() {
+ if(isUnicode)
+ return getEnd()*2;
+ return getEnd();
+ }
+}
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/CHPBinTable.java b/src/scratchpad/src/org/apache/poi/hwpf/model/CHPBinTable.java
index 48c5a9d8b..f46aee80a 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/model/CHPBinTable.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/model/CHPBinTable.java
@@ -37,6 +37,8 @@ public class CHPBinTable
/** List of character properties.*/
protected ArrayList _textRuns = new ArrayList();
+ /** So we can know if things are unicode or not */
+ private TextPieceTable tpt;
public CHPBinTable()
{
@@ -52,9 +54,10 @@ public class CHPBinTable
* @param fcMin
*/
public CHPBinTable(byte[] documentStream, byte[] tableStream, int offset,
- int size, int fcMin)
+ int size, int fcMin, TextPieceTable tpt)
{
PlexOfCps binTable = new PlexOfCps(tableStream, offset, size, 4);
+ this.tpt = tpt;
int length = binTable.length();
for (int x = 0; x < length; x++)
@@ -65,7 +68,7 @@ public class CHPBinTable
int pageOffset = POIFSConstants.BIG_BLOCK_SIZE * pageNum;
CHPFormattedDiskPage cfkp = new CHPFormattedDiskPage(documentStream,
- pageOffset, fcMin);
+ pageOffset, fcMin, tpt);
int fkpSize = cfkp.size();
@@ -116,7 +119,14 @@ public class CHPBinTable
public void insert(int listIndex, int cpStart, SprmBuffer buf)
{
- CHPX insertChpx = new CHPX(cpStart, cpStart, buf);
+ boolean needsToBeUnicode = tpt.isUnicodeAtCharOffset(cpStart);
+
+ CHPX insertChpx = new CHPX(0, 0, buf, needsToBeUnicode);
+
+ // Ensure character offsets are really characters
+ insertChpx.setStart(cpStart);
+ insertChpx.setEnd(cpStart);
+
if (listIndex == _textRuns.size())
{
_textRuns.add(insertChpx);
@@ -126,7 +136,16 @@ public class CHPBinTable
CHPX chpx = (CHPX)_textRuns.get(listIndex);
if (chpx.getStart() < cpStart)
{
- CHPX clone = new CHPX(cpStart, chpx.getEnd(), chpx.getSprmBuf());
+ // Copy the properties of the one before to afterwards
+ // Will go:
+ // Original, until insert at point
+ // New one
+ // Clone of original, on to the old end
+ CHPX clone = new CHPX(0, 0, chpx.getSprmBuf(), needsToBeUnicode);
+ // Again ensure contains character based offsets no matter what
+ clone.setStart(cpStart);
+ clone.setEnd(chpx.getEnd());
+
chpx.setEnd(cpStart);
_textRuns.add(listIndex + 1, insertChpx);
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/CHPFormattedDiskPage.java b/src/scratchpad/src/org/apache/poi/hwpf/model/CHPFormattedDiskPage.java
index cd1a8c24f..e6b302300 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/model/CHPFormattedDiskPage.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/model/CHPFormattedDiskPage.java
@@ -55,13 +55,14 @@ public class CHPFormattedDiskPage extends FormattedDiskPage
* This constructs a CHPFormattedDiskPage from a raw fkp (512 byte array
* read from a Word file).
*/
- public CHPFormattedDiskPage(byte[] documentStream, int offset, int fcMin)
+ public CHPFormattedDiskPage(byte[] documentStream, int offset, int fcMin, TextPieceTable tpt)
{
super(documentStream, offset);
for (int x = 0; x < _crun; x++)
{
- _chpxList.add(new CHPX(getStart(x) - fcMin, getEnd(x) - fcMin, getGrpprl(x)));
+ boolean isUnicode = tpt.isUnicodeAtByteOffset( getStart(x) );
+ _chpxList.add(new CHPX(getStart(x) - fcMin, getEnd(x) - fcMin, getGrpprl(x), isUnicode));
}
}
@@ -157,7 +158,7 @@ public class CHPFormattedDiskPage extends FormattedDiskPage
chpx = (CHPX)_chpxList.get(x);
byte[] grpprl = chpx.getGrpprl();
- LittleEndian.putInt(buf, fcOffset, chpx.getStart() + fcMin);
+ LittleEndian.putInt(buf, fcOffset, chpx.getStartBytes() + fcMin);
grpprlOffset -= (1 + grpprl.length);
grpprlOffset -= (grpprlOffset % 2);
buf[offsetOffset] = (byte)(grpprlOffset/2);
@@ -168,7 +169,7 @@ public class CHPFormattedDiskPage extends FormattedDiskPage
fcOffset += FC_SIZE;
}
// put the last chpx's end in
- LittleEndian.putInt(buf, fcOffset, chpx.getEnd() + fcMin);
+ LittleEndian.putInt(buf, fcOffset, chpx.getEndBytes() + fcMin);
return buf;
}
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/CHPX.java b/src/scratchpad/src/org/apache/poi/hwpf/model/CHPX.java
index 3e7b5b11f..a89036c73 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/model/CHPX.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/model/CHPX.java
@@ -25,22 +25,26 @@ import org.apache.poi.hwpf.sprm.SprmBuffer;
import org.apache.poi.hwpf.sprm.CharacterSprmUncompressor;
/**
- * Comment me
+ * DANGER - works in bytes!
+ *
+ * Make sure you call getStart() / getEnd() when you want characters
+ * (normal use), but getStartByte() / getEndByte() when you're
+ * reading in / writing out!
*
* @author Ryan Ackley
*/
-public class CHPX extends PropertyNode
+public class CHPX extends BytePropertyNode
{
- public CHPX(int fcStart, int fcEnd, byte[] grpprl)
+ public CHPX(int fcStart, int fcEnd, byte[] grpprl, boolean isUnicode)
{
- super(fcStart, fcEnd, new SprmBuffer(grpprl));
+ super(fcStart, fcEnd, new SprmBuffer(grpprl), isUnicode);
}
- public CHPX(int fcStart, int fcEnd, SprmBuffer buf)
+ public CHPX(int fcStart, int fcEnd, SprmBuffer buf, boolean isUnicode)
{
- super(fcStart, fcEnd, buf);
+ super(fcStart, fcEnd, buf, isUnicode);
}
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/PAPBinTable.java b/src/scratchpad/src/org/apache/poi/hwpf/model/PAPBinTable.java
index 6f141d761..ed47b59c5 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/model/PAPBinTable.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/model/PAPBinTable.java
@@ -39,14 +39,18 @@ public class PAPBinTable
protected ArrayList _paragraphs = new ArrayList();
byte[] _dataStream;
+ /** So we can know if things are unicode or not */
+ private TextPieceTable tpt;
+
public PAPBinTable()
{
}
public PAPBinTable(byte[] documentStream, byte[] tableStream, byte[] dataStream, int offset,
- int size, int fcMin)
+ int size, int fcMin, TextPieceTable tpt)
{
PlexOfCps binTable = new PlexOfCps(tableStream, offset, size, 4);
+ this.tpt = tpt;
int length = binTable.length();
for (int x = 0; x < length; x++)
@@ -57,13 +61,14 @@ public class PAPBinTable
int pageOffset = POIFSConstants.BIG_BLOCK_SIZE * pageNum;
PAPFormattedDiskPage pfkp = new PAPFormattedDiskPage(documentStream,
- dataStream, pageOffset, fcMin);
+ dataStream, pageOffset, fcMin, tpt);
int fkpSize = pfkp.size();
for (int y = 0; y < fkpSize; y++)
{
- _paragraphs.add(pfkp.getPAPX(y));
+ PAPX papx = pfkp.getPAPX(y);
+ _paragraphs.add(papx);
}
}
_dataStream = dataStream;
@@ -71,7 +76,14 @@ public class PAPBinTable
public void insert(int listIndex, int cpStart, SprmBuffer buf)
{
- PAPX forInsert = new PAPX(cpStart, cpStart, buf, _dataStream);
+ boolean needsToBeUnicode = tpt.isUnicodeAtCharOffset(cpStart);
+
+ PAPX forInsert = new PAPX(0, 0, buf, _dataStream, needsToBeUnicode);
+
+ // Ensure character offsets are really characters
+ forInsert.setStart(cpStart);
+ forInsert.setEnd(cpStart);
+
if (listIndex == _paragraphs.size())
{
_paragraphs.add(forInsert);
@@ -90,10 +102,21 @@ public class PAPBinTable
{
exc.printStackTrace();
}
+
+ // Copy the properties of the one before to afterwards
+ // Will go:
+ // Original, until insert at point
+ // New one
+ // Clone of original, on to the old end
+ PAPX clone = new PAPX(0, 0, clonedBuf, _dataStream, needsToBeUnicode);
+ // Again ensure contains character based offsets no matter what
+ clone.setStart(cpStart);
+ clone.setEnd(currentPap.getEnd());
+
currentPap.setEnd(cpStart);
- PAPX splitPap = new PAPX(cpStart, currentPap.getEnd(), clonedBuf, _dataStream);
- _paragraphs.add(++listIndex, forInsert);
- _paragraphs.add(++listIndex, splitPap);
+
+ _paragraphs.add(listIndex + 1, forInsert);
+ _paragraphs.add(listIndex + 2, clone);
}
else
{
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/PAPFormattedDiskPage.java b/src/scratchpad/src/org/apache/poi/hwpf/model/PAPFormattedDiskPage.java
index 979825bf8..1a9a7bad5 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/model/PAPFormattedDiskPage.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/model/PAPFormattedDiskPage.java
@@ -60,13 +60,17 @@ public class PAPFormattedDiskPage extends FormattedDiskPage
/**
* Creates a PAPFormattedDiskPage from a 512 byte array
*/
- public PAPFormattedDiskPage(byte[] documentStream, byte[] dataStream, int offset, int fcMin)
+ public PAPFormattedDiskPage(byte[] documentStream, byte[] dataStream, int offset, int fcMin, TextPieceTable tpt)
{
super(documentStream, offset);
- for (int x = 0; x < _crun; x++)
- {
- _papxList.add(new PAPX(getStart(x) - fcMin, getEnd(x) - fcMin, getGrpprl(x), getParagraphHeight(x), dataStream));
+ for (int x = 0; x < _crun; x++) {
+ int startAt = getStart(x) - fcMin;
+ int endAt = getEnd(x) - fcMin;
+ boolean isUnicode = tpt.isUnicodeAtByteOffset(startAt);
+ //System.err.println(startAt + " -> " + endAt + " = " + isUnicode);
+
+ _papxList.add(new PAPX(startAt, endAt, getGrpprl(x), getParagraphHeight(x), dataStream, isUnicode));
}
_fkp = null;
_dataStream = dataStream;
@@ -110,7 +114,7 @@ public class PAPFormattedDiskPage extends FormattedDiskPage
}
/**
- * Gets the papx for the paragraph at index in this fkp.
+ * Gets the papx grpprl for the paragraph at index in this fkp.
*
* @param index The index of the papx to get.
* @return a papx grpprl.
@@ -259,7 +263,7 @@ public class PAPFormattedDiskPage extends FormattedDiskPage
grpprlOffset -= (grpprl.length + (2 - grpprl.length % 2));
grpprlOffset -= (grpprlOffset % 2);
}
- LittleEndian.putInt(buf, fcOffset, papx.getStart() + fcMin);
+ LittleEndian.putInt(buf, fcOffset, papx.getStartBytes() + fcMin);
buf[bxOffset] = (byte)(grpprlOffset/2);
System.arraycopy(phe, 0, buf, bxOffset + 1, phe.length);
@@ -287,7 +291,7 @@ public class PAPFormattedDiskPage extends FormattedDiskPage
}
- LittleEndian.putInt(buf, fcOffset, papx.getEnd() + fcMin);
+ LittleEndian.putInt(buf, fcOffset, papx.getEndBytes() + fcMin);
return buf;
}
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/PAPX.java b/src/scratchpad/src/org/apache/poi/hwpf/model/PAPX.java
index a7e259ec7..1e8ae86b5 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/model/PAPX.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/model/PAPX.java
@@ -29,29 +29,32 @@ import org.apache.poi.hwpf.sprm.SprmBuffer;
import org.apache.poi.hwpf.sprm.SprmOperation;
/**
- * Comment me
+ * DANGER - works in bytes!
+ *
+ * Make sure you call getStart() / getEnd() when you want characters
+ * (normal use), but getStartByte() / getEndByte() when you're
+ * reading in / writing out!
*
* @author Ryan Ackley
*/
-public class PAPX extends PropertyNode
-{
+public class PAPX extends BytePropertyNode {
private ParagraphHeight _phe;
private int _hugeGrpprlOffset = -1;
- public PAPX(int fcStart, int fcEnd, byte[] papx, ParagraphHeight phe, byte[] dataStream)
+ public PAPX(int fcStart, int fcEnd, byte[] papx, ParagraphHeight phe, byte[] dataStream, boolean isUnicode)
{
- super(fcStart, fcEnd, new SprmBuffer(papx));
+ super(fcStart, fcEnd, new SprmBuffer(papx), isUnicode);
_phe = phe;
SprmBuffer buf = findHuge(new SprmBuffer(papx), dataStream);
if(buf != null)
_buf = buf;
}
- public PAPX(int fcStart, int fcEnd, SprmBuffer buf, byte[] dataStream)
+ public PAPX(int fcStart, int fcEnd, SprmBuffer buf, byte[] dataStream, boolean isUnicode)
{
- super(fcStart, fcEnd, buf);
+ super(fcStart, fcEnd, buf, isUnicode);
_phe = new ParagraphHeight();
buf = findHuge(buf, dataStream);
if(buf != null)
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/PropertyNode.java b/src/scratchpad/src/org/apache/poi/hwpf/model/PropertyNode.java
index 42c5f5c27..5a1491796 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/model/PropertyNode.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/model/PropertyNode.java
@@ -22,7 +22,10 @@ import java.util.Arrays;
/**
* Represents a lightweight node in the Trees used to store content
- * properties. Works only in characters.
+ * properties.
+ * This only ever works in characters. For the few odd cases when
+ * the start and end aren't in characters (eg PAPX and CHPX), use
+ * {@link BytePropertyNode} between you and this.
*
* @author Ryan Ackley
*/
@@ -45,6 +48,11 @@ public abstract class PropertyNode implements Comparable, Cloneable
_cpStart = fcStart;
_cpEnd = fcEnd;
_buf = buf;
+
+ if(_cpStart < 0) {
+ System.err.println("A property claimed to start before zero, at " + _cpStart + "! Resetting it to zero, and hoping for the best");
+ _cpStart = 0;
+ }
}
/**
@@ -82,18 +90,18 @@ public abstract class PropertyNode implements Comparable, Cloneable
{
int end = start + length;
- if (_cpEnd > start)
- {
- if (_cpStart < end)
- {
- _cpEnd = end >= _cpEnd ? start : _cpEnd - length;
- _cpStart = Math.min(start, _cpStart);
- }
- else
- {
- _cpEnd -= length;
- _cpStart -= length;
- }
+ if (_cpEnd > start) {
+ // The start of the change is before we end
+
+ if (_cpStart < end) {
+ // The delete was somewhere in the middle of us
+ _cpEnd = end >= _cpEnd ? start : _cpEnd - length;
+ _cpStart = Math.min(start, _cpStart);
+ } else {
+ // The delete was before us
+ _cpEnd -= length;
+ _cpStart -= length;
+ }
}
}
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/SEPX.java b/src/scratchpad/src/org/apache/poi/hwpf/model/SEPX.java
index c66f8aa34..7987280ed 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/model/SEPX.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/model/SEPX.java
@@ -20,19 +20,20 @@
package org.apache.poi.hwpf.model;
-import org.apache.poi.hwpf.sprm.SprmBuffer;
-import org.apache.poi.hwpf.sprm.SectionSprmUncompressor;
import org.apache.poi.hwpf.sprm.SectionSprmCompressor;
+import org.apache.poi.hwpf.sprm.SectionSprmUncompressor;
import org.apache.poi.hwpf.usermodel.SectionProperties;
-public class SEPX extends PropertyNode
+/**
+ */
+public class SEPX extends BytePropertyNode
{
SectionDescriptor _sed;
- public SEPX(SectionDescriptor sed, int start, int end, byte[] grpprl)
+ public SEPX(SectionDescriptor sed, int start, int end, byte[] grpprl, boolean isUnicode)
{
- super(start, end, SectionSprmUncompressor.uncompressSEP(grpprl, 0));
+ super(start, end, SectionSprmUncompressor.uncompressSEP(grpprl, 0), isUnicode);
_sed = sed;
}
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/SectionTable.java b/src/scratchpad/src/org/apache/poi/hwpf/model/SectionTable.java
index 7b9c23325..b88edbb95 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/model/SectionTable.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/model/SectionTable.java
@@ -34,6 +34,9 @@ public class SectionTable
protected ArrayList _sections = new ArrayList();
protected List _text;
+ /** So we can know if things are unicode or not */
+ private TextPieceTable tpt;
+
public SectionTable()
{
}
@@ -41,10 +44,11 @@ public class SectionTable
public SectionTable(byte[] documentStream, byte[] tableStream, int offset,
int size, int fcMin,
- List tpt)
+ TextPieceTable tpt, CPSplitCalculator cps)
{
PlexOfCps sedPlex = new PlexOfCps(tableStream, offset, size, SED_SIZE);
- _text = tpt;
+ this.tpt = tpt;
+ this._text = tpt.getTextPieces();
int length = sedPlex.length();
@@ -54,11 +58,16 @@ public class SectionTable
SectionDescriptor sed = new SectionDescriptor(node.getBytes(), 0);
int fileOffset = sed.getFc();
+ int startAt = CPtoFC(node.getStart());
+ int endAt = CPtoFC(node.getEnd());
+
+ boolean isUnicodeAtStart = tpt.isUnicodeAtByteOffset( startAt );
+// System.err.println(startAt + " -> " + endAt + " = " + isUnicodeAtStart);
// check for the optimization
if (fileOffset == 0xffffffff)
{
- _sections.add(new SEPX(sed, CPtoFC(node.getStart()), CPtoFC(node.getEnd()), new byte[0]));
+ _sections.add(new SEPX(sed, startAt, endAt, new byte[0], isUnicodeAtStart));
}
else
{
@@ -67,9 +76,34 @@ public class SectionTable
byte[] buf = new byte[sepxSize];
fileOffset += LittleEndian.SHORT_SIZE;
System.arraycopy(documentStream, fileOffset, buf, 0, buf.length);
- _sections.add(new SEPX(sed, CPtoFC(node.getStart()), CPtoFC(node.getEnd()), buf));
+ _sections.add(new SEPX(sed, startAt, endAt, buf, isUnicodeAtStart));
}
}
+
+ // Some files seem to lie about their unicode status, which
+ // is very very pesky. Try to work around these, but this
+ // is getting on for black magic...
+ int mainEndsAt = cps.getMainDocumentEnd();
+ boolean matchAt = false;
+ boolean matchHalf = false;
+ for(int i=0; i<_sections.size(); i++) {
+ SEPX s = (SEPX)_sections.get(i);
+ if(s.getEnd() == mainEndsAt) {
+ matchAt = true;
+ } else if(s.getEndBytes() == mainEndsAt || s.getEndBytes() == mainEndsAt-1) {
+ matchHalf = true;
+ }
+ }
+ if(! matchAt && matchHalf) {
+ System.err.println("Your document seemed to be mostly unicode, but the section definition was in bytes! Trying anyway, but things may well go wrong!");
+ for(int i=0; i<_sections.size(); i++) {
+ SEPX s = (SEPX)_sections.get(i);
+ GenericPropertyNode node = sedPlex.getProperty(i);
+
+ s.setStart( CPtoFC(node.getStart()) );
+ s.setEnd( CPtoFC(node.getEnd()) );
+ }
+ }
}
public void adjustForInsert(int listIndex, int length)
@@ -171,7 +205,7 @@ public class SectionTable
// Line using Ryan's FCtoCP() conversion method -
// unable to observe any effect on our testcases when using this code - piers
- GenericPropertyNode property = new GenericPropertyNode(FCtoCP(sepx.getStart()), FCtoCP(sepx.getEnd()), sed.toByteArray());
+ GenericPropertyNode property = new GenericPropertyNode(FCtoCP(sepx.getStartBytes()), FCtoCP(sepx.getEndBytes()), sed.toByteArray());
plex.addProperty(property);
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/TextPiece.java b/src/scratchpad/src/org/apache/poi/hwpf/model/TextPiece.java
index 351c06ae7..bf2cf3014 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/model/TextPiece.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/model/TextPiece.java
@@ -118,6 +118,9 @@ public class TextPiece extends PropertyNode implements Comparable
if(end > buf.length()) {
throw new StringIndexOutOfBoundsException("Index " + end + " out of range 0 -> " + buf.length());
}
+ if(end < start) {
+ throw new StringIndexOutOfBoundsException("Asked for text from " + start + " to " + end + ", which has an end before the start!");
+ }
return buf.substring(start, end);
}
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/TextPieceTable.java b/src/scratchpad/src/org/apache/poi/hwpf/model/TextPieceTable.java
index 5e903ecb8..129603463 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/model/TextPieceTable.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/model/TextPieceTable.java
@@ -25,6 +25,9 @@ import org.apache.poi.poifs.common.POIFSConstants;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Hashtable;
+import java.util.Iterator;
import java.util.List;
/**
@@ -62,8 +65,17 @@ public class TextPieceTable
pieces[x] = new PieceDescriptor(node.getBytes(), 0);
}
- int firstPieceFilePosition = pieces[0].getFilePosition();
- _cpMin = firstPieceFilePosition - fcMin;
+
+ // Figure out the cp of the earliest text piece
+ // Note that text pieces don't have to be stored in order!
+ _cpMin = pieces[0].getFilePosition() - fcMin;
+ for (int x = 0; x < pieces.length; x++) {
+ int start = pieces[x].getFilePosition() - fcMin;
+ if(start < _cpMin) {
+ _cpMin = start;
+ }
+ }
+
// using the PieceDescriptors, build our list of TextPieces.
for (int x = 0; x < pieces.length; x++)
@@ -93,6 +105,15 @@ public class TextPieceTable
// And now build the piece
_textPieces.add(new TextPiece(nodeStartChars, nodeEndChars, buf, pieces[x], node.getStart()));
}
+
+ // In the interest of our sanity, now sort the text pieces
+ // into order, if they're not already
+ TextPiece[] tp = (TextPiece[])
+ _textPieces.toArray(new TextPiece[_textPieces.size()]);
+ Arrays.sort(tp);
+ for(int i=0; i= cp) {
+ return tp.isUnicode();
+ }
+ // Otherwise keep track for the last one
+ lastWas = tp.isUnicode();
+ }
+
+ // If they ask off the end, just go with the last one...
+ return lastWas;
+ }
+ /**
+ * Is the text at the given byte offset
+ * unicode, or plain old ascii?
+ * In a very evil fashion, you have to actually
+ * know this to make sense of character and
+ * paragraph properties :(
+ * @param cp The character offset to check about
+ */
+ public boolean isUnicodeAtByteOffset(int bytePos) {
+ boolean lastWas = false;
+ int curByte = 0;
+
+ Iterator it = _textPieces.iterator();
+ while(it.hasNext()) {
+ TextPiece tp = (TextPiece)it.next();
+ int nextByte = curByte + tp.bytesLength();
+
+ // If the text piece covers the character, all good
+ if(curByte <= bytePos && nextByte >= bytePos) {
+ return tp.isUnicode();
+ }
+ // Otherwise keep track for the last one
+ lastWas = tp.isUnicode();
+ // Move along
+ curByte = nextByte;
+ }
+
+ // If they ask off the end, just go with the last one...
+ return lastWas;
+ }
public byte[] writeTo(HWPFOutputStream docStream)
throws IOException
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/types/FIBAbstractType.java b/src/scratchpad/src/org/apache/poi/hwpf/model/types/FIBAbstractType.java
index 661582328..63961b455 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/model/types/FIBAbstractType.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/model/types/FIBAbstractType.java
@@ -70,10 +70,10 @@ public abstract class FIBAbstractType
private static BitField fFutureSavedUndo = BitFieldFactory.getInstance(0x0008);
private static BitField fWord97Saved = BitFieldFactory.getInstance(0x0010);
private static BitField fSpare0 = BitFieldFactory.getInstance(0x00FE);
- protected int field_11_chs;
- protected int field_12_chsTables;
- protected int field_13_fcMin;
- protected int field_14_fcMac;
+ protected int field_11_chs; /** Latest docs say this is Reserved3! */
+ protected int field_12_chsTables; /** Latest docs say this is Reserved4! */
+ protected int field_13_fcMin; /** Latest docs say this is Reserved5! */
+ protected int field_14_fcMac; /** Latest docs say this is Reserved6! */
public FIBAbstractType()
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Range.java b/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Range.java
index 109fd175b..0a145d5fd 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Range.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Range.java
@@ -155,6 +155,8 @@ public class Range
_characters = _doc.getCharacterTable().getTextRuns();
_text = _doc.getTextTable().getTextPieces();
_parent = new WeakReference(null);
+
+ sanityCheckStartEnd();
}
@@ -175,6 +177,8 @@ public class Range
_characters = parent._characters;
_text = parent._text;
_parent = new WeakReference(parent);
+
+ sanityCheckStartEnd();
}
/**
@@ -226,6 +230,22 @@ public class Range
_textRangeFound = true;
break;
}
+
+ sanityCheckStartEnd();
+ }
+
+ /**
+ * Ensures that the start and end were were given
+ * are actually valid, to avoid issues later on
+ * if they're not
+ */
+ private void sanityCheckStartEnd() {
+ if(_start < 0) {
+ throw new IllegalArgumentException("Range start must not be negative. Given " + _start);
+ }
+ if(_end < _start) {
+ throw new IllegalArgumentException("The end (" + _end + ") must not be before the start ("+_start+")");
+ }
}
/**
@@ -537,13 +557,17 @@ public class Range
for (int x = _parStart; x < numParagraphs; x++)
{
PAPX papx = (PAPX)_paragraphs.get(x);
+ //System.err.println("Paragraph " + x + " was " + papx.getStart() + " -> " + papx.getEnd());
papx.adjustForDelete(_start, _end - _start);
+ //System.err.println("Paragraph " + x + " is now " + papx.getStart() + " -> " + papx.getEnd());
}
for (int x = _sectionStart; x < numSections; x++)
{
SEPX sepx = (SEPX)_sections.get(x);
+ //System.err.println("Section " + x + " was " + sepx.getStart() + " -> " + sepx.getEnd());
sepx.adjustForDelete(_start, _end - _start);
+ //System.err.println("Section " + x + " is now " + sepx.getStart() + " -> " + sepx.getEnd());
}
for (int x = _textStart; x < numTextPieces; x++)
@@ -650,14 +674,6 @@ public class Range
absPlaceHolderIndex,
(absPlaceHolderIndex + pPlaceHolder.length()), getDocument()
);
- if (subRange.usesUnicode()) {
- absPlaceHolderIndex = getStartOffset() + (pOffset * 2);
- subRange = new Range(
- absPlaceHolderIndex,
- (absPlaceHolderIndex + (pPlaceHolder.length() * 2)),
- getDocument()
- );
- }
// this Range isn't a proper parent of the subRange() so we'll have to keep
// track of an updated endOffset on our own
@@ -674,12 +690,6 @@ public class Range
(absPlaceHolderIndex + pPlaceHolder.length() + pValue.length()),
getDocument()
);
- if (subRange.usesUnicode())
- subRange = new Range(
- (absPlaceHolderIndex + (pValue.length() * 2)),
- (absPlaceHolderIndex + (pPlaceHolder.length() * 2) +
- (pValue.length() * 2)), getDocument()
- );
// deletes are automagically propagated
subRange.delete();
@@ -820,6 +830,10 @@ public class Range
{
throw new ArrayIndexOutOfBoundsException("The table's bounds fall outside of this Range");
}
+ if (tableEnd < 0)
+ {
+ throw new ArrayIndexOutOfBoundsException("The table's end is negative, which isn't allowed!");
+ }
return new Table(r._parStart, tableEnd, r._doc.getRange(), paragraph.getTableLevel());
}
diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/model/TestCHPBinTable.java b/src/scratchpad/testcases/org/apache/poi/hwpf/model/TestCHPBinTable.java
index 07e8bfbf9..d1f1451ac 100644
--- a/src/scratchpad/testcases/org/apache/poi/hwpf/model/TestCHPBinTable.java
+++ b/src/scratchpad/testcases/org/apache/poi/hwpf/model/TestCHPBinTable.java
@@ -32,6 +32,8 @@ public class TestCHPBinTable
{
private CHPBinTable _cHPBinTable = null;
private HWPFDocFixture _hWPFDocFixture;
+
+ private TextPieceTable fakeTPT = new TextPieceTable();
public TestCHPBinTable(String name)
{
@@ -46,7 +48,7 @@ public class TestCHPBinTable
byte[] tableStream = _hWPFDocFixture._tableStream;
int fcMin = fib.getFcMin();
- _cHPBinTable = new CHPBinTable(mainStream, tableStream, fib.getFcPlcfbteChpx(), fib.getLcbPlcfbteChpx(), fcMin);
+ _cHPBinTable = new CHPBinTable(mainStream, tableStream, fib.getFcPlcfbteChpx(), fib.getLcbPlcfbteChpx(), fcMin, fakeTPT);
HWPFFileSystem fileSys = new HWPFFileSystem();
@@ -57,7 +59,7 @@ public class TestCHPBinTable
byte[] newTableStream = tableOut.toByteArray();
byte[] newMainStream = mainOut.toByteArray();
- CHPBinTable newBinTable = new CHPBinTable(newMainStream, newTableStream, 0, newTableStream.length, 0);
+ CHPBinTable newBinTable = new CHPBinTable(newMainStream, newTableStream, 0, newTableStream.length, 0, fakeTPT);
ArrayList oldTextRuns = _cHPBinTable._textRuns;
ArrayList newTextRuns = newBinTable._textRuns;
diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/model/TestPAPBinTable.java b/src/scratchpad/testcases/org/apache/poi/hwpf/model/TestPAPBinTable.java
index 4358cdef0..446b5232a 100644
--- a/src/scratchpad/testcases/org/apache/poi/hwpf/model/TestPAPBinTable.java
+++ b/src/scratchpad/testcases/org/apache/poi/hwpf/model/TestPAPBinTable.java
@@ -32,6 +32,8 @@ public class TestPAPBinTable
private PAPBinTable _pAPBinTable = null;
private HWPFDocFixture _hWPFDocFixture;
+ private TextPieceTable fakeTPT = new TextPieceTable();
+
public TestPAPBinTable(String name)
{
super(name);
@@ -45,7 +47,7 @@ public class TestPAPBinTable
byte[] tableStream = _hWPFDocFixture._tableStream;
int fcMin = fib.getFcMin();
- _pAPBinTable = new PAPBinTable(mainStream, tableStream, null, fib.getFcPlcfbtePapx(), fib.getLcbPlcfbtePapx(), fcMin);
+ _pAPBinTable = new PAPBinTable(mainStream, tableStream, null, fib.getFcPlcfbtePapx(), fib.getLcbPlcfbtePapx(), fcMin, fakeTPT);
HWPFFileSystem fileSys = new HWPFFileSystem();
@@ -56,7 +58,7 @@ public class TestPAPBinTable
byte[] newTableStream = tableOut.toByteArray();
byte[] newMainStream = mainOut.toByteArray();
- PAPBinTable newBinTable = new PAPBinTable(newMainStream, newTableStream, null,0, newTableStream.length, 0);
+ PAPBinTable newBinTable = new PAPBinTable(newMainStream, newTableStream, null,0, newTableStream.length, 0, fakeTPT);
ArrayList oldTextRuns = _pAPBinTable.getParagraphs();
ArrayList newTextRuns = newBinTable.getParagraphs();
diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/model/TestSectionTable.java b/src/scratchpad/testcases/org/apache/poi/hwpf/model/TestSectionTable.java
index 0912daaf7..2f5ad1ccb 100644
--- a/src/scratchpad/testcases/org/apache/poi/hwpf/model/TestSectionTable.java
+++ b/src/scratchpad/testcases/org/apache/poi/hwpf/model/TestSectionTable.java
@@ -45,13 +45,15 @@ public class TestSectionTable
byte[] tableStream = _hWPFDocFixture._tableStream;
int fcMin = fib.getFcMin();
+ CPSplitCalculator cps = new CPSplitCalculator(fib);
+
ComplexFileTable cft = new ComplexFileTable(mainStream, tableStream, fib.getFcClx(), fcMin);
TextPieceTable tpt = cft.getTextPieceTable();
SectionTable sectionTable = new SectionTable(mainStream, tableStream,
fib.getFcPlcfsed(),
fib.getLcbPlcfsed(),
- fcMin, tpt.getTextPieces());
+ fcMin, tpt, cps);
HWPFFileSystem fileSys = new HWPFFileSystem();
sectionTable.writeTo(fileSys, 0);
@@ -61,7 +63,9 @@ public class TestSectionTable
byte[] newTableStream = tableOut.toByteArray();
byte[] newMainStream = mainOut.toByteArray();
- SectionTable newSectionTable = new SectionTable(newMainStream, newTableStream, 0, newTableStream.length, 0, tpt.getTextPieces());
+ SectionTable newSectionTable = new SectionTable(
+ newMainStream, newTableStream, 0,
+ newTableStream.length, 0, tpt, cps);
ArrayList oldSections = sectionTable.getSections();
ArrayList newSections = newSectionTable.getSections();
diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestProblems.java b/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestProblems.java
index 764b3239d..db28cbd45 100644
--- a/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestProblems.java
+++ b/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestProblems.java
@@ -81,9 +81,16 @@ public class TestProblems extends TestCase {
HWPFDocument doc = new HWPFDocument(new FileInputStream(
new File(dirname, "Bug44292.doc")));
Range r = doc.getRange();
+ assertEquals(6, r.numParagraphs());
+ assertEquals(0, r.getStartOffset());
+ assertEquals(87, r.getEndOffset());
- //get the table
+ // Paragraph with table
Paragraph p = r.getParagraph(0);
+ assertEquals(0, p.getStartOffset());
+ assertEquals(20, p.getEndOffset());
+
+ // Get the table
Table t = r.getTable(p);
//get the only row
diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestRangeDelete.java b/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestRangeDelete.java
index 2994b6332..4adc5b9cf 100644
--- a/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestRangeDelete.java
+++ b/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestRangeDelete.java
@@ -18,27 +18,28 @@
package org.apache.poi.hwpf.usermodel;
-import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
-import java.util.List;
-
-import org.apache.poi.hwpf.HWPFDocument;
-import org.apache.poi.hwpf.model.PicturesTable;
-import org.apache.poi.hwpf.usermodel.Picture;
import junit.framework.TestCase;
+import org.apache.poi.hwpf.HWPFDocument;
+import org.apache.poi.hwpf.model.PAPX;
+
/**
* Test to see if Range.delete() works even if the Range contains a
* CharacterRun that uses Unicode characters.
- *
- * TODO - re-enable me when unicode paragraph stuff is fixed!
*/
-public abstract class TestRangeDelete extends TestCase {
+public class TestRangeDelete extends TestCase {
// u201c and u201d are "smart-quotes"
+ private String introText =
+ "Introduction\r";
+ private String fillerText =
+ "${delete} This is an MS-Word 97 formatted document created using NeoOffice v. 2.2.4 Patch 0 (OpenOffice.org v. 2.2.1).\r";
private String originalText =
"It is used to confirm that text delete works even if Unicode characters (such as \u201c\u2014\u201d (U+2014), \u201c\u2e8e\u201d (U+2E8E), or \u201c\u2714\u201d (U+2714)) are present. Everybody should be thankful to the ${organization} ${delete} and all the POI contributors for their assistance in this matter.\r";
+ private String lastText =
+ "Thank you, ${organization} ${delete}!\r";
private String searchText = "${delete}";
private String expectedText1 = " This is an MS-Word 97 formatted document created using NeoOffice v. 2.2.4 Patch 0 (OpenOffice.org v. 2.2.1).\r";
private String expectedText2 =
@@ -68,32 +69,63 @@ public abstract class TestRangeDelete extends TestCase {
public void testDocStructure() throws Exception {
HWPFDocument daDoc = new HWPFDocument(new FileInputStream(illustrativeDocFile));
+ Range range;
+ Section section;
+ Paragraph para;
+ PAPX paraDef;
- Range range = daDoc.getOverallRange();
-
+ // First, check overall
+ range = daDoc.getOverallRange();
assertEquals(1, range.numSections());
- Section section = range.getSection(0);
-
- assertEquals(5, section.numParagraphs());
- Paragraph para = section.getParagraph(2);
-
- assertEquals(5, para.numCharacterRuns());
-
- assertEquals(originalText, para.text());
+ assertEquals(5, range.numParagraphs());
- // Now check on just the main text
+ // Now, onto just the doc bit
range = daDoc.getRange();
-
+
assertEquals(1, range.numSections());
+ assertEquals(1, daDoc.getSectionTable().getSections().size());
section = range.getSection(0);
-
+
assertEquals(5, section.numParagraphs());
- para = section.getParagraph(2);
-
+
+ para = section.getParagraph(0);
+ assertEquals(1, para.numCharacterRuns());
+ assertEquals(introText, para.text());
+
+ para = section.getParagraph(1);
+ assertEquals(5, para.numCharacterRuns());
+ assertEquals(fillerText, para.text());
+
+
+ paraDef = (PAPX)daDoc.getParagraphTable().getParagraphs().get(2);
+ assertEquals(132, paraDef.getStart());
+ assertEquals(400, paraDef.getEnd());
+
+ para = section.getParagraph(2);
assertEquals(5, para.numCharacterRuns());
-
assertEquals(originalText, para.text());
+
+
+ paraDef = (PAPX)daDoc.getParagraphTable().getParagraphs().get(3);
+ assertEquals(400, paraDef.getStart());
+ assertEquals(438, paraDef.getEnd());
+
+ para = section.getParagraph(3);
+ assertEquals(1, para.numCharacterRuns());
+ assertEquals(lastText, para.text());
+
+
+ // Check things match on text length
+ assertEquals(439, range.text().length());
+ assertEquals(439, section.text().length());
+ assertEquals(439,
+ section.getParagraph(0).text().length() +
+ section.getParagraph(1).text().length() +
+ section.getParagraph(2).text().length() +
+ section.getParagraph(3).text().length() +
+ section.getParagraph(4).text().length()
+ );
}
/**
@@ -118,12 +150,7 @@ public abstract class TestRangeDelete extends TestCase {
assertEquals(192, offset);
int absOffset = para.getStartOffset() + offset;
- if (para.usesUnicode())
- absOffset = para.getStartOffset() + (offset * 2);
-
Range subRange = new Range(absOffset, (absOffset + searchText.length()), para.getDocument());
- if (subRange.usesUnicode())
- subRange = new Range(absOffset, (absOffset + (searchText.length() * 2)), para.getDocument());
assertEquals(searchText, subRange.text());
@@ -167,26 +194,23 @@ public abstract class TestRangeDelete extends TestCase {
boolean keepLooking = true;
while (keepLooking) {
-
+ // Reload the range every time
+ range = daDoc.getRange();
int offset = range.text().indexOf(searchText);
if (offset >= 0) {
int absOffset = range.getStartOffset() + offset;
- if (range.usesUnicode())
- absOffset = range.getStartOffset() + (offset * 2);
Range subRange = new Range(
absOffset, (absOffset + searchText.length()), range.getDocument());
- if (subRange.usesUnicode())
- subRange = new Range(
- absOffset, (absOffset + (searchText.length() * 2)), range.getDocument());
assertEquals(searchText, subRange.text());
subRange.delete();
- } else
+ } else {
keepLooking = false;
+ }
}
// we need to let the model re-calculate the Range before we use it
@@ -197,6 +221,10 @@ public abstract class TestRangeDelete extends TestCase {
assertEquals(5, section.numParagraphs());
+ para = section.getParagraph(0);
+ text = para.text();
+ assertEquals(introText, text);
+
para = section.getParagraph(1);
text = para.text();
assertEquals(expectedText1, text);
diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestRangeInsertion.java b/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestRangeInsertion.java
index 5f21508c9..a520b953f 100644
--- a/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestRangeInsertion.java
+++ b/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestRangeInsertion.java
@@ -18,29 +18,25 @@
package org.apache.poi.hwpf.usermodel;
-import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
-import java.util.List;
-
-import org.apache.poi.hwpf.HWPFDocument;
-import org.apache.poi.hwpf.model.PicturesTable;
-import org.apache.poi.hwpf.usermodel.Picture;
import junit.framework.TestCase;
+import org.apache.poi.hwpf.HWPFDocument;
+
/**
* Test to see if Range.insertBefore() works even if the Range contains a
* CharacterRun that uses Unicode characters.
*
* TODO - re-enable me when unicode paragraph stuff is fixed!
*/
-public abstract class TestRangeInsertion extends TestCase {
+public class TestRangeInsertion extends TestCase {
// u201c and u201d are "smart-quotes"
private String originalText =
"It is used to confirm that text insertion works even if Unicode characters (such as \u201c\u2014\u201d (U+2014), \u201c\u2e8e\u201d (U+2E8E), or \u201c\u2714\u201d (U+2714)) are present.\r";
private String textToInsert = "Look at me! I'm cool! ";
- private int insertionPoint = 244;
+ private int insertionPoint = 122;
private String illustrativeDocFile;
@@ -73,12 +69,18 @@ public abstract class TestRangeInsertion extends TestCase {
assertEquals(3, section.numParagraphs());
Paragraph para = section.getParagraph(2);
+ assertEquals(originalText, para.text());
assertEquals(3, para.numCharacterRuns());
- String text = para.getCharacterRun(0).text() + para.getCharacterRun(1).text() +
- para.getCharacterRun(2).text();
+ String text =
+ para.getCharacterRun(0).text() +
+ para.getCharacterRun(1).text() +
+ para.getCharacterRun(2).text()
+ ;
assertEquals(originalText, text);
+
+ assertEquals(insertionPoint, para.getStartOffset());
}
/**
@@ -109,10 +111,14 @@ public abstract class TestRangeInsertion extends TestCase {
assertEquals(3, section.numParagraphs());
Paragraph para = section.getParagraph(2);
+ assertEquals((textToInsert + originalText), para.text());
assertEquals(3, para.numCharacterRuns());
- String text = para.getCharacterRun(0).text() + para.getCharacterRun(1).text() +
- para.getCharacterRun(2).text();
+ String text =
+ para.getCharacterRun(0).text() +
+ para.getCharacterRun(1).text() +
+ para.getCharacterRun(2).text()
+ ;
// System.out.println(text);
diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestRangeProperties.java b/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestRangeProperties.java
index 1f0aad5aa..1578ebdaf 100644
--- a/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestRangeProperties.java
+++ b/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestRangeProperties.java
@@ -18,8 +18,10 @@ package org.apache.poi.hwpf.usermodel;
import java.io.File;
import java.io.FileInputStream;
+import java.util.List;
import org.apache.poi.hwpf.HWPFDocument;
+import org.apache.poi.hwpf.model.PropertyNode;
import junit.framework.TestCase;
@@ -30,7 +32,7 @@ import junit.framework.TestCase;
*
* TODO - re-enable me when unicode paragraph stuff is fixed!
*/
-public abstract class TestRangeProperties extends TestCase {
+public class TestRangeProperties extends TestCase {
private static final char page_break = (char)12;
private static final String u_page_1 =
@@ -85,6 +87,16 @@ public abstract class TestRangeProperties extends TestCase {
r.text()
);
+ assertEquals(1, r.numSections());
+ assertEquals(1, a.getSectionTable().getSections().size());
+ Section s = r.getSection(0);
+ assertEquals(
+ a_page_1 +
+ page_break + "\r" +
+ a_page_2,
+ s.text()
+ );
+
assertEquals(
7,
r.numParagraphs()
@@ -142,8 +154,102 @@ public abstract class TestRangeProperties extends TestCase {
assertEquals(22, c1.getFontSize());
assertEquals(32, c7.getFontSize());
}
-
+ /**
+ * Tests the raw definitions of the paragraphs of
+ * a unicode document
+ */
+ public void testUnicodeParagraphDefinitions() throws Exception {
+ Range r = u.getRange();
+ String[] p1_parts = u_page_1.split("\r");
+ String[] p2_parts = u_page_2.split("\r");
+
+ assertEquals(
+ u_page_1 + page_break + "\r" + u_page_2,
+ r.text()
+ );
+ assertEquals(
+ 408, r.text().length()
+ );
+
+
+ assertEquals(1, r.numSections());
+ assertEquals(1, u.getSectionTable().getSections().size());
+ Section s = r.getSection(0);
+ assertEquals(
+ u_page_1 +
+ page_break + "\r" +
+ u_page_2,
+ s.text()
+ );
+ assertEquals(0, s.getStartOffset());
+ assertEquals(408, s.getEndOffset());
+
+
+ List pDefs = r._paragraphs;
+ assertEquals(35, pDefs.size());
+
+ // Check that the last paragraph ends where it should do
+ assertEquals(531, u.getOverallRange().text().length());
+ assertEquals(530, u.getCPSplitCalculator().getHeaderTextboxEnd());
+ PropertyNode pLast = (PropertyNode)pDefs.get(34);
+// assertEquals(530, pLast.getEnd());
+
+ // Only care about the first few really though
+ PropertyNode p0 = (PropertyNode)pDefs.get(0);
+ PropertyNode p1 = (PropertyNode)pDefs.get(1);
+ PropertyNode p2 = (PropertyNode)pDefs.get(2);
+ PropertyNode p3 = (PropertyNode)pDefs.get(3);
+ PropertyNode p4 = (PropertyNode)pDefs.get(4);
+
+ // 5 paragraphs should get us to the end of our text
+ assertTrue(p0.getStart() < 408);
+ assertTrue(p0.getEnd() < 408);
+ assertTrue(p1.getStart() < 408);
+ assertTrue(p1.getEnd() < 408);
+ assertTrue(p2.getStart() < 408);
+ assertTrue(p2.getEnd() < 408);
+ assertTrue(p3.getStart() < 408);
+ assertTrue(p3.getEnd() < 408);
+ assertTrue(p4.getStart() < 408);
+ assertTrue(p4.getEnd() < 408);
+
+ // Paragraphs should match with lines
+ assertEquals(
+ 0,
+ p0.getStart()
+ );
+ assertEquals(
+ p1_parts[0].length() + 1,
+ p0.getEnd()
+ );
+
+ assertEquals(
+ p1_parts[0].length() + 1,
+ p1.getStart()
+ );
+ assertEquals(
+ p1_parts[0].length() + 1 +
+ p1_parts[1].length() + 1,
+ p1.getEnd()
+ );
+
+ assertEquals(
+ p1_parts[0].length() + 1 +
+ p1_parts[1].length() + 1,
+ p2.getStart()
+ );
+ assertEquals(
+ p1_parts[0].length() + 1 +
+ p1_parts[1].length() + 1 +
+ p1_parts[2].length() + 1,
+ p2.getEnd()
+ );
+ }
+
+ /**
+ * Tests the paragraph text of a unicode document
+ */
public void testUnicodeTextParagraphs() throws Exception {
Range r = u.getRange();
assertEquals(
@@ -154,16 +260,112 @@ public abstract class TestRangeProperties extends TestCase {
);
assertEquals(
- 5,
+ 12,
r.numParagraphs()
);
String[] p1_parts = u_page_1.split("\r");
String[] p2_parts = u_page_2.split("\r");
- System.out.println(r.getParagraph(2).text());
- // TODO
+ // Check text all matches up properly
+ assertEquals(p1_parts[0] + "\r", r.getParagraph(0).text());
+ assertEquals(p1_parts[1] + "\r", r.getParagraph(1).text());
+ assertEquals(p1_parts[2] + "\r", r.getParagraph(2).text());
+ assertEquals(p1_parts[3] + "\r", r.getParagraph(3).text());
+ assertEquals(p1_parts[4] + "\r", r.getParagraph(4).text());
+ assertEquals(p1_parts[5] + "\r", r.getParagraph(5).text());
+ assertEquals(p1_parts[6] + "\r", r.getParagraph(6).text());
+ assertEquals(p1_parts[7] + "\r", r.getParagraph(7).text());
+ assertEquals(p1_parts[8] + "\r", r.getParagraph(8).text());
+ assertEquals(p1_parts[9] + "\r", r.getParagraph(9).text());
+ assertEquals(page_break + "\r", r.getParagraph(10).text());
+ assertEquals(p2_parts[0] + "\r", r.getParagraph(11).text());
}
public void testUnicodeStyling() throws Exception {
- // TODO
+ Range r = u.getRange();
+ String[] p1_parts = u_page_1.split("\r");
+
+ Paragraph p1 = r.getParagraph(0);
+ Paragraph p7 = r.getParagraph(6);
+
+ // Line ending in its own run each time!
+ assertEquals(2, p1.numCharacterRuns());
+ assertEquals(2, p7.numCharacterRuns());
+
+ CharacterRun c1a = p1.getCharacterRun(0);
+ CharacterRun c1b = p1.getCharacterRun(1);
+ CharacterRun c7a = p7.getCharacterRun(0);
+ CharacterRun c7b = p7.getCharacterRun(1);
+
+ assertEquals("Times New Roman", c1a.getFontName()); // No Calibri
+ assertEquals(22, c1a.getFontSize());
+
+ assertEquals("Times New Roman", c1b.getFontName()); // No Calibri
+ assertEquals(22, c1b.getFontSize());
+
+ assertEquals("Times New Roman", c7a.getFontName());
+ assertEquals(48, c7a.getFontSize());
+
+ assertEquals("Times New Roman", c7b.getFontName());
+ assertEquals(48, c7b.getFontSize());
+
+ // Now check where they crop up
+ assertEquals(
+ 0,
+ c1a.getStartOffset()
+ );
+ assertEquals(
+ p1_parts[0].length(),
+ c1a.getEndOffset()
+ );
+
+ assertEquals(
+ p1_parts[0].length(),
+ c1b.getStartOffset()
+ );
+ assertEquals(
+ p1_parts[0].length()+1,
+ c1b.getEndOffset()
+ );
+
+ assertEquals(
+ p1_parts[0].length() + 1 +
+ p1_parts[1].length() + 1 +
+ p1_parts[2].length() + 1 +
+ p1_parts[3].length() + 1 +
+ p1_parts[4].length() + 1 +
+ p1_parts[5].length() + 1,
+ c7a.getStartOffset()
+ );
+ assertEquals(
+ p1_parts[0].length() + 1 +
+ p1_parts[1].length() + 1 +
+ p1_parts[2].length() + 1 +
+ p1_parts[3].length() + 1 +
+ p1_parts[4].length() + 1 +
+ p1_parts[5].length() + 1 +
+ 1,
+ c7a.getEndOffset()
+ );
+
+ assertEquals(
+ p1_parts[0].length() + 1 +
+ p1_parts[1].length() + 1 +
+ p1_parts[2].length() + 1 +
+ p1_parts[3].length() + 1 +
+ p1_parts[4].length() + 1 +
+ p1_parts[5].length() + 1 +
+ 1,
+ c7b.getStartOffset()
+ );
+ assertEquals(
+ p1_parts[0].length() + 1 +
+ p1_parts[1].length() + 1 +
+ p1_parts[2].length() + 1 +
+ p1_parts[3].length() + 1 +
+ p1_parts[4].length() + 1 +
+ p1_parts[5].length() + 1 +
+ p1_parts[6].length() + 1,
+ c7b.getEndOffset()
+ );
}
}
diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestRangeReplacement.java b/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestRangeReplacement.java
index 67aea65be..7c4766844 100644
--- a/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestRangeReplacement.java
+++ b/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestRangeReplacement.java
@@ -18,23 +18,19 @@
package org.apache.poi.hwpf.usermodel;
-import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
-import java.util.List;
-
-import org.apache.poi.hwpf.HWPFDocument;
-import org.apache.poi.hwpf.model.PicturesTable;
-import org.apache.poi.hwpf.usermodel.Picture;
import junit.framework.TestCase;
+import org.apache.poi.hwpf.HWPFDocument;
+
/**
* Test to see if Range.replaceText() works even if the Range contains a
* CharacterRun that uses Unicode characters.
*
* TODO - re-enable me when unicode paragraph stuff is fixed!
*/
-public abstract class TestRangeReplacement extends TestCase {
+public class TestRangeReplacement extends TestCase {
// u201c and u201d are "smart-quotes"
private String originalText =
@@ -70,16 +66,23 @@ public abstract class TestRangeReplacement extends TestCase {
HWPFDocument daDoc = new HWPFDocument(new FileInputStream(illustrativeDocFile));
Range range = daDoc.getRange();
+ assertEquals(414, range.text().length());
assertEquals(1, range.numSections());
Section section = range.getSection(0);
+ assertEquals(414, section.text().length());
assertEquals(5, section.numParagraphs());
Paragraph para = section.getParagraph(2);
assertEquals(5, para.numCharacterRuns());
- String text = para.getCharacterRun(0).text() + para.getCharacterRun(1).text() +
- para.getCharacterRun(2).text() + para.getCharacterRun(3).text() + para.getCharacterRun(4).text();
+ String text =
+ para.getCharacterRun(0).text() +
+ para.getCharacterRun(1).text() +
+ para.getCharacterRun(2).text() +
+ para.getCharacterRun(3).text() +
+ para.getCharacterRun(4).text()
+ ;
assertEquals(originalText, text);
}
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..2e393d610 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.ss.usermodel.FormulaEvaluator.CellValue;
/**
* Tests for functions from external workbooks (e.g. YEARFRAC).
*
@@ -30,17 +38,45 @@ import org.apache.poi.hssf.usermodel.HSSFWorkbook;
*/
public final class TestExternalFunctionFormulas extends TestCase {
-
- /**
- * tests 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 9e6c7bce6..e1bed55c5 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 08646b3e6..e7c793176 100644
--- a/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java
+++ b/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java
@@ -417,6 +417,9 @@ public final class TestBugs extends TestCase {
for(int i = 0 ; i < wb.getNumberOfNames(); i++){
HSSFName name = wb.getNameAt(i);
name.getNameName();
+ if (name.isFunctionName()) {
+ continue;
+ }
name.getReference();
}
}
@@ -1004,7 +1007,6 @@ public final class TestBugs extends TestCase {
* Test that we can delete sheets without
* breaking the build in named ranges
* used for printing stuff.
- * Currently broken, as we change the Ptg
*/
public void test30978() {
HSSFWorkbook wb = openSample("30978-alt.xls");
@@ -1016,7 +1018,7 @@ public final class TestBugs extends TestCase {
Workbook w = wb.getWorkbook();
for(int i=0; i