aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorNick Burch <nick@apache.org>2008-05-23 09:48:23 +0000
committerNick Burch <nick@apache.org>2008-05-23 09:48:23 +0000
commit877e4efa74a270406a9f4f7e73833f8815e47f47 (patch)
tree97691bfe18fdd8efd626681bb5b7c27162cf1303 /src
parentd643dc1cf1a8108c78b8a3bf5ee2f681fb00660e (diff)
downloadpoi-877e4efa74a270406a9f4f7e73833f8815e47f47.tar.gz
poi-877e4efa74a270406a9f4f7e73833f8815e47f47.zip
Merged revisions 638786-638802,638805-638811,638813-638814,638816-639230,639233-639241,639243-639253,639255-639486,639488-639601,639603-639835,639837-639917,639919-640056,640058-640710,640712-641156,641158-641184,641186-641795,641797-641798,641800-641933,641935-641963,641965-641966,641968-641995,641997-642230,642232-642562,642564-642565,642568-642570,642572-642573,642576-642736,642739-642877,642879,642881-642890,642892-642903,642905-642945,642947-643624,643626-643653,643655-643669,643671,643673-643830,643832-643833,643835-644342,644344-644472,644474-644508,644510-645347,645349-645351,645353-645559,645561-645565,645568-645951,645953-646193,646195-646311,646313-646404,646406-646665,646667-646853,646855-646869,646871-647151,647153-647185,647187-647277,647279-647566,647568-647573,647575,647578-647711,647714-647737,647739-647823,647825-648155,648157-648202,648204-648273,648275,648277-648302,648304-648333,648335-648588,648590-648622,648625-648673,648675-649141,649144,649146-649556,649558-649795,649799,649801-649910,649912-649913,649915-650128,650131-650132,650134-650137,650140-650914,650916-651991,651993-652284,652286-652287,652289,652291,652293-652297,652299-652328,652330-652425,652427-652445,652447-652560,652562-652933,652935,652937-652993,652995-653116,653118-653124,653126-653483,653487-653519,653522-653550,653552-653607,653609-653667,653669-653674,653676-653814,653817-653830,653832-653891,653893-653944,653946-654055,654057-654355,654357-654365,654367-654648,654651-655215,655217-655277,655279-655281,655283-655911,655913-656212,656214,656216-656251,656253-656698,656700-656756,656758-656892,656894-657135,657137-657165,657168-657179,657181-657354,657356-657357,657359-657701,657703-657874,657876-658032,658034-658284,658286,658288-658301,658303-658307,658309-659484 via svnmerge from
https://svn.apache.org:443/repos/asf/poi/trunk ........ r658322 | nick | 2008-05-20 17:37:15 +0100 (Tue, 20 May 2008) | 1 line Fix bug #44977 - Support for AM/PM in excel date formats ........ r658336 | nick | 2008-05-20 17:51:49 +0100 (Tue, 20 May 2008) | 1 line Test which seems to show that bug #44996 is invalid, but not completely sure ........ r658349 | nick | 2008-05-20 17:57:20 +0100 (Tue, 20 May 2008) | 1 line Patch from bug #45001 - Partial fix for HWPF Range.insertBefore() and Range.delete() with unicode characters ........ r658350 | nick | 2008-05-20 18:12:08 +0100 (Tue, 20 May 2008) | 1 line Put abstract write(OutputStream) method on POIDocument ........ r658352 | nick | 2008-05-20 18:17:16 +0100 (Tue, 20 May 2008) | 1 line Patch from bug #45003 - Support embeded HDGF visio documents ........ r658833 | josh | 2008-05-21 20:57:40 +0100 (Wed, 21 May 2008) | 1 line improved toString and refactored toFormulaString on Area(3D)Ptg ........ r658984 | josh | 2008-05-22 04:00:29 +0100 (Thu, 22 May 2008) | 1 line Fixed compiler errors. Other improvements for type safety and immutability. ........ r658986 | josh | 2008-05-22 04:26:25 +0100 (Thu, 22 May 2008) | 1 line Follow on from bug 44675 - regenerated functionMetadata.txt from new ooo excelfileformat.odt ........ r659067 | nick | 2008-05-22 10:51:44 +0100 (Thu, 22 May 2008) | 1 line Example for finding hslf sounds from Yegor ........ r659403 | josh | 2008-05-23 04:56:31 +0100 (Fri, 23 May 2008) | 1 line Fix for 45066 - sheet encoding size mismatch problems ........ r659429 | josh | 2008-05-23 06:28:54 +0100 (Fri, 23 May 2008) | 1 line Fix for bug 45046 - allowed DEFINEDNAME records without EXTERNALBOOK records ........ r659452 | josh | 2008-05-23 07:43:51 +0100 (Fri, 23 May 2008) | 1 line Bug 45041 - improved FormulaParser parse error messages ........ r659455 | josh | 2008-05-23 07:54:46 +0100 (Fri, 23 May 2008) | 1 line Bug 45025 - improved FormulaParser parse error messages (r659452 had wrong bug number) ........ r659462 | josh | 2008-05-23 08:42:14 +0100 (Fri, 23 May 2008) | 1 line Marked out test failure which was fixed by patch for bug 39903 ........ r659478 | josh | 2008-05-23 09:55:48 +0100 (Fri, 23 May 2008) | 1 line Fix for bug 35925 - Missing HSSFColor.TAN from HashTables returned by getIndexHash() and getTripletHash() ........ git-svn-id: https://svn.apache.org/repos/asf/poi/branches/ooxml@659485 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src')
-rw-r--r--src/documentation/content/xdocs/changes.xml6
-rw-r--r--src/documentation/content/xdocs/status.xml6
-rw-r--r--src/examples/src/org/apache/poi/hslf/usermodel/examples/SoundFinder.java80
-rw-r--r--src/java/org/apache/poi/POIDocument.java6
-rw-r--r--src/java/org/apache/poi/hssf/model/FormulaParser.java92
-rwxr-xr-xsrc/java/org/apache/poi/hssf/model/LinkTable.java34
-rw-r--r--src/java/org/apache/poi/hssf/model/Sheet.java98
-rw-r--r--src/java/org/apache/poi/hssf/model/Workbook.java3
-rw-r--r--src/java/org/apache/poi/hssf/record/DBCellRecord.java24
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/Area3DPtg.java32
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/AreaPtg.java39
-rw-r--r--src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java185
-rw-r--r--src/java/org/apache/poi/hssf/util/AreaReference.java103
-rw-r--r--src/java/org/apache/poi/hssf/util/HSSFColor.java276
-rw-r--r--src/java/org/apache/poi/ss/usermodel/DateUtil.java4
-rw-r--r--src/resources/main/org/apache/poi/hssf/record/formula/function/functionMetadata-asGenerated.txt10
-rw-r--r--src/resources/main/org/apache/poi/hssf/record/formula/function/functionMetadata.txt6
-rw-r--r--src/scratchpad/src/org/apache/poi/hdgf/HDGFDiagram.java15
-rw-r--r--src/scratchpad/src/org/apache/poi/hwpf/model/FSPATable.java32
-rw-r--r--src/scratchpad/src/org/apache/poi/hwpf/model/FileInformationBlock.java10
-rw-r--r--src/scratchpad/src/org/apache/poi/hwpf/model/TextPiece.java8
-rw-r--r--src/scratchpad/src/org/apache/poi/hwpf/usermodel/Range.java56
-rw-r--r--src/testcases/org/apache/poi/hssf/data/ex45046-21984.xlsbin0 -> 22528 bytes
-rw-r--r--src/testcases/org/apache/poi/hssf/model/TestFormulaParser.java1522
-rw-r--r--src/testcases/org/apache/poi/hssf/model/TestSheet.java21
-rw-r--r--src/testcases/org/apache/poi/hssf/record/formula/function/ExcelFileFormatDocFunctionExtractor.java91
-rw-r--r--src/testcases/org/apache/poi/hssf/record/formula/function/TestParseMissingBuiltInFuncs.java5
-rw-r--r--src/testcases/org/apache/poi/hssf/record/formula/function/TestReadMissingBuiltInFuncs.java12
-rwxr-xr-xsrc/testcases/org/apache/poi/hssf/usermodel/AllUserModelTests.java3
-rw-r--r--src/testcases/org/apache/poi/hssf/usermodel/TestHSSFCell.java24
-rw-r--r--src/testcases/org/apache/poi/hssf/usermodel/TestHSSFDateUtil.java2
-rw-r--r--src/testcases/org/apache/poi/hssf/usermodel/TestHSSFSheet.java169
-rw-r--r--src/testcases/org/apache/poi/hssf/usermodel/TestHSSFWorkbook.java51
-rw-r--r--src/testcases/org/apache/poi/hssf/usermodel/TestLinkTable.java44
-rw-r--r--src/testcases/org/apache/poi/hssf/usermodel/TestSheetHiding.java4
35 files changed, 1589 insertions, 1484 deletions
diff --git a/src/documentation/content/xdocs/changes.xml b/src/documentation/content/xdocs/changes.xml
index b84dec3344..fc755ea79a 100644
--- a/src/documentation/content/xdocs/changes.xml
+++ b/src/documentation/content/xdocs/changes.xml
@@ -44,6 +44,12 @@
<action dev="POI-DEVELOPERS" type="add">Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx</action>
</release>
<release version="3.1-final" date="2008-06-??">
+ <action dev="POI-DEVELOPERS" type="add">45025 - improved FormulaParser parse error messages</action>
+ <action dev="POI-DEVELOPERS" type="add">45046 - allowed EXTERNALBOOK(0x01AE) to be optional in the LinkTable</action>
+ <action dev="POI-DEVELOPERS" type="add">45066 - fixed sheet encoding size mismatch problems</action>
+ <action dev="POI-DEVELOPERS" type="add">45003 - Support embeded HDGF visio documents</action>
+ <action dev="POI-DEVELOPERS" type="fix">45001 - Partial fix for HWPF Range.insertBefore() and Range.delete() with unicode characters</action>
+ <action dev="POI-DEVELOPERS" type="fix">44977 - Support for AM/PM in excel date formats</action>
<action dev="POI-DEVELOPERS" type="add">Support for specifying a policy to HSSF on missing / blank cells when fetching</action>
<action dev="POI-DEVELOPERS" type="add">44937 - Partial support for extracting Escher images from HWPF files</action>
<action dev="POI-DEVELOPERS" type="fix">44824 - Avoid an infinite loop when reading some HWPF pictures</action>
diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml
index 0b7f0140d4..ba2c99ec68 100644
--- a/src/documentation/content/xdocs/status.xml
+++ b/src/documentation/content/xdocs/status.xml
@@ -41,6 +41,12 @@
<action dev="POI-DEVELOPERS" type="add">Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx</action>
</release>
<release version="3.1-final" date="2008-06-??">
+ <action dev="POI-DEVELOPERS" type="add">45025 - improved FormulaParser parse error messages</action>
+ <action dev="POI-DEVELOPERS" type="add">45046 - allowed EXTERNALBOOK(0x01AE) to be optional in the LinkTable</action>
+ <action dev="POI-DEVELOPERS" type="add">45066 - fixed sheet encoding size mismatch problems</action>
+ <action dev="POI-DEVELOPERS" type="add">45003 - Support embeded HDGF visio documents</action>
+ <action dev="POI-DEVELOPERS" type="fix">45001 - Partial fix for HWPF Range.insertBefore() and Range.delete() with unicode characters</action>
+ <action dev="POI-DEVELOPERS" type="fix">44977 - Support for AM/PM in excel date formats</action>
<action dev="POI-DEVELOPERS" type="add">Support for specifying a policy to HSSF on missing / blank cells when fetching</action>
<action dev="POI-DEVELOPERS" type="add">44937 - Partial support for extracting Escher images from HWPF files</action>
<action dev="POI-DEVELOPERS" type="fix">44824 - Avoid an infinite loop when reading some HWPF pictures</action>
diff --git a/src/examples/src/org/apache/poi/hslf/usermodel/examples/SoundFinder.java b/src/examples/src/org/apache/poi/hslf/usermodel/examples/SoundFinder.java
new file mode 100644
index 0000000000..800a4952c8
--- /dev/null
+++ b/src/examples/src/org/apache/poi/hslf/usermodel/examples/SoundFinder.java
@@ -0,0 +1,80 @@
+/* ====================================================================
+ 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.hslf.usermodel.examples;
+import org.apache.poi.ddf.*;
+import org.apache.poi.hslf.model.*;
+import org.apache.poi.hslf.record.InteractiveInfo;
+import org.apache.poi.hslf.record.InteractiveInfoAtom;
+import org.apache.poi.hslf.record.Record;
+import org.apache.poi.hslf.usermodel.*;
+import java.io.FileInputStream;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * For each slide iterate over shapes and found associated sound data.
+ *
+ * @author Yegor Kozlov
+ */
+public class SoundFinder {
+ public static void main(String[] args) throws Exception {
+ SlideShow ppt = new SlideShow(new FileInputStream(args[0]));
+ SoundData[] sounds = ppt.getSoundData();
+
+ Slide[] slide = ppt.getSlides();
+ for (int i = 0; i < slide.length; i++) {
+ Shape[] shape = slide[i].getShapes();
+ for (int j = 0; j < shape.length; j++) {
+ int soundRef = getSoundReference(shape[j]);
+ if(soundRef != -1) {
+ System.out.println("Slide["+i+"], shape["+j+"], soundRef: "+soundRef);
+ System.out.println(" " + sounds[soundRef].getSoundName());
+ System.out.println(" " + sounds[soundRef].getSoundType());
+ }
+ }
+ }
+ }
+
+ /**
+ * Check if a given shape is associated with a sound.
+ * @return 0-based reference to a sound in the sound collection
+ * or -1 if the shape is not associated with a sound
+ */
+ protected static int getSoundReference(Shape shape){
+ int soundRef = -1;
+ //dive into the shape container and search for InteractiveInfoAtom
+ EscherContainerRecord spContainer = shape.getSpContainer();
+ List spchild = spContainer.getChildRecords();
+ for (Iterator it = spchild.iterator(); it.hasNext();) {
+ EscherRecord obj = (EscherRecord) it.next();
+ if (obj.getRecordId() == EscherClientDataRecord.RECORD_ID) {
+ byte[] data = obj.serialize();
+ Record[] records = Record.findChildRecords(data, 8,
+data.length - 8);
+ for (int j = 0; j < records.length; j++) {
+ if (records[j] instanceof InteractiveInfo) {
+ InteractiveInfoAtom info = ((InteractiveInfo)records[j]).getInteractiveInfoAtom();
+ if (info.getAction() == InteractiveInfoAtom.ACTION_MEDIA) {
+ soundRef = info.getSoundRef();
+ }
+ }
+ }
+ }
+ }
+ return soundRef;
+ }
+}
diff --git a/src/java/org/apache/poi/POIDocument.java b/src/java/org/apache/poi/POIDocument.java
index 01e50231ce..4d7e50c0fb 100644
--- a/src/java/org/apache/poi/POIDocument.java
+++ b/src/java/org/apache/poi/POIDocument.java
@@ -20,6 +20,7 @@ package org.apache.poi;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
+import java.io.OutputStream;
import java.util.Iterator;
import java.util.List;
@@ -191,6 +192,11 @@ public abstract class POIDocument {
System.err.println("Couldn't write property set with name " + name + " as not supported by HPSF yet");
}
}
+
+ /**
+ * Writes the document out to the specified output stream
+ */
+ public abstract void write(OutputStream out) throws IOException;
/**
* Copies nodes from one POIFS to the other minus the excepts
diff --git a/src/java/org/apache/poi/hssf/model/FormulaParser.java b/src/java/org/apache/poi/hssf/model/FormulaParser.java
index 39a79bb76d..085a140ad9 100644
--- a/src/java/org/apache/poi/hssf/model/FormulaParser.java
+++ b/src/java/org/apache/poi/hssf/model/FormulaParser.java
@@ -55,7 +55,7 @@ public final class FormulaParser {
*/
static final class FormulaParseException extends RuntimeException {
// This class was given package scope until it would become clear that it is useful to
- // general client code.
+ // general client code.
public FormulaParseException(String msg) {
super(msg);
}
@@ -127,42 +127,34 @@ public final class FormulaParser {
// Just return if so and reset 'look' to something to keep
// SkipWhitespace from spinning
look = (char)0;
- }
+ }
pointer++;
//System.out.println("Got char: "+ look);
}
/** Report What Was Expected */
private RuntimeException expected(String s) {
- String msg = "Parse error near char " + (pointer-1) + "'" + look + "'"
+ String msg = "Parse error near char " + (pointer-1) + " '" + look + "'"
+ " in specified formula '" + formulaString + "'. Expected "
+ s;
return new FormulaParseException(msg);
}
-
-
/** Recognize an Alpha Character */
private boolean IsAlpha(char c) {
return Character.isLetter(c) || c == '$' || c=='_';
}
-
-
/** Recognize a Decimal Digit */
private boolean IsDigit(char c) {
- //System.out.println("Checking digit for"+c);
return Character.isDigit(c);
}
-
-
/** Recognize an Alphanumeric */
private boolean IsAlNum(char c) {
return (IsAlpha(c) || IsDigit(c));
}
-
/** Recognize White Space */
private boolean IsWhite( char c) {
return (c ==' ' || c== TAB);
@@ -178,7 +170,7 @@ public final class FormulaParser {
/**
* Consumes the next input character if it is equal to the one specified otherwise throws an
* unchecked exception. This method does <b>not</b> consume whitespace (before or after the
- * matched character).
+ * matched character).
*/
private void Match(char x) {
if (look != x) {
@@ -218,7 +210,6 @@ public final class FormulaParser {
return Token.toString();
}
-
/** Get a Number */
private String GetNum() {
StringBuffer value = new StringBuffer();
@@ -281,18 +272,18 @@ public final class FormulaParser {
// This can be either a cell ref or a named range
// Try to spot which it is
boolean cellRef = CELL_REFERENCE_PATTERN.matcher(name).matches();
-
+
if (cellRef) {
return new ReferencePtg(name);
}
for(int i = 0; i < book.getNumberOfNames(); i++) {
// named range name matching is case insensitive
- if(book.getNameAt(i).getNameName().equalsIgnoreCase(name)) {
+ if(book.getNameAt(i).getNameName().equalsIgnoreCase(name)) {
return new NamePtg(name, book);
}
}
- throw new FormulaParseException("Found reference to named range \""
+ throw new FormulaParseException("Found reference to named range \""
+ name + "\", but that named range wasn't defined!");
}
@@ -307,19 +298,19 @@ public final class FormulaParser {
/**
* Note - Excel function names are 'case aware but not case sensitive'. This method may end
* up creating a defined name record in the workbook if the specified name is not an internal
- * Excel function, and has not been encountered before.
- *
- * @param name case preserved function name (as it was entered/appeared in the formula).
+ * Excel function, and has not been encountered before.
+ *
+ * @param name case preserved function name (as it was entered/appeared in the formula).
*/
private Ptg function(String name) {
int numArgs =0 ;
- // Note regarding parameter -
+ // Note regarding parameter -
if(!AbstractFunctionPtg.isInternalFunctionName(name)) {
// external functions get a Name token which points to a defined name record
NamePtg nameToken = new NamePtg(name, this.book);
-
+
// in the token tree, the name is more or less the first argument
- numArgs++;
+ numArgs++;
tokens.add(nameToken);
}
//average 2 args per function
@@ -477,26 +468,25 @@ public final class FormulaParser {
private static boolean isArgumentDelimiter(char ch) {
return ch == ',' || ch == ')';
}
-
+
/** get arguments to a function */
private int Arguments(List argumentPointers) {
SkipWhite();
if(look == ')') {
return 0;
}
-
+
boolean missedPrevArg = true;
-
int numArgs = 0;
- while(true) {
+ while (true) {
SkipWhite();
- if(isArgumentDelimiter(look)) {
- if(missedPrevArg) {
+ if (isArgumentDelimiter(look)) {
+ if (missedPrevArg) {
tokens.add(new MissingArgPtg());
addArgumentPointer(argumentPointers);
numArgs++;
}
- if(look == ')') {
+ if (look == ')') {
break;
}
Match(',');
@@ -507,6 +497,10 @@ public final class FormulaParser {
addArgumentPointer(argumentPointers);
numArgs++;
missedPrevArg = false;
+ SkipWhite();
+ if (!isArgumentDelimiter(look)) {
+ throw expected("',' or ')'");
+ }
}
return numArgs;
}
@@ -524,7 +518,7 @@ public final class FormulaParser {
tokens.add(new PowerPtg());
}
}
-
+
private void percentFactor() {
tokens.add(parseSimpleFactor());
while(true) {
@@ -536,8 +530,8 @@ public final class FormulaParser {
tokens.add(new PercentPtg());
}
}
-
-
+
+
/**
* factors (without ^ or % )
*/
@@ -561,9 +555,6 @@ public final class FormulaParser {
return new ParenthesisPtg();
case '"':
return parseStringLiteral();
- case ',':
- case ')':
- return new MissingArgPtg(); // TODO - not quite the right place to recognise a missing arg
}
if (IsAlpha(look) || look == '\''){
return parseIdent();
@@ -707,10 +698,9 @@ public final class FormulaParser {
}
- private StringPtg parseStringLiteral()
- {
+ private StringPtg parseStringLiteral() {
Match('"');
-
+
StringBuffer token = new StringBuffer();
while (true) {
if (look == '"') {
@@ -745,7 +735,7 @@ public final class FormulaParser {
return; // finished with Term
}
}
-
+
private void comparisonExpression() {
concatExpression();
while (true) {
@@ -787,7 +777,7 @@ public final class FormulaParser {
}
return new LessThanPtg();
}
-
+
private void concatExpression() {
additiveExpression();
@@ -801,7 +791,7 @@ public final class FormulaParser {
tokens.add(new ConcatPtg());
}
}
-
+
/** Parse and Translate an Expression */
private void additiveExpression() {
@@ -838,8 +828,9 @@ end;
**/
- /** API call to execute the parsing of the formula
- *
+ /**
+ * API call to execute the parsing of the formula
+ * @deprecated use Ptg[] FormulaParser.parse(String, HSSFWorkbook) directly
*/
public void parse() {
pointer=0;
@@ -847,8 +838,8 @@ end;
comparisonExpression();
if(pointer <= formulaLength) {
- String msg = "Unused input [" + formulaString.substring(pointer-1)
- + "] after attempting to parse the formula [" + formulaString + "]";
+ String msg = "Unused input [" + formulaString.substring(pointer-1)
+ + "] after attempting to parse the formula [" + formulaString + "]";
throw new FormulaParseException(msg);
}
}
@@ -863,11 +854,12 @@ end;
* a result of the parsing
*/
public Ptg[] getRPNPtg() {
- return getRPNPtg(FORMULA_TYPE_CELL);
+ return getRPNPtg(FORMULA_TYPE_CELL);
}
public Ptg[] getRPNPtg(int formulaType) {
Node node = createTree();
+ // RVA is for 'operand class': 'reference', 'value', 'array'
setRootLevelRVA(node, formulaType);
setParameterRVA(node,formulaType);
return (Ptg[]) tokens.toArray(new Ptg[0]);
@@ -948,7 +940,7 @@ end;
}
}
/**
- * Convience method which takes in a list then passes it to the
+ * Convenience method which takes in a list then passes it to the
* other toFormulaString signature.
* @param book workbook for 3D and named references
* @param lptgs list of Ptg, can be null or empty
@@ -963,7 +955,7 @@ end;
return retval;
}
/**
- * Convience method which takes in a list then passes it to the
+ * Convenience method which takes in a list then passes it to the
* other toFormulaString signature. Works on the current
* workbook for 3D and named references
* @param lptgs list of Ptg, can be null or empty
@@ -1011,7 +1003,7 @@ end;
continue;
// but if it ever did, care must be taken:
// tAttrSpace comes *before* the operand it applies to, which may be consistent
- // with how the formula text appears but is against the RPN ordering assumed here
+ // with how the formula text appears but is against the RPN ordering assumed here
}
if (attrPtg.isSemiVolatile()) {
// similar to tAttrSpace - RPN is violated
@@ -1038,7 +1030,7 @@ end;
stack.push(o.toFormulaString(operands));
}
if(stack.isEmpty()) {
- // inspection of the code above reveals that every stack.pop() is followed by a
+ // inspection of the code above reveals that every stack.pop() is followed by a
// stack.push(). So this is either an internal error or impossible.
throw new IllegalStateException("Stack underflow");
}
diff --git a/src/java/org/apache/poi/hssf/model/LinkTable.java b/src/java/org/apache/poi/hssf/model/LinkTable.java
index 88c94a61e7..a19971b7d5 100755
--- a/src/java/org/apache/poi/hssf/model/LinkTable.java
+++ b/src/java/org/apache/poi/hssf/model/LinkTable.java
@@ -41,7 +41,7 @@ import org.apache.poi.hssf.record.SupBookRecord;
*
* In BIFF8 the Link Table consists of
* <ul>
- * <li>one or more EXTERNALBOOK Blocks<p/>
+ * <li>zero or more EXTERNALBOOK Blocks<p/>
* each consisting of
* <ul>
* <li>exactly one EXTERNALBOOK (0x01AE) record</li>
@@ -55,7 +55,7 @@ import org.apache.poi.hssf.record.SupBookRecord;
* </li>
* </ul>
* </li>
- * <li>exactly one EXTERNSHEET (0x0017) record</li>
+ * <li>zero or one EXTERNSHEET (0x0017) record</li>
* <li>zero or more DEFINEDNAME (0x0018) records</li>
* </ul>
*
@@ -63,6 +63,7 @@ import org.apache.poi.hssf.record.SupBookRecord;
* @author Josh Micich
*/
final class LinkTable {
+ // TODO make this class into a record aggregate
private static final class CRNBlock {
@@ -79,8 +80,8 @@ final class LinkTable {
_crns = crns;
}
public CRNRecord[] getCrns() {
- return (CRNRecord[]) _crns.clone();
- }
+ return (CRNRecord[]) _crns.clone();
+ }
}
private static final class ExternalBookBlock {
@@ -136,16 +137,19 @@ final class LinkTable {
while(rs.peekNextClass() == SupBookRecord.class) {
temp.add(new ExternalBookBlock(rs));
}
- if(temp.size() < 1) {
- throw new RuntimeException("Need at least one EXTERNALBOOK blocks");
- }
+
_externalBookBlocks = new ExternalBookBlock[temp.size()];
temp.toArray(_externalBookBlocks);
temp.clear();
-
- // If link table is present, there is always 1 of ExternSheetRecord
- Record next = rs.getNext();
- _externSheetRecord = (ExternSheetRecord)next;
+
+ if (_externalBookBlocks.length > 0) {
+ // If any ExternalBookBlock present, there is always 1 of ExternSheetRecord
+ Record next = rs.getNext();
+ _externSheetRecord = (ExternSheetRecord) next;
+ } else {
+ _externSheetRecord = null;
+ }
+
_definedNames = new ArrayList();
// collect zero or more DEFINEDNAMEs id=0x18
while(rs.peekNextClass() == NameRecord.class) {
@@ -222,7 +226,7 @@ final class LinkTable {
public void addName(NameRecord name) {
_definedNames.add(name);
- // TODO - this is messy
+ // TODO - this is messy
// Not the most efficient way but the other way was causing too many bugs
int idx = findFirstRecordLocBySid(ExternSheetRecord.sid);
if (idx == -1) idx = findFirstRecordLocBySid(SupBookRecord.sid);
@@ -242,8 +246,8 @@ final class LinkTable {
public int getSheetIndexFromExternSheetIndex(int externSheetNumber) {
if (externSheetNumber >= _externSheetRecord.getNumOfREFStructures()) {
- return -1;
- }
+ return -1;
+ }
return _externSheetRecord.getREFRecordAt(externSheetNumber).getIndexToFirstSupBook();
}
@@ -265,7 +269,7 @@ final class LinkTable {
ExternSheetSubRecord esr = _externSheetRecord.getREFRecordAt(i);
if (esr.getIndexToFirstSupBook() == sheetNumber
- && esr.getIndexToLastSupBook() == sheetNumber){
+ && esr.getIndexToLastSupBook() == sheetNumber){
return i;
}
}
diff --git a/src/java/org/apache/poi/hssf/model/Sheet.java b/src/java/org/apache/poi/hssf/model/Sheet.java
index 45090e85cf..871ecc100f 100644
--- a/src/java/org/apache/poi/hssf/model/Sheet.java
+++ b/src/java/org/apache/poi/hssf/model/Sheet.java
@@ -96,8 +96,8 @@ public final class Sheet implements Model {
protected List condFormatting = new ArrayList();
/** Add an UncalcedRecord if not true indicating formulas have not been calculated */
- protected boolean uncalced = false;
-
+ protected boolean _isUncalced = false;
+
public static final byte PANE_LOWER_RIGHT = (byte)0;
public static final byte PANE_UPPER_RIGHT = (byte)1;
public static final byte PANE_LOWER_LEFT = (byte)2;
@@ -162,7 +162,7 @@ public final class Sheet implements Model {
}
}
else if (rec.getSid() == UncalcedRecord.sid) {
- retval.uncalced = true;
+ retval._isUncalced = true;
}
else if (rec.getSid() == DimensionsRecord.sid)
{
@@ -329,16 +329,8 @@ public final class Sheet implements Model {
}
}
retval.records = records;
-// if (retval.rows == null)
-// {
-// retval.rows = new RowRecordsAggregate();
-// }
retval.checkCells();
retval.checkRows();
-// if (retval.cells == null)
-// {
-// retval.cells = new ValueRecordsAggregate();
-// }
if (log.check( POILogger.DEBUG ))
log.log(POILogger.DEBUG, "sheet createSheet (existing file) exited");
return retval;
@@ -816,17 +808,17 @@ public final class Sheet implements Model {
// Once the rows have been found in the list of records, start
// writing out the blocked row information. This includes the DBCell references
if (record instanceof RowRecordsAggregate) {
- pos += ((RowRecordsAggregate)record).serialize(pos, data, cells); // rec.length;
+ pos += ((RowRecordsAggregate)record).serialize(pos, data, cells);
} else if (record instanceof ValueRecordsAggregate) {
//Do nothing here. The records were serialized during the RowRecordAggregate block serialization
} else {
- pos += record.serialize(pos, data ); // rec.length;
+ pos += record.serialize(pos, data );
}
// If the BOF record was just serialized then add the IndexRecord
if (record.getSid() == BOFRecord.sid) {
// Add an optional UncalcedRecord
- if (uncalced) {
+ if (_isUncalced) {
UncalcedRecord rec = new UncalcedRecord();
pos += rec.serialize(pos, data);
}
@@ -837,31 +829,10 @@ public final class Sheet implements Model {
pos += serializeIndexRecord(k, pos, data);
}
}
-
- //// uncomment to test record sizes ////
-// System.out.println( record.getClass().getName() );
-// byte[] data2 = new byte[record.getRecordSize()];
-// record.serialize(0, data2 ); // rec.length;
-// if (LittleEndian.getUShort(data2, 2) != record.getRecordSize() - 4
-// && record instanceof RowRecordsAggregate == false
-// && record instanceof ValueRecordsAggregate == false
-// && record instanceof EscherAggregate == false)
-// {
-// throw new RuntimeException("Blah!!! Size off by " + ( LittleEndian.getUShort(data2, 2) - record.getRecordSize() - 4) + " records.");
-// }
-
-//asd: int len = record.serialize(pos + offset, data );
-
- ///// DEBUG BEGIN /////
-//asd: if (len != record.getRecordSize())
-//asd: throw new IllegalStateException("Record size does not match serialized bytes. Serialized size = " + len + " but getRecordSize() returns " + record.getRecordSize() + ". Record object is " + record.getClass());
- ///// DEBUG END /////
-
-//asd: pos += len; // rec.length;
-
}
- if (log.check( POILogger.DEBUG ))
+ if (log.check( POILogger.DEBUG )) {
log.log(POILogger.DEBUG, "Sheet.serialize returning ");
+ }
return pos-offset;
}
@@ -875,10 +846,17 @@ public final class Sheet implements Model {
for (int j = BOFRecordIndex+1; j < records.size(); j++)
{
Record tmpRec = (( Record ) records.get(j));
- if (tmpRec instanceof RowRecordsAggregate)
- break;
+ if (tmpRec instanceof UncalcedRecord) {
+ continue;
+ }
+ if (tmpRec instanceof RowRecordsAggregate) {
+ break;
+ }
sheetRecSize+= tmpRec.getRecordSize();
}
+ if (_isUncalced) {
+ sheetRecSize += UncalcedRecord.getStaticRecordSize();
+ }
//Add the references to the DBCells in the IndexRecord (one for each block)
int blockCount = rows.getRowBlockCount();
//Calculate the size of this IndexRecord
@@ -2017,31 +1995,33 @@ public final class Sheet implements Model {
{
int retval = 0;
- for ( int k = 0; k < records.size(); k++ )
- {
- retval += ( (Record) records.get( k ) ).getRecordSize();
+ for ( int k = 0; k < records.size(); k++) {
+ Record record = (Record) records.get(k);
+ if (record instanceof UncalcedRecord) {
+ // skip the UncalcedRecord if present, it's only encoded if the isUncalced flag is set
+ continue;
+ }
+ retval += record.getRecordSize();
}
- //Add space for the IndexRecord
if (rows != null) {
- final int blocks = rows.getRowBlockCount();
- retval += IndexRecord.getRecordSizeForBlockCount(blocks);
-
- //Add space for the DBCell records
- //Once DBCell per block.
- //8 bytes per DBCell (non variable section)
- //2 bytes per row reference
- retval += (8 * blocks);
- for (Iterator itr = rows.getIterator(); itr.hasNext();) {
- RowRecord row = (RowRecord)itr.next();
- if (cells != null && cells.rowHasCells(row.getRowNumber()))
- retval += 2;
+ // Add space for the IndexRecord and DBCell records
+ final int nBlocks = rows.getRowBlockCount();
+ int nRows = 0;
+ if (cells != null) {
+ for (Iterator itr = rows.getIterator(); itr.hasNext();) {
+ RowRecord row = (RowRecord)itr.next();
+ if (cells.rowHasCells(row.getRowNumber())) {
+ nRows++;
+ }
+ }
}
+ retval += IndexRecord.getRecordSizeForBlockCount(nBlocks);
+ retval += DBCellRecord.calculateSizeOfRecords(nBlocks, nRows);
}
// Add space for UncalcedRecord
- if (uncalced) {
+ if (_isUncalced) {
retval += UncalcedRecord.getStaticRecordSize();
}
-
return retval;
}
@@ -2518,13 +2498,13 @@ public final class Sheet implements Model {
* @return whether an uncalced record must be inserted or not at generation
*/
public boolean getUncalced() {
- return uncalced;
+ return _isUncalced;
}
/**
* @param uncalced whether an uncalced record must be inserted or not at generation
*/
public void setUncalced(boolean uncalced) {
- this.uncalced = uncalced;
+ this._isUncalced = uncalced;
}
/**
diff --git a/src/java/org/apache/poi/hssf/model/Workbook.java b/src/java/org/apache/poi/hssf/model/Workbook.java
index 08f2263182..d87fc2c632 100644
--- a/src/java/org/apache/poi/hssf/model/Workbook.java
+++ b/src/java/org/apache/poi/hssf/model/Workbook.java
@@ -191,12 +191,11 @@ public class Workbook implements Model
case ExternSheetRecord.sid :
throw new RuntimeException("Extern sheet is part of LinkTable");
case NameRecord.sid :
- throw new RuntimeException("DEFINEDNAME is part of LinkTable");
case SupBookRecord.sid :
+ // LinkTable can start with either of these
if (log.check( POILogger.DEBUG ))
log.log(DEBUG, "found SupBook record at " + k);
retval.linkTable = new LinkTable(recs, k, retval.records);
- // retval.records.supbookpos = k;
k+=retval.linkTable.getRecordCount() - 1;
continue;
case FormatRecord.sid :
diff --git a/src/java/org/apache/poi/hssf/record/DBCellRecord.java b/src/java/org/apache/poi/hssf/record/DBCellRecord.java
index caeb333a52..1da6b82c73 100644
--- a/src/java/org/apache/poi/hssf/record/DBCellRecord.java
+++ b/src/java/org/apache/poi/hssf/record/DBCellRecord.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,7 +14,6 @@
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
-
package org.apache.poi.hssf.record;
@@ -29,10 +27,7 @@ import org.apache.poi.util.LittleEndian;
* @author Jason Height
* @version 2.0-pre
*/
-
-public class DBCellRecord
- extends Record
-{
+public final class DBCellRecord extends Record {
public final static int BLOCK_SIZE = 32;
public final static short sid = 0xd7;
private int field_1_row_offset;
@@ -46,7 +41,6 @@ public class DBCellRecord
* Constructs a DBCellRecord and sets its fields appropriately
* @param in the RecordInputstream to read the record from
*/
-
public DBCellRecord(RecordInputStream in)
{
super(in);
@@ -78,7 +72,6 @@ public class DBCellRecord
*
* @param offset offset to the start of the first cell in the next DBCell block
*/
-
public void setRowOffset(int offset)
{
field_1_row_offset = offset;
@@ -108,7 +101,6 @@ public class DBCellRecord
*
* @return rowoffset to the start of the first cell in the next DBCell block
*/
-
public int getRowOffset()
{
return field_1_row_offset;
@@ -120,7 +112,6 @@ public class DBCellRecord
* @param index of the cell offset to retrieve
* @return celloffset from the celloffset array
*/
-
public short getCellOffsetAt(int index)
{
return field_2_cell_offsets[ index ];
@@ -131,7 +122,6 @@ public class DBCellRecord
*
* @return number of cell offsets
*/
-
public int getNumCellOffsets()
{
return field_2_cell_offsets.length;
@@ -175,9 +165,15 @@ public class DBCellRecord
return 8 + (getNumCellOffsets() * 2);
}
- /** Returns the size of a DBCellRecord when it needs to reference a certain number of rows*/
- public static int getRecordSizeForRows(int rows) {
- return 8 + (rows * 2);
+ /**
+ * @returns the size of the group of <tt>DBCellRecord</tt>s needed to encode
+ * the specified number of blocks and rows
+ */
+ public static int calculateSizeOfRecords(int nBlocks, int nRows) {
+ // One DBCell per block.
+ // 8 bytes per DBCell (non variable section)
+ // 2 bytes per row reference
+ return nBlocks * 8 + nRows * 2;
}
public short getSid()
diff --git a/src/java/org/apache/poi/hssf/record/formula/Area3DPtg.java b/src/java/org/apache/poi/hssf/record/formula/Area3DPtg.java
index 458bd1e594..668a251516 100644
--- a/src/java/org/apache/poi/hssf/record/formula/Area3DPtg.java
+++ b/src/java/org/apache/poi/hssf/record/formula/Area3DPtg.java
@@ -27,7 +27,7 @@ import org.apache.poi.util.LittleEndian;
/**
- * Title: Area 3D Ptg - 3D referecnce (Sheet + Area)<P>
+ * Title: Area 3D Ptg - 3D reference (Sheet + Area)<P>
* Description: Defined a area in Extern Sheet. <P>
* REFERENCE: <P>
* @author Libin Roman (Vista Portal LDT. Developer)
@@ -35,7 +35,6 @@ import org.apache.poi.util.LittleEndian;
* @author Jason Height (jheight at chariot dot net dot au)
* @version 1.0-pre
*/
-
public class Area3DPtg extends Ptg implements AreaI
{
public final static byte sid = 0x3b;
@@ -84,23 +83,15 @@ public class Area3DPtg extends Ptg implements AreaI
setExternSheetIndex(externalSheetIndex);
}
- public String toString()
- {
- StringBuffer buffer = new StringBuffer();
-
- buffer.append( "AreaPtg\n" );
- buffer.append( "Index to Extern Sheet = " + getExternSheetIndex() ).append( "\n" );
- buffer.append( "firstRow = " + getFirstRow() ).append( "\n" );
- buffer.append( "lastRow = " + getLastRow() ).append( "\n" );
- buffer.append( "firstCol = " + getFirstColumn() ).append( "\n" );
- buffer.append( "lastCol = " + getLastColumn() ).append( "\n" );
- buffer.append( "firstColRel= "
- + isFirstRowRelative() ).append( "\n" );
- buffer.append( "lastColRowRel = "
- + isLastRowRelative() ).append( "\n" );
- buffer.append( "firstColRel = " + isFirstColRelative() ).append( "\n" );
- buffer.append( "lastColRel = " + isLastColRelative() ).append( "\n" );
- return buffer.toString();
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append(getClass().getName());
+ sb.append(" [");
+ sb.append("sheetIx=").append(getExternSheetIndex());
+ sb.append(" ! ");
+ sb.append(AreaReference.formatAsString(this));
+ sb.append("]");
+ return sb.toString();
}
public void writeBytes( byte[] array, int offset )
@@ -284,7 +275,7 @@ public class Area3DPtg extends Ptg implements AreaI
}
// Now the normal area bit
- retval.append( AreaPtg.toFormulaString(this, book) );
+ retval.append(AreaReference.formatAsString(this));
// All done
return retval.toString();
@@ -326,6 +317,7 @@ public class Area3DPtg extends Ptg implements AreaI
public int hashCode()
{
+ // TODO - hashCode seems to be unused
int result;
result = (int) field_1_index_extern_sheet;
result = 29 * result + (int) field_2_first_row;
diff --git a/src/java/org/apache/poi/hssf/record/formula/AreaPtg.java b/src/java/org/apache/poi/hssf/record/formula/AreaPtg.java
index c4e7534c7d..38cae39f44 100644
--- a/src/java/org/apache/poi/hssf/record/formula/AreaPtg.java
+++ b/src/java/org/apache/poi/hssf/record/formula/AreaPtg.java
@@ -114,23 +114,13 @@ public class AreaPtg extends Ptg implements AreaI {
return "AreaPtg";
}
- public String toString()
- {
- StringBuffer buffer = new StringBuffer();
-
- buffer.append(getAreaPtgName());
- buffer.append("\n");
- buffer.append("firstRow = " + getFirstRow()).append("\n");
- buffer.append("lastRow = " + getLastRow()).append("\n");
- buffer.append("firstCol = " + getFirstColumn()).append("\n");
- buffer.append("lastCol = " + getLastColumn()).append("\n");
- buffer.append("firstColRowRel= "
- + isFirstRowRelative()).append("\n");
- buffer.append("lastColRowRel = "
- + isLastRowRelative()).append("\n");
- buffer.append("firstColRel = " + isFirstColRelative()).append("\n");
- buffer.append("lastColRel = " + isLastColRelative()).append("\n");
- return buffer.toString();
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append(getClass().getName());
+ sb.append(" [");
+ sb.append(AreaReference.formatAsString(this));
+ sb.append("]");
+ return sb.toString();
}
public void writeBytes(byte [] array, int offset) {
@@ -307,19 +297,8 @@ public class AreaPtg extends Ptg implements AreaI {
field_4_last_column = column;
}
- public String toFormulaString(Workbook book)
- {
- return toFormulaString(this, book);
- }
- protected static String toFormulaString(AreaI area, Workbook book) {
- CellReference topLeft = new CellReference(area.getFirstRow(),area.getFirstColumn(),!area.isFirstRowRelative(),!area.isFirstColRelative());
- CellReference botRight = new CellReference(area.getLastRow(),area.getLastColumn(),!area.isLastRowRelative(),!area.isLastColRelative());
-
- if(AreaReference.isWholeColumnReference(topLeft, botRight)) {
- return (new AreaReference(topLeft, botRight)).formatAsString();
- } else {
- return topLeft.formatAsString() + ":" + botRight.formatAsString();
- }
+ public String toFormulaString(Workbook book) {
+ return AreaReference.formatAsString(this);
}
public byte getDefaultOperandClass() {
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java b/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java
index 08ddb9656f..32fce2f099 100644
--- a/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java
+++ b/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java
@@ -15,12 +15,6 @@
limitations under the License.
==================================================================== */
-
-/*
- * HSSFWorkbook.java
- *
- * Created on September 30, 2001, 3:37 PM
- */
package org.apache.poi.hssf.usermodel;
import java.io.ByteArrayInputStream;
@@ -81,7 +75,6 @@ import org.apache.poi.util.POILogger;
* @author Shawn Laubach (slaubach at apache dot org)
* @version 2.0-pre
*/
-
public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.usermodel.Workbook
{
private static final int DEBUG = POILogger.DEBUG;
@@ -105,7 +98,7 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
* this holds the HSSFSheet objects attached to this workbook
*/
- protected ArrayList sheets;
+ protected List _sheets;
/**
* this holds the HSSFName objects attached to this workbook
@@ -159,7 +152,7 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
{
super(null, null);
workbook = book;
- sheets = new ArrayList( INITIAL_CAPACITY );
+ _sheets = new ArrayList( INITIAL_CAPACITY );
names = new ArrayList( INITIAL_CAPACITY );
}
@@ -250,7 +243,7 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
this.directory = null;
}
- sheets = new ArrayList(INITIAL_CAPACITY);
+ _sheets = new ArrayList(INITIAL_CAPACITY);
names = new ArrayList(INITIAL_CAPACITY);
// Grab the data from the workbook stream, however
@@ -280,7 +273,7 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
HSSFSheet hsheet = new HSSFSheet(this, sheet);
- sheets.add(hsheet);
+ _sheets.add(hsheet);
// workbook.setSheetName(sheets.size() -1, "Sheet"+sheets.size());
}
@@ -378,12 +371,12 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
*/
public void setSheetOrder(String sheetname, int pos ) {
- sheets.add(pos,sheets.remove(getSheetIndex(sheetname)));
+ _sheets.add(pos,_sheets.remove(getSheetIndex(sheetname)));
workbook.setSheetOrder(sheetname, pos);
}
private void validateSheetIndex(int index) {
- int lastSheetIx = sheets.size() - 1;
+ int lastSheetIx = _sheets.size() - 1;
if (index < 0 || index > lastSheetIx) {
throw new IllegalArgumentException("Sheet index ("
+ index +") is out of range (0.." + lastSheetIx + ")");
@@ -397,7 +390,7 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
public void setSelectedTab(int index) {
validateSheetIndex(index);
- int nSheets = sheets.size();
+ int nSheets = _sheets.size();
for (int i=0; i<nSheets; i++) {
getSheetAt(i).setSelected(i == index);
}
@@ -415,7 +408,7 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
for (int i = 0; i < indexes.length; i++) {
validateSheetIndex(indexes[i]);
}
- int nSheets = sheets.size();
+ int nSheets = _sheets.size();
for (int i=0; i<nSheets; i++) {
boolean bSelect = false;
for (int j = 0; j < indexes.length; j++) {
@@ -437,7 +430,7 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
public void setActiveSheet(int index) {
validateSheetIndex(index);
- int nSheets = sheets.size();
+ int nSheets = _sheets.size();
for (int i=0; i<nSheets; i++) {
getSheetAt(i).setActive(i == index);
}
@@ -509,19 +502,15 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
* set the sheet name.
* Will throw IllegalArgumentException if the name is greater than 31 chars
* or contains /\?*[]
- * @param sheet number (0 based)
+ * @param sheetIx number (0 based)
*/
- public void setSheetName(int sheet, String name)
+ public void setSheetName(int sheetIx, String name)
{
- if (workbook.doesContainsSheetName( name, sheet ))
+ if (workbook.doesContainsSheetName( name, sheetIx )) {
throw new IllegalArgumentException( "The workbook already contains a sheet with this name" );
-
- if (sheet > (sheets.size() - 1))
- {
- throw new RuntimeException("Sheet out of bounds");
}
-
- workbook.setSheetName( sheet, name);
+ validateSheetIndex(sheetIx);
+ workbook.setSheetName(sheetIx, name);
}
@@ -533,15 +522,12 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
* or contains /\?*[]
* @param sheet number (0 based)
*/
- public void setSheetName( int sheet, String name, short encoding )
+ public void setSheetName(int sheetIx, String name, short encoding)
{
- if (workbook.doesContainsSheetName( name, sheet ))
+ if (workbook.doesContainsSheetName( name, sheetIx )) {
throw new IllegalArgumentException( "The workbook already contains a sheet with this name" );
-
- if (sheet > (sheets.size() - 1))
- {
- throw new RuntimeException("Sheet out of bounds");
}
+ validateSheetIndex(sheetIx);
switch ( encoding ) {
case ENCODING_COMPRESSED_UNICODE:
@@ -553,51 +539,39 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
throw new RuntimeException( "Unsupported encoding" );
}
- workbook.setSheetName( sheet, name, encoding );
+ workbook.setSheetName( sheetIx, name, encoding );
}
/**
* get the sheet name
- * @param sheet Number
+ * @param sheetIx Number
* @return Sheet name
*/
-
- public String getSheetName(int sheet)
+ public String getSheetName(int sheetIx)
{
- if (sheet > (sheets.size() - 1))
- {
- throw new RuntimeException("Sheet out of bounds");
- }
- return workbook.getSheetName(sheet);
+ validateSheetIndex(sheetIx);
+ return workbook.getSheetName(sheetIx);
}
/**
* check whether a sheet is hidden
- * @param sheet Number
+ * @param sheetIx Number
* @return True if sheet is hidden
*/
-
- public boolean isSheetHidden(int sheet) {
- if (sheet > (sheets.size() - 1))
- {
- throw new RuntimeException("Sheet out of bounds");
- }
- return workbook.isSheetHidden(sheet);
+ public boolean isSheetHidden(int sheetIx) {
+ validateSheetIndex(sheetIx);
+ return workbook.isSheetHidden(sheetIx);
}
/**
* Hide or unhide a sheet
*
- * @param sheetnum The sheet number
+ * @param sheetIx The sheet index
* @param hidden True to mark the sheet as hidden, false otherwise
*/
-
- public void setSheetHidden(int sheet, boolean hidden) {
- if (sheet > (sheets.size() - 1))
- {
- throw new RuntimeException("Sheet out of bounds");
- }
- workbook.setSheetHidden(sheet,hidden);
+ public void setSheetHidden(int sheetIx, boolean hidden) {
+ validateSheetIndex(sheetIx);
+ workbook.setSheetHidden(sheetIx, hidden);
}
/*
@@ -619,12 +593,12 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
/** Returns the index of the given sheet
* @param sheet the sheet to look up
- * @return index of the sheet (0 based)
+ * @return index of the sheet (0 based). <tt>-1</tt> if not found
*/
public int getSheetIndex(org.apache.poi.ss.usermodel.Sheet sheet)
{
- for(int i=0; i<sheets.size(); i++) {
- if(sheets.get(i) == sheet) {
+ for(int i=0; i<_sheets.size(); i++) {
+ if(_sheets.get(i) == sheet) {
return i;
}
}
@@ -653,9 +627,9 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
{
HSSFSheet sheet = new HSSFSheet(this);
- sheets.add(sheet);
- workbook.setSheetName(sheets.size() - 1, "Sheet" + (sheets.size() - 1));
- boolean isOnlySheet = sheets.size() == 1;
+ _sheets.add(sheet);
+ workbook.setSheetName(_sheets.size() - 1, "Sheet" + (_sheets.size() - 1));
+ boolean isOnlySheet = _sheets.size() == 1;
sheet.setSelected(isOnlySheet);
sheet.setActive(isOnlySheet);
return sheet;
@@ -669,13 +643,13 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
public HSSFSheet cloneSheet(int sheetNum) {
validateSheetIndex(sheetNum);
- HSSFSheet srcSheet = (HSSFSheet) sheets.get(sheetNum);
+ HSSFSheet srcSheet = (HSSFSheet) _sheets.get(sheetNum);
String srcName = workbook.getSheetName(sheetNum);
HSSFSheet clonedSheet = srcSheet.cloneSheet(this);
clonedSheet.setSelected(false);
clonedSheet.setActive(false);
- sheets.add(clonedSheet);
+ _sheets.add(clonedSheet);
int i = 1;
while (true) {
// Try and find the next sheet name that is unique
@@ -689,7 +663,7 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
//If the sheet name is unique, then set it otherwise move on to the next number.
if (workbook.getSheetIndex(name) == -1) {
- workbook.setSheetName(sheets.size()-1, name);
+ workbook.setSheetName(_sheets.size()-1, name);
break;
}
}
@@ -710,14 +684,14 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
public HSSFSheet createSheet(String sheetname)
{
- if (workbook.doesContainsSheetName( sheetname, sheets.size() ))
+ if (workbook.doesContainsSheetName( sheetname, _sheets.size() ))
throw new IllegalArgumentException( "The workbook already contains a sheet of this name" );
HSSFSheet sheet = new HSSFSheet(this);
- sheets.add(sheet);
- workbook.setSheetName(sheets.size() - 1, sheetname);
- boolean isOnlySheet = sheets.size() == 1;
+ _sheets.add(sheet);
+ workbook.setSheetName(_sheets.size() - 1, sheetname);
+ boolean isOnlySheet = _sheets.size() == 1;
sheet.setSelected(isOnlySheet);
sheet.setActive(isOnlySheet);
return sheet;
@@ -730,13 +704,19 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
public int getNumberOfSheets()
{
- return sheets.size();
+ return _sheets.size();
}
public int getSheetIndexFromExternSheetIndex(int externSheetNumber) {
return workbook.getSheetIndexFromExternSheetIndex(externSheetNumber);
}
+ private HSSFSheet[] getSheets() {
+ HSSFSheet[] result = new HSSFSheet[_sheets.size()];
+ _sheets.toArray(result);
+ return result;
+ }
+
/**
* Get the HSSFSheet object at the given index.
* @param index of the sheet number (0-based physical & logical)
@@ -745,7 +725,7 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
public HSSFSheet getSheetAt(int index)
{
- return (HSSFSheet) sheets.get(index);
+ return (HSSFSheet) _sheets.get(index);
}
/**
@@ -758,13 +738,13 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
{
HSSFSheet retval = null;
- for (int k = 0; k < sheets.size(); k++)
+ for (int k = 0; k < _sheets.size(); k++)
{
String sheetname = workbook.getSheetName(k);
if (sheetname.equalsIgnoreCase(name))
{
- retval = (HSSFSheet) sheets.get(k);
+ retval = (HSSFSheet) _sheets.get(k);
}
}
return retval;
@@ -793,11 +773,11 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
boolean wasActive = getSheetAt(index).isActive();
boolean wasSelected = getSheetAt(index).isSelected();
- sheets.remove(index);
+ _sheets.remove(index);
workbook.removeSheet(index);
// set the remaining active/selected sheet
- int nSheets = sheets.size();
+ int nSheets = _sheets.size();
if (nSheets < 1) {
// nothing more to do if there are no sheets left
return;
@@ -1173,48 +1153,47 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
public byte[] getBytes()
{
- if (log.check( POILogger.DEBUG ))
+ if (log.check( POILogger.DEBUG )) {
log.log(DEBUG, "HSSFWorkbook.getBytes()");
+ }
+
+ HSSFSheet[] sheets = getSheets();
+ int nSheets = sheets.length;
// before getting the workbook size we must tell the sheets that
// serialization is about to occur.
- for (int k = 0; k < sheets.size(); k++)
- ((HSSFSheet) sheets.get(k)).getSheet().preSerialize();
-
- int wbsize = workbook.getSize();
+ for (int i = 0; i < nSheets; i++) {
+ sheets[i].getSheet().preSerialize();
+ }
- // log.debug("REMOVEME: old sizing method "+workbook.serialize().length);
- // ArrayList sheetbytes = new ArrayList(sheets.size());
- int totalsize = wbsize;
+ int totalsize = workbook.getSize();
- for (int k = 0; k < sheets.size(); k++)
- {
+ // pre-calculate all the sheet sizes and set BOF indexes
+ int[] estimatedSheetSizes = new int[nSheets];
+ for (int k = 0; k < nSheets; k++) {
workbook.setSheetBof(k, totalsize);
- totalsize += ((HSSFSheet) sheets.get(k)).getSheet().getSize();
+ int sheetSize = sheets[k].getSheet().getSize();
+ estimatedSheetSizes[k] = sheetSize;
+ totalsize += sheetSize;
}
-/* if (totalsize < 4096)
- {
- totalsize = 4096;
- }*/
byte[] retval = new byte[totalsize];
int pos = workbook.serialize(0, retval);
- // System.arraycopy(wb, 0, retval, 0, wb.length);
- for (int k = 0; k < sheets.size(); k++)
- {
-
- // byte[] sb = (byte[])sheetbytes.get(k);
- // System.arraycopy(sb, 0, retval, pos, sb.length);
- int len = ((HSSFSheet) sheets.get(k)).getSheet().serialize(pos,
- retval);
- pos += len; // sb.length;
+ for (int k = 0; k < nSheets; k++) {
+ int serializedSize = sheets[k].getSheet().serialize(pos, retval);
+ if (serializedSize != estimatedSheetSizes[k]) {
+ // Wrong offset values have been passed in the call to setSheetBof() above.
+ // For books with more than one sheet, this discrepancy would cause excel
+ // to report errors and loose data while reading the workbook
+ throw new IllegalStateException("Actual serialized sheet size (" + serializedSize
+ + ") differs from pre-calculated size (" + estimatedSheetSizes[k]
+ + ") for sheet (" + k + ")");
+ // TODO - add similar sanity check to ensure that Sheet.serializeIndexRecord() does not write mis-aligned offsets either
+ }
+ pos += serializedSize;
}
-/* for (int k = pos; k < totalsize; k++)
- {
- retval[k] = 0;
- }*/
return retval;
}
diff --git a/src/java/org/apache/poi/hssf/util/AreaReference.java b/src/java/org/apache/poi/hssf/util/AreaReference.java
index 3f6b321a6e..a10b9976aa 100644
--- a/src/java/org/apache/poi/hssf/util/AreaReference.java
+++ b/src/java/org/apache/poi/hssf/util/AreaReference.java
@@ -15,12 +15,13 @@
limitations under the License.
==================================================================== */
-
package org.apache.poi.hssf.util;
import java.util.ArrayList;
import java.util.StringTokenizer;
+import org.apache.poi.hssf.record.formula.AreaI;
+
public final class AreaReference {
/** The character (!) that separates sheet names from cell references */
@@ -50,13 +51,13 @@ public final class AreaReference {
// Special handling for whole-column references
if(parts.length == 2 && parts[0].length() == 1 &&
- parts[1].length() == 1 &&
- parts[0].charAt(0) >= 'A' && parts[0].charAt(0) <= 'Z' &&
- parts[1].charAt(0) >= 'A' && parts[1].charAt(0) <= 'Z') {
- // Represented internally as x$1 to x$65536
- // which is the maximum range of rows
- parts[0] = parts[0] + "$1";
- parts[1] = parts[1] + "$65536";
+ parts[1].length() == 1 &&
+ parts[0].charAt(0) >= 'A' && parts[0].charAt(0) <= 'Z' &&
+ parts[1].charAt(0) >= 'A' && parts[1].charAt(0) <= 'Z') {
+ // Represented internally as x$1 to x$65536
+ // which is the maximum range of rows
+ parts[0] = parts[0] + "$1";
+ parts[1] = parts[1] + "$65536";
}
_firstCell = new CellReference(parts[0]);
@@ -74,9 +75,9 @@ public final class AreaReference {
* Creates an area ref from a pair of Cell References.
*/
public AreaReference(CellReference topLeft, CellReference botRight) {
- _firstCell = topLeft;
- _lastCell = botRight;
- _isSingleCell = false;
+ _firstCell = topLeft;
+ _lastCell = botRight;
+ _isSingleCell = false;
}
/**
@@ -98,17 +99,17 @@ public final class AreaReference {
* such as C:C or D:G ?
*/
public static boolean isWholeColumnReference(CellReference topLeft, CellReference botRight) {
- // These are represented as something like
- // C$1:C$65535 or D$1:F$0
- // i.e. absolute from 1st row to 0th one
- if(topLeft.getRow() == 0 && topLeft.isRowAbsolute() &&
- botRight.getRow() == 65535 && botRight.isRowAbsolute()) {
- return true;
- }
- return false;
+ // These are represented as something like
+ // C$1:C$65535 or D$1:F$0
+ // i.e. absolute from 1st row to 0th one
+ if(topLeft.getRow() == 0 && topLeft.isRowAbsolute() &&
+ botRight.getRow() == 65535 && botRight.isRowAbsolute()) {
+ return true;
+ }
+ return false;
}
public boolean isWholeColumnReference() {
- return isWholeColumnReference(_firstCell, _lastCell);
+ return isWholeColumnReference(_firstCell, _lastCell);
}
/**
@@ -155,26 +156,26 @@ public final class AreaReference {
* Returns a reference to every cell covered by this area
*/
public CellReference[] getAllReferencedCells() {
- // Special case for single cell reference
- if(_isSingleCell) {
- return new CellReference[] { _firstCell, };
- }
+ // Special case for single cell reference
+ if(_isSingleCell) {
+ return new CellReference[] { _firstCell, };
+ }
- // Interpolate between the two
+ // Interpolate between the two
int minRow = Math.min(_firstCell.getRow(), _lastCell.getRow());
- int maxRow = Math.max(_firstCell.getRow(), _lastCell.getRow());
- int minCol = Math.min(_firstCell.getCol(), _lastCell.getCol());
- int maxCol = Math.max(_firstCell.getCol(), _lastCell.getCol());
+ int maxRow = Math.max(_firstCell.getRow(), _lastCell.getRow());
+ int minCol = Math.min(_firstCell.getCol(), _lastCell.getCol());
+ int maxCol = Math.max(_firstCell.getCol(), _lastCell.getCol());
String sheetName = _firstCell.getSheetName();
-
- ArrayList refs = new ArrayList();
- for(int row=minRow; row<=maxRow; row++) {
- for(int col=minCol; col<=maxCol; col++) {
- CellReference ref = new CellReference(sheetName, row, col, _firstCell.isRowAbsolute(), _firstCell.isColAbsolute());
- refs.add(ref);
- }
- }
- return (CellReference[])refs.toArray(new CellReference[refs.size()]);
+
+ ArrayList refs = new ArrayList();
+ for(int row=minRow; row<=maxRow; row++) {
+ for(int col=minCol; col<=maxCol; col++) {
+ CellReference ref = new CellReference(sheetName, row, col, _firstCell.isRowAbsolute(), _firstCell.isColAbsolute());
+ refs.add(ref);
+ }
+ }
+ return (CellReference[])refs.toArray(new CellReference[refs.size()]);
}
/**
@@ -189,14 +190,14 @@ public final class AreaReference {
* @return the text representation of this area reference as it would appear in a formula.
*/
public String formatAsString() {
- // Special handling for whole-column references
- if(isWholeColumnReference()) {
- return
- CellReference.convertNumToColString(_firstCell.getCol())
- + ":" +
- CellReference.convertNumToColString(_lastCell.getCol());
- }
-
+ // Special handling for whole-column references
+ if(isWholeColumnReference()) {
+ return
+ CellReference.convertNumToColString(_firstCell.getCol())
+ + ":" +
+ CellReference.convertNumToColString(_lastCell.getCol());
+ }
+
StringBuffer sb = new StringBuffer(32);
sb.append(_firstCell.formatAsString());
if(!_isSingleCell) {
@@ -210,6 +211,18 @@ public final class AreaReference {
}
return sb.toString();
}
+ /**
+ * Formats a 2-D area as it would appear in a formula. See formatAsString() (no-arg)
+ */
+ public static String formatAsString(AreaI area) {
+ CellReference topLeft = new CellReference(area.getFirstRow(),area.getFirstColumn(),!area.isFirstRowRelative(),!area.isFirstColRelative());
+ CellReference botRight = new CellReference(area.getLastRow(),area.getLastColumn(),!area.isLastRowRelative(),!area.isLastColRelative());
+
+ if(isWholeColumnReference(topLeft, botRight)) {
+ return (new AreaReference(topLeft, botRight)).formatAsString();
+ }
+ return topLeft.formatAsString() + ":" + botRight.formatAsString();
+ }
public String toString() {
StringBuffer sb = new StringBuffer(64);
sb.append(getClass().getName()).append(" [");
diff --git a/src/java/org/apache/poi/hssf/util/HSSFColor.java b/src/java/org/apache/poi/hssf/util/HSSFColor.java
index 9251ccc74e..2c51b3d208 100644
--- a/src/java/org/apache/poi/hssf/util/HSSFColor.java
+++ b/src/java/org/apache/poi/hssf/util/HSSFColor.java
@@ -15,16 +15,16 @@
limitations under the License.
==================================================================== */
-
package org.apache.poi.hssf.util;
+import java.lang.reflect.Field;
import java.util.Hashtable;
import org.apache.poi.ss.usermodel.Color;
/**
* Intends to provide support for the very evil index to triplet issue and
- * will likely replace the color contants interface for HSSF 2.0.
+ * will likely replace the color constants interface for HSSF 2.0.
* This class contains static inner class members for representing colors.
* Each color has an index (for the standard palette in Excel (tm) ),
* native (RGB) triplet and string triplet. The string triplet is as the
@@ -35,14 +35,10 @@ import org.apache.poi.ss.usermodel.Color;
* @author Andrew C. Oliver (acoliver at apache dot org)
* @author Brian Sanders (bsanders at risklabs dot com) - full default color palette
*/
-
-public class HSSFColor implements Color
-{
- private final static int PALETTE_SIZE = 56;
- private final static int DISTINCT_COLOR_COUNT = 46;
+public class HSSFColor implements Color {
+ // TODO make subclass instances immutable
/** Creates a new instance of HSSFColor */
-
public HSSFColor()
{
}
@@ -54,87 +50,86 @@ public class HSSFColor implements Color
* it takes to create it once per request but you will not hold onto it
* if you have none of those requests.
*
- * @return a hashtable containing all colors mapped to their excel-style
- * pallette index
+ * @return a hashtable containing all colors keyed by <tt>Integer</tt> excel-style palette indexes
*/
public final static Hashtable getIndexHash() {
- Hashtable hash = new Hashtable(PALETTE_SIZE);
-
- hash.put(new Integer(HSSFColor.BLACK.index), new HSSFColor.BLACK());
- hash.put(new Integer(HSSFColor.BROWN.index), new HSSFColor.BROWN());
- hash.put(new Integer(HSSFColor.OLIVE_GREEN.index),
- new HSSFColor.OLIVE_GREEN());
- hash.put(new Integer(HSSFColor.DARK_GREEN.index), new HSSFColor.DARK_GREEN());
- hash.put(new Integer(HSSFColor.DARK_TEAL.index), new HSSFColor.DARK_TEAL());
- hash.put(new Integer(HSSFColor.DARK_BLUE.index), new HSSFColor.DARK_BLUE());
- hash.put(new Integer(HSSFColor.DARK_BLUE.index2), new HSSFColor.DARK_BLUE());
- hash.put(new Integer(HSSFColor.INDIGO.index), new HSSFColor.INDIGO());
- hash.put(new Integer(HSSFColor.GREY_80_PERCENT.index),
- new HSSFColor.GREY_80_PERCENT());
- hash.put(new Integer(HSSFColor.ORANGE.index), new HSSFColor.ORANGE());
- hash.put(new Integer(HSSFColor.DARK_YELLOW.index),
- new HSSFColor.DARK_YELLOW());
- hash.put(new Integer(HSSFColor.GREEN.index), new HSSFColor.GREEN());
- hash.put(new Integer(HSSFColor.TEAL.index), new HSSFColor.TEAL());
- hash.put(new Integer(HSSFColor.TEAL.index2), new HSSFColor.TEAL());
- hash.put(new Integer(HSSFColor.BLUE.index), new HSSFColor.BLUE());
- hash.put(new Integer(HSSFColor.BLUE.index2), new HSSFColor.BLUE());
- hash.put(new Integer(HSSFColor.BLUE_GREY.index), new HSSFColor.BLUE_GREY());
- hash.put(new Integer(HSSFColor.GREY_50_PERCENT.index),
- new HSSFColor.GREY_50_PERCENT());
- hash.put(new Integer(HSSFColor.RED.index), new HSSFColor.RED());
- hash.put(new Integer(HSSFColor.LIGHT_ORANGE.index),
- new HSSFColor.LIGHT_ORANGE());
- hash.put(new Integer(HSSFColor.LIME.index), new HSSFColor.LIME());
- hash.put(new Integer(HSSFColor.SEA_GREEN.index), new HSSFColor.SEA_GREEN());
- hash.put(new Integer(HSSFColor.AQUA.index), new HSSFColor.AQUA());
- hash.put(new Integer(HSSFColor.LIGHT_BLUE.index), new HSSFColor.LIGHT_BLUE());
- hash.put(new Integer(HSSFColor.VIOLET.index), new HSSFColor.VIOLET());
- hash.put(new Integer(HSSFColor.VIOLET.index2), new HSSFColor.VIOLET());
- hash.put(new Integer(HSSFColor.GREY_40_PERCENT.index),
- new HSSFColor.GREY_40_PERCENT());
- hash.put(new Integer(HSSFColor.PINK.index), new HSSFColor.PINK());
- hash.put(new Integer(HSSFColor.PINK.index2), new HSSFColor.PINK());
- hash.put(new Integer(HSSFColor.GOLD.index), new HSSFColor.GOLD());
- hash.put(new Integer(HSSFColor.YELLOW.index), new HSSFColor.YELLOW());
- hash.put(new Integer(HSSFColor.YELLOW.index2), new HSSFColor.YELLOW());
- hash.put(new Integer(HSSFColor.BRIGHT_GREEN.index),
- new HSSFColor.BRIGHT_GREEN());
- hash.put(new Integer(HSSFColor.BRIGHT_GREEN.index2),
- new HSSFColor.BRIGHT_GREEN());
- hash.put(new Integer(HSSFColor.TURQUOISE.index), new HSSFColor.TURQUOISE());
- hash.put(new Integer(HSSFColor.TURQUOISE.index2), new HSSFColor.TURQUOISE());
- hash.put(new Integer(HSSFColor.DARK_RED.index), new HSSFColor.DARK_RED());
- hash.put(new Integer(HSSFColor.DARK_RED.index2), new HSSFColor.DARK_RED());
- hash.put(new Integer(HSSFColor.SKY_BLUE.index), new HSSFColor.SKY_BLUE());
- hash.put(new Integer(HSSFColor.PLUM.index), new HSSFColor.PLUM());
- hash.put(new Integer(HSSFColor.PLUM.index2), new HSSFColor.PLUM());
- hash.put(new Integer(HSSFColor.GREY_25_PERCENT.index),
- new HSSFColor.GREY_25_PERCENT());
- hash.put(new Integer(HSSFColor.ROSE.index), new HSSFColor.ROSE());
- hash.put(new Integer(HSSFColor.LIGHT_YELLOW.index),
- new HSSFColor.LIGHT_YELLOW());
- hash.put(new Integer(HSSFColor.LIGHT_GREEN.index),
- new HSSFColor.LIGHT_GREEN());
- hash.put(new Integer(HSSFColor.LIGHT_TURQUOISE.index),
- new HSSFColor.LIGHT_TURQUOISE());
- hash.put(new Integer(HSSFColor.LIGHT_TURQUOISE.index2),
- new HSSFColor.LIGHT_TURQUOISE());
- hash.put(new Integer(HSSFColor.PALE_BLUE.index), new HSSFColor.PALE_BLUE());
- hash.put(new Integer(HSSFColor.LAVENDER.index), new HSSFColor.LAVENDER());
- hash.put(new Integer(HSSFColor.WHITE.index), new HSSFColor.WHITE());
- hash.put(new Integer(HSSFColor.CORNFLOWER_BLUE.index),
- new HSSFColor.CORNFLOWER_BLUE());
- hash.put(new Integer(HSSFColor.LEMON_CHIFFON.index),
- new HSSFColor.LEMON_CHIFFON());
- hash.put(new Integer(HSSFColor.MAROON.index), new HSSFColor.MAROON());
- hash.put(new Integer(HSSFColor.ORCHID.index), new HSSFColor.ORCHID());
- hash.put(new Integer(HSSFColor.CORAL.index), new HSSFColor.CORAL());
- hash.put(new Integer(HSSFColor.ROYAL_BLUE.index), new HSSFColor.ROYAL_BLUE());
- hash.put(new Integer(HSSFColor.LIGHT_CORNFLOWER_BLUE.index),
- new HSSFColor.LIGHT_CORNFLOWER_BLUE());
- return hash;
+ return createColorsByIndexMap();
+ }
+
+ private static Hashtable createColorsByIndexMap() {
+ HSSFColor[] colors = getAllColors();
+ Hashtable result = new Hashtable(colors.length * 3 / 2);
+
+ for (int i = 0; i < colors.length; i++) {
+ HSSFColor color = colors[i];
+
+ Integer index1 = new Integer(color.getIndex());
+ if (result.containsKey(index1)) {
+ HSSFColor prevColor = (HSSFColor)result.get(index1);
+ throw new RuntimeException("Dup color index (" + index1
+ + ") for colors (" + prevColor.getClass().getName()
+ + "),(" + color.getClass().getName() + ")");
+ }
+ result.put(index1, color);
+ }
+
+ for (int i = 0; i < colors.length; i++) {
+ HSSFColor color = colors[i];
+ Integer index2 = getIndex2(color);
+ if (index2 == null) {
+ // most colors don't have a second index
+ continue;
+ }
+ if (result.containsKey(index2)) {
+ if (false) { // Many of the second indexes clash
+ HSSFColor prevColor = (HSSFColor)result.get(index2);
+ throw new RuntimeException("Dup color index (" + index2
+ + ") for colors (" + prevColor.getClass().getName()
+ + "),(" + color.getClass().getName() + ")");
+ }
+ }
+ result.put(index2, color);
+ }
+ return result;
+ }
+
+ private static Integer getIndex2(HSSFColor color) {
+
+ Field f;
+ try {
+ f = color.getClass().getDeclaredField("index2");
+ } catch (NoSuchFieldException e) {
+ // can happen because not all colors have a second index
+ return null;
+ }
+
+ Short s;
+ try {
+ s = (Short) f.get(color);
+ } catch (IllegalArgumentException e) {
+ throw new RuntimeException(e);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ return new Integer(s.intValue());
+ }
+
+ private static HSSFColor[] getAllColors() {
+
+ return new HSSFColor[] {
+ new BLACK(), new BROWN(), new OLIVE_GREEN(), new DARK_GREEN(),
+ new DARK_TEAL(), new DARK_BLUE(), new INDIGO(), new GREY_80_PERCENT(),
+ new ORANGE(), new DARK_YELLOW(), new GREEN(), new TEAL(), new BLUE(),
+ new BLUE_GREY(), new GREY_50_PERCENT(), new RED(), new LIGHT_ORANGE(), new LIME(),
+ new SEA_GREEN(), new AQUA(), new LIGHT_BLUE(), new VIOLET(), new GREY_40_PERCENT(),
+ new PINK(), new GOLD(), new YELLOW(), new BRIGHT_GREEN(), new TURQUOISE(),
+ new DARK_RED(), new SKY_BLUE(), new PLUM(), new GREY_25_PERCENT(), new ROSE(),
+ new LIGHT_YELLOW(), new LIGHT_GREEN(), new LIGHT_TURQUOISE(), new PALE_BLUE(),
+ new LAVENDER(), new WHITE(), new CORNFLOWER_BLUE(), new LEMON_CHIFFON(),
+ new MAROON(), new ORCHID(), new CORAL(), new ROYAL_BLUE(),
+ new LIGHT_CORNFLOWER_BLUE(), new TAN(),
+ };
}
/**
@@ -144,73 +139,28 @@ public class HSSFColor implements Color
* it takes to create it once per request but you will not hold onto it
* if you have none of those requests.
*
- * @return a hashtable containing all colors mapped to their gnumeric-like
- * triplet string
+ * @return a hashtable containing all colors keyed by String gnumeric-like triplets
*/
-
public final static Hashtable getTripletHash()
{
- Hashtable hash = new Hashtable(DISTINCT_COLOR_COUNT);
-
- hash.put(HSSFColor.BLACK.hexString, new HSSFColor.BLACK());
- hash.put(HSSFColor.BROWN.hexString, new HSSFColor.BROWN());
- hash.put(HSSFColor.OLIVE_GREEN.hexString,
- new HSSFColor.OLIVE_GREEN());
- hash.put(HSSFColor.DARK_GREEN.hexString, new HSSFColor.DARK_GREEN());
- hash.put(HSSFColor.DARK_TEAL.hexString, new HSSFColor.DARK_TEAL());
- hash.put(HSSFColor.DARK_BLUE.hexString, new HSSFColor.DARK_BLUE());
- hash.put(HSSFColor.INDIGO.hexString, new HSSFColor.INDIGO());
- hash.put(HSSFColor.GREY_80_PERCENT.hexString,
- new HSSFColor.GREY_80_PERCENT());
- hash.put(HSSFColor.ORANGE.hexString, new HSSFColor.ORANGE());
- hash.put(HSSFColor.DARK_YELLOW.hexString,
- new HSSFColor.DARK_YELLOW());
- hash.put(HSSFColor.GREEN.hexString, new HSSFColor.GREEN());
- hash.put(HSSFColor.TEAL.hexString, new HSSFColor.TEAL());
- hash.put(HSSFColor.BLUE.hexString, new HSSFColor.BLUE());
- hash.put(HSSFColor.BLUE_GREY.hexString, new HSSFColor.BLUE_GREY());
- hash.put(HSSFColor.GREY_50_PERCENT.hexString,
- new HSSFColor.GREY_50_PERCENT());
- hash.put(HSSFColor.RED.hexString, new HSSFColor.RED());
- hash.put(HSSFColor.LIGHT_ORANGE.hexString,
- new HSSFColor.LIGHT_ORANGE());
- hash.put(HSSFColor.LIME.hexString, new HSSFColor.LIME());
- hash.put(HSSFColor.SEA_GREEN.hexString, new HSSFColor.SEA_GREEN());
- hash.put(HSSFColor.AQUA.hexString, new HSSFColor.AQUA());
- hash.put(HSSFColor.LIGHT_BLUE.hexString, new HSSFColor.LIGHT_BLUE());
- hash.put(HSSFColor.VIOLET.hexString, new HSSFColor.VIOLET());
- hash.put(HSSFColor.GREY_40_PERCENT.hexString,
- new HSSFColor.GREY_40_PERCENT());
- hash.put(HSSFColor.PINK.hexString, new HSSFColor.PINK());
- hash.put(HSSFColor.GOLD.hexString, new HSSFColor.GOLD());
- hash.put(HSSFColor.YELLOW.hexString, new HSSFColor.YELLOW());
- hash.put(HSSFColor.BRIGHT_GREEN.hexString,
- new HSSFColor.BRIGHT_GREEN());
- hash.put(HSSFColor.TURQUOISE.hexString, new HSSFColor.TURQUOISE());
- hash.put(HSSFColor.DARK_RED.hexString, new HSSFColor.DARK_RED());
- hash.put(HSSFColor.SKY_BLUE.hexString, new HSSFColor.SKY_BLUE());
- hash.put(HSSFColor.PLUM.hexString, new HSSFColor.PLUM());
- hash.put(HSSFColor.GREY_25_PERCENT.hexString,
- new HSSFColor.GREY_25_PERCENT());
- hash.put(HSSFColor.ROSE.hexString, new HSSFColor.ROSE());
- hash.put(HSSFColor.LIGHT_YELLOW.hexString,
- new HSSFColor.LIGHT_YELLOW());
- hash.put(HSSFColor.LIGHT_GREEN.hexString,
- new HSSFColor.LIGHT_GREEN());
- hash.put(HSSFColor.LIGHT_TURQUOISE.hexString,
- new HSSFColor.LIGHT_TURQUOISE());
- hash.put(HSSFColor.PALE_BLUE.hexString, new HSSFColor.PALE_BLUE());
- hash.put(HSSFColor.LAVENDER.hexString, new HSSFColor.LAVENDER());
- hash.put(HSSFColor.WHITE.hexString, new HSSFColor.WHITE());
- hash.put(HSSFColor.CORNFLOWER_BLUE.hexString, new HSSFColor.CORNFLOWER_BLUE());
- hash.put(HSSFColor.LEMON_CHIFFON.hexString, new HSSFColor.LEMON_CHIFFON());
- hash.put(HSSFColor.MAROON.hexString, new HSSFColor.MAROON());
- hash.put(HSSFColor.ORCHID.hexString, new HSSFColor.ORCHID());
- hash.put(HSSFColor.CORAL.hexString, new HSSFColor.CORAL());
- hash.put(HSSFColor.ROYAL_BLUE.hexString, new HSSFColor.ROYAL_BLUE());
- hash.put(HSSFColor.LIGHT_CORNFLOWER_BLUE.hexString,
- new HSSFColor.LIGHT_CORNFLOWER_BLUE());
- return hash;
+ return createColorsByHexStringMap();
+ }
+
+ private static Hashtable createColorsByHexStringMap() {
+ HSSFColor[] colors = getAllColors();
+ Hashtable result = new Hashtable(colors.length * 3 / 2);
+
+ for (int i = 0; i < colors.length; i++) {
+ HSSFColor color = colors[i];
+
+ String hexString = color.getHexString();
+ if (result.containsKey(hexString)) {
+ throw new RuntimeException("Dup color hexString (" + hexString
+ + ") for color (" + color.getClass().getName() + ")");
+ }
+ result.put(hexString, color);
+ }
+ return result;
}
/**
@@ -1492,7 +1442,7 @@ public class HSSFColor implements Color
return hexString;
}
}
-
+
/**
* Class CORNFLOWER_BLUE
*/
@@ -1521,8 +1471,8 @@ public class HSSFColor implements Color
return hexString;
}
}
-
-
+
+
/**
* Class LEMON_CHIFFON
*/
@@ -1551,7 +1501,7 @@ public class HSSFColor implements Color
return hexString;
}
}
-
+
/**
* Class MAROON
*/
@@ -1580,7 +1530,7 @@ public class HSSFColor implements Color
return hexString;
}
}
-
+
/**
* Class ORCHID
*/
@@ -1609,7 +1559,7 @@ public class HSSFColor implements Color
return hexString;
}
}
-
+
/**
* Class CORAL
*/
@@ -1638,7 +1588,7 @@ public class HSSFColor implements Color
return hexString;
}
}
-
+
/**
* Class ROYAL_BLUE
*/
@@ -1667,7 +1617,7 @@ public class HSSFColor implements Color
return hexString;
}
}
-
+
/**
* Class LIGHT_CORNFLOWER_BLUE
*/
@@ -1696,19 +1646,19 @@ public class HSSFColor implements Color
return hexString;
}
}
-
+
/**
* Special Default/Normal/Automatic color.
* <p><i>Note:</i> This class is NOT in the default HashTables returned by HSSFColor.
* The index is a special case which is interpreted in the various setXXXColor calls.
- *
+ *
* @author Jason
*
*/
public final static class AUTOMATIC extends HSSFColor
{
- private static HSSFColor instance = new AUTOMATIC();
-
+ private static HSSFColor instance = new AUTOMATIC();
+
public final static short index = 0x40;
public short getIndex()
@@ -1725,7 +1675,7 @@ public class HSSFColor implements Color
{
return BLACK.hexString;
}
-
+
public static HSSFColor getInstance() {
return instance;
}
diff --git a/src/java/org/apache/poi/ss/usermodel/DateUtil.java b/src/java/org/apache/poi/ss/usermodel/DateUtil.java
index 9335de35da..0a9bdcfe88 100644
--- a/src/java/org/apache/poi/ss/usermodel/DateUtil.java
+++ b/src/java/org/apache/poi/ss/usermodel/DateUtil.java
@@ -226,7 +226,9 @@ public class DateUtil
// Otherwise, check it's only made up, in any case, of:
// y m d h s - / , . :
- if(fs.matches("^[yYmMdDhHsS\\-/,. :]+$")) {
+ // optionally followed by AM/PM
+ // optionally followed by AM/PM
+ if(fs.matches("^[yYmMdDhHsS\\-/,. :]+[ampAMP]*$")) {
return true;
}
diff --git a/src/resources/main/org/apache/poi/hssf/record/formula/function/functionMetadata-asGenerated.txt b/src/resources/main/org/apache/poi/hssf/record/formula/function/functionMetadata-asGenerated.txt
index 475131e1c0..8a85f42841 100644
--- a/src/resources/main/org/apache/poi/hssf/record/formula/function/functionMetadata-asGenerated.txt
+++ b/src/resources/main/org/apache/poi/hssf/record/formula/function/functionMetadata-asGenerated.txt
@@ -14,7 +14,7 @@
# limitations under the License.
# Created by (org.apache.poi.hssf.record.formula.function.ExcelFileFormatDocFunctionExtractor)
-# from source file 'excelfileformat.odt' (size=355750, crc=0x2FAEA65A)
+# from source file 'excelfileformat.odt' (size=356107, md5=0x8f789cb6e75594caf068f8e193004ef4)
#
#Columns: (index, name, minParams, maxParams, returnClass, paramClasses, isVolatile, hasFootnote )
@@ -37,7 +37,7 @@
15 SIN 1 1 V V
16 COS 1 1 V V
17 TAN 1 1 V V
-18 ARCTAN 1 1 V V
+18 ATAN 1 1 V V
19 PI 0 0 V -
20 SQRT 1 1 V V
21 EXP 1 1 V V
@@ -141,8 +141,8 @@
169 COUNTA 0 30 V R
183 PRODUCT 0 30 V R
184 FACT 1 1 V V
-191 DPRODUCT 3 3 V R R R
-192 ISNONTEXT 1 1 V V
+189 DPRODUCT 3 3 V R R R
+190 ISNONTEXT 1 1 V V
193 STDEVP 1 30 V R
194 VARP 1 30 V R
195 DSTDEVP 3 3 V R R R
@@ -184,6 +184,8 @@
244 INFO 1 1 V V
# New Built-In Sheet Functions in BIFF4
14 FIXED 2 3 V V V V x
+204 USDOLLAR 1 2 V V V x
+215 DBCS 1 1 V V x
216 RANK 2 3 V V R V
247 DB 4 5 V V V V V V
252 FREQUENCY 2 2 A R R
diff --git a/src/resources/main/org/apache/poi/hssf/record/formula/function/functionMetadata.txt b/src/resources/main/org/apache/poi/hssf/record/formula/function/functionMetadata.txt
index 6902027de9..8a85f42841 100644
--- a/src/resources/main/org/apache/poi/hssf/record/formula/function/functionMetadata.txt
+++ b/src/resources/main/org/apache/poi/hssf/record/formula/function/functionMetadata.txt
@@ -14,11 +14,9 @@
# limitations under the License.
# Created by (org.apache.poi.hssf.record.formula.function.ExcelFileFormatDocFunctionExtractor)
-# from source file 'excelfileformat.odt' (size=355750, crc=0x2FAEA65A)
+# from source file 'excelfileformat.odt' (size=356107, md5=0x8f789cb6e75594caf068f8e193004ef4)
#
#Columns: (index, name, minParams, maxParams, returnClass, paramClasses, isVolatile, hasFootnote )
-#
-# + some manual edits !
# Built-In Sheet Functions in BIFF2
0 COUNT 0 30 V R
@@ -186,7 +184,7 @@
244 INFO 1 1 V V
# New Built-In Sheet Functions in BIFF4
14 FIXED 2 3 V V V V x
-204 USDOLLAR 1 1 V V x
+204 USDOLLAR 1 2 V V V x
215 DBCS 1 1 V V x
216 RANK 2 3 V V R V
247 DB 4 5 V V V V V V
diff --git a/src/scratchpad/src/org/apache/poi/hdgf/HDGFDiagram.java b/src/scratchpad/src/org/apache/poi/hdgf/HDGFDiagram.java
index af66163072..764b8e3f5f 100644
--- a/src/scratchpad/src/org/apache/poi/hdgf/HDGFDiagram.java
+++ b/src/scratchpad/src/org/apache/poi/hdgf/HDGFDiagram.java
@@ -18,6 +18,7 @@ package org.apache.poi.hdgf;
import java.io.FileInputStream;
import java.io.IOException;
+import java.io.OutputStream;
import org.apache.poi.POIDocument;
import org.apache.poi.hdgf.chunks.ChunkFactory;
@@ -27,6 +28,7 @@ import org.apache.poi.hdgf.streams.PointerContainingStream;
import org.apache.poi.hdgf.streams.Stream;
import org.apache.poi.hdgf.streams.StringsStream;
import org.apache.poi.hdgf.streams.TrailerStream;
+import org.apache.poi.poifs.filesystem.DirectoryNode;
import org.apache.poi.poifs.filesystem.DocumentEntry;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.util.LittleEndian;
@@ -53,14 +55,17 @@ public class HDGFDiagram extends POIDocument {
private PointerFactory ptrFactory;
public HDGFDiagram(POIFSFileSystem fs) throws IOException {
- super(fs);
+ this(fs.getRoot(), fs);
+ }
+ public HDGFDiagram(DirectoryNode dir, POIFSFileSystem fs) throws IOException {
+ super(dir, fs);
DocumentEntry docProps =
- (DocumentEntry)filesystem.getRoot().getEntry("VisioDocument");
+ (DocumentEntry)dir.getEntry("VisioDocument");
// Grab the document stream
_docstream = new byte[docProps.getSize()];
- filesystem.createDocumentInputStream("VisioDocument").read(_docstream);
+ dir.createDocumentInputStream("VisioDocument").read(_docstream);
// Read in the common POI streams
readProperties();
@@ -149,6 +154,10 @@ public class HDGFDiagram extends POIDocument {
}
}
+ public void write(OutputStream out) {
+ throw new IllegalStateException("Writing is not yet implemented, see http://poi.apache.org/hdgf/");
+ }
+
/**
* For testing only
*/
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/FSPATable.java b/src/scratchpad/src/org/apache/poi/hwpf/model/FSPATable.java
index 58c69ff4b9..812ab1a4a7 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/model/FSPATable.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/model/FSPATable.java
@@ -21,17 +21,18 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
+import java.util.Map;
/**
* This class holds all the FSPA (File Shape Address) structures.
*
* @author Squeeself
*/
-public class FSPATable
+public final class FSPATable
{
- protected ArrayList shapes = new ArrayList();
- protected HashMap cps = new HashMap();
- protected List _text;
+ private final List _shapes = new ArrayList();
+ private final Map _shapeIndexesByPropertyStart = new HashMap();
+ private final List _text;
public FSPATable(byte[] tableStream, int fcPlcspa, int lcbPlcspa, List tpt)
{
@@ -46,32 +47,35 @@ public class FSPATable
GenericPropertyNode property = plex.getProperty(i);
FSPA fspa = new FSPA(property.getBytes(), 0);
- shapes.add(fspa);
- cps.put(Integer.valueOf(property.getStart()), Integer.valueOf(i));
+ _shapes.add(fspa);
+ _shapeIndexesByPropertyStart.put(new Integer(property.getStart()), new Integer(i));
}
}
public FSPA getFspaFromCp(int cp)
{
- Integer idx = (Integer)cps.get(Integer.valueOf(cp));
- if (idx == null)
+ Integer idx = (Integer)_shapeIndexesByPropertyStart.get(new Integer(cp));
+ if (idx == null) {
return null;
- return (FSPA)shapes.get(idx.intValue());
+ }
+ return (FSPA)_shapes.get(idx.intValue());
}
- public List getShapes()
+ public FSPA[] getShapes()
{
- return shapes;
+ FSPA[] result = new FSPA[_shapes.size()];
+ _shapes.toArray(result);
+ return result;
}
public String toString()
{
StringBuffer buf = new StringBuffer();
- buf.append("[FPSA PLC size=").append(shapes.size()).append("]\n");
- for (Iterator it = cps.keySet().iterator(); it.hasNext(); )
+ buf.append("[FPSA PLC size=").append(_shapes.size()).append("]\n");
+ for (Iterator it = _shapeIndexesByPropertyStart.keySet().iterator(); it.hasNext(); )
{
Integer i = (Integer) it.next();
- FSPA fspa = (FSPA) shapes.get(((Integer)cps.get(i)).intValue());
+ FSPA fspa = (FSPA) _shapes.get(((Integer)_shapeIndexesByPropertyStart.get(i)).intValue());
buf.append(" [FC: ").append(i.toString()).append("] ");
buf.append(fspa.toString());
buf.append("\n");
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/FileInformationBlock.java b/src/scratchpad/src/org/apache/poi/hwpf/model/FileInformationBlock.java
index 48e6d78b3a..887e13d829 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/model/FileInformationBlock.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/model/FileInformationBlock.java
@@ -294,6 +294,16 @@ public class FileInformationBlock extends FIBAbstractType
_longHandler.setLong(FIBLongHandler.CBMAC, cbMac);
}
+ public int getCcpText()
+ {
+ return _longHandler.getLong(FIBLongHandler.CCPTEXT);
+ }
+
+ public void setCcpText(int ccpText)
+ {
+ _longHandler.setLong(FIBLongHandler.CCPTEXT, ccpText);
+ }
+
public void clearOffsetsSizes()
{
_fieldHandler.clearFields();
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 67c634d9f6..bc33954dff 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/model/TextPiece.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/model/TextPiece.java
@@ -90,12 +90,20 @@ public class TextPiece extends PropertyNode implements Comparable
public void adjustForDelete(int start, int length)
{
+
+ if (usesUnicode()) {
+
+ start /= 2;
+ length /= 2;
+ }
+
int myStart = getStart();
int myEnd = getEnd();
int end = start + length;
/* do we have to delete from this text piece? */
if (start <= myEnd && end >= myStart) {
+
/* find where the deleted area overlaps with this text piece */
int overlapStart = Math.max(myStart, start);
int overlapEnd = Math.min(myEnd, end);
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 f2d9a615f8..85592a92a2 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Range.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Range.java
@@ -227,6 +227,25 @@ public class Range
}
/**
+ * Does any <code>TextPiece</code> in this Range use unicode?
+ *
+ * @return true if it does and false if it doesn't
+ */
+ public boolean usesUnicode() {
+
+ initText();
+
+ for (int i = _textStart; i < _textEnd; i++)
+ {
+ TextPiece piece = (TextPiece)_text.get(i);
+ if (piece.usesUnicode())
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
* Gets the text that this Range contains.
*
* @return The text for this range.
@@ -306,13 +325,19 @@ public class Range
// Since this is the first item in our list, it is safe to assume that
// _start >= tp.getStart()
int insertIndex = _start - tp.getStart();
+ if (tp.usesUnicode())
+ insertIndex /= 2;
sb.insert(insertIndex, text);
+
int adjustedLength = _doc.getTextTable().adjustForInsert(_textStart, text.length());
_doc.getCharacterTable().adjustForInsert(_charStart, adjustedLength);
_doc.getParagraphTable().adjustForInsert(_parStart, adjustedLength);
_doc.getSectionTable().adjustForInsert(_sectionStart, adjustedLength);
adjustForInsert(text.length());
+ // update the FIB.CCPText field
+ adjustFIB(text.length());
+
return getCharacterRun(0);
}
@@ -489,6 +514,7 @@ public class Range
public void delete()
{
+
initAll();
int numSections = _sections.size();
@@ -519,6 +545,12 @@ public class Range
TextPiece piece = (TextPiece)_text.get(x);
piece.adjustForDelete(_start, _end - _start);
}
+
+ // update the FIB.CCPText field
+ if (usesUnicode())
+ adjustFIB(-((_end - _start) / 2));
+ else
+ adjustFIB(-(_end - _start));
}
/**
@@ -828,12 +860,26 @@ public class Range
}
/**
+ * Adjust the value of <code>FIB.CCPText</code> after an insert or a delete...
+ *
+ * @param adjustment The (signed) value that should be added to <code>FIB.CCPText</code>
+ */
+ protected void adjustFIB(int adjustment) {
+
+ // update the FIB.CCPText field (this should happen once per adjustment, so we don't want it in
+ // adjustForInsert() or it would get updated multiple times if the range has a parent)
+ // without this, OpenOffice.org (v. 2.2.x) does not see all the text in the document
+ _doc.getFileInformationBlock().setCcpText(_doc.getFileInformationBlock().getCcpText() + adjustment);
+ }
+
+ /**
* adjust this range after an insert happens.
* @param length the length to adjust for
*/
private void adjustForInsert(int length)
{
_end += length;
+
reset();
Range parent = (Range)_parent.get();
if (parent != null)
@@ -842,4 +888,14 @@ public class Range
}
}
+
+ public int getStartOffset() {
+
+ return _start;
+ }
+
+ public int getEndOffset() {
+
+ return _end;
+ }
}
diff --git a/src/testcases/org/apache/poi/hssf/data/ex45046-21984.xls b/src/testcases/org/apache/poi/hssf/data/ex45046-21984.xls
new file mode 100644
index 0000000000..96ef3ee7ca
--- /dev/null
+++ b/src/testcases/org/apache/poi/hssf/data/ex45046-21984.xls
Binary files differ
diff --git a/src/testcases/org/apache/poi/hssf/model/TestFormulaParser.java b/src/testcases/org/apache/poi/hssf/model/TestFormulaParser.java
index 1895705a56..f2821140f3 100644
--- a/src/testcases/org/apache/poi/hssf/model/TestFormulaParser.java
+++ b/src/testcases/org/apache/poi/hssf/model/TestFormulaParser.java
@@ -55,120 +55,99 @@ import org.apache.poi.hssf.usermodel.HSSFWorkbook;
/**
* Test the low level formula parser functionality. High level tests are to
- * be done via usermodel/HSSFCell.setFormulaValue() .
- * Some tests are also done in scratchpad, if they need
- * HSSFFormulaEvaluator, which is there
+ * be done via usermodel/HSSFCell.setFormulaValue().
*/
public final class TestFormulaParser extends TestCase {
- /**
- * @return parsed token array already confirmed not <code>null</code>
- */
- private static Ptg[] parseFormula(String s) {
- // TODO - replace multiple copies of this code with calls to this method
- FormulaParser fp = new FormulaParser(s, null);
- fp.parse();
- Ptg[] result = fp.getRPNPtg();
- assertNotNull("Ptg array should not be null", result);
- return result;
- }
-
- public void testSimpleFormula() {
- FormulaParser fp = new FormulaParser("2+2",null);
- fp.parse();
- Ptg[] ptgs = fp.getRPNPtg();
- assertTrue("three tokens expected, got "+ptgs.length,ptgs.length == 3);
- }
- public void testFormulaWithSpace1() {
- FormulaParser fp = new FormulaParser(" 2 + 2 ",null);
- fp.parse();
- Ptg[] ptgs = fp.getRPNPtg();
- assertTrue("three tokens expected, got "+ptgs.length,ptgs.length == 3);
- assertTrue("",(ptgs[0] instanceof IntPtg));
- assertTrue("",(ptgs[1] instanceof IntPtg));
- assertTrue("",(ptgs[2] instanceof AddPtg));
- }
-
- public void testFormulaWithSpace2() {
- Ptg[] ptgs;
- FormulaParser fp;
- fp = new FormulaParser("2+ sum( 3 , 4) ",null);
- fp.parse();
- ptgs = fp.getRPNPtg();
- assertTrue("five tokens expected, got "+ptgs.length,ptgs.length == 5);
- }
-
- public void testFormulaWithSpaceNRef() {
- Ptg[] ptgs;
- FormulaParser fp;
- fp = new FormulaParser("sum( A2:A3 )",null);
- fp.parse();
- ptgs = fp.getRPNPtg();
- assertTrue("two tokens expected, got "+ptgs.length,ptgs.length == 2);
- }
-
- public void testFormulaWithString() {
- Ptg[] ptgs;
- FormulaParser fp;
- fp = new FormulaParser("\"hello\" & \"world\" ",null);
- fp.parse();
- ptgs = fp.getRPNPtg();
- assertTrue("three token expected, got " + ptgs.length, ptgs.length == 3);
- }
-
- public void testTRUE() throws Exception {
- FormulaParser fp = new FormulaParser("TRUE", null);
- fp.parse();
- Ptg[] asts = fp.getRPNPtg();
- assertEquals(1, asts.length);
- BoolPtg flag = (BoolPtg) asts[0];
- assertEquals(true, flag.getValue());
- }
-
- public void testYN() throws Exception {
- final String yn = "IF(TRUE,\"Y\",\"N\")";
- FormulaParser fp = new FormulaParser(yn, null);
- fp.parse();
- Ptg[] asts = fp.getRPNPtg();
- assertEquals(7, asts.length);
-
- BoolPtg flag = (BoolPtg) asts[0];
- AttrPtg funif = (AttrPtg) asts[1];
- StringPtg y = (StringPtg) asts[2];
- AttrPtg goto1 = (AttrPtg) asts[3];
- StringPtg n = (StringPtg) asts[4];
-
-
- assertEquals(true, flag.getValue());
- assertEquals("Y", y.getValue());
- assertEquals("N", n.getValue());
- assertEquals("IF", funif.toFormulaString((HSSFWorkbook) null));
- assertTrue("Goto ptg exists", goto1.isGoto());
- }
-
- public void testSimpleIf() throws Exception {
- final String simpleif = "IF(1=1,0,1)";
- FormulaParser fp = new FormulaParser(simpleif, null);
+ /**
+ * @return parsed token array already confirmed not <code>null</code>
+ */
+ private static Ptg[] parseFormula(String s) {
+ FormulaParser fp = new FormulaParser(s, null);
fp.parse();
- Ptg[] asts = fp.getRPNPtg();
- assertEquals(9, asts.length);
-
- IntPtg op1 = (IntPtg) asts[0];
- IntPtg op2 = (IntPtg) asts[1];
- EqualPtg eq = (EqualPtg) asts[2];
- AttrPtg ifPtg = (AttrPtg) asts[3];
- IntPtg res1 = (IntPtg) asts[4];
-
- AttrPtg ptgGoto= (AttrPtg) asts[5];
- assertEquals("Goto 1 Length", (short)10, ptgGoto.getData());
-
- IntPtg res2 = (IntPtg) asts[6];
- AttrPtg ptgGoto2 = (AttrPtg) asts[7];
- assertEquals("Goto 2 Length", (short)3, ptgGoto2.getData());
-
- assertEquals("If FALSE offset", (short)7, ifPtg.getData());
+ Ptg[] result = fp.getRPNPtg();
+ assertNotNull("Ptg array should not be null", result);
+ return result;
+ }
+
+ public void testSimpleFormula() {
+ Ptg[] ptgs = parseFormula("2+2");
+ assertEquals(3, ptgs.length);
+ }
+
+ public void testFormulaWithSpace1() {
+ Ptg[] ptgs = parseFormula(" 2 + 2 ");
+ assertEquals(3, ptgs.length);
+ assertTrue("",(ptgs[0] instanceof IntPtg));
+ assertTrue("",(ptgs[1] instanceof IntPtg));
+ assertTrue("",(ptgs[2] instanceof AddPtg));
+ }
+
+ public void testFormulaWithSpace2() {
+ Ptg[] ptgs = parseFormula("2+ sum( 3 , 4) ");
+ assertEquals(5, ptgs.length);
+ }
+
+ public void testFormulaWithSpaceNRef() {
+ Ptg[] ptgs = parseFormula("sum( A2:A3 )");
+ assertEquals(2, ptgs.length);
+ }
+
+ public void testFormulaWithString() {
+ Ptg[] ptgs = parseFormula("\"hello\" & \"world\" ");
+ assertEquals(3, ptgs.length);
+ }
+
+ public void testTRUE() {
+ Ptg[] ptgs = parseFormula("TRUE");
+ assertEquals(1, ptgs.length);
+ BoolPtg flag = (BoolPtg) ptgs[0];
+ assertEquals(true, flag.getValue());
+ }
+
+ public void testYN() {
+ Ptg[] ptgs = parseFormula("IF(TRUE,\"Y\",\"N\")");
+ assertEquals(7, ptgs.length);
+
+ BoolPtg flag = (BoolPtg) ptgs[0];
+ AttrPtg funif = (AttrPtg) ptgs[1];
+ StringPtg y = (StringPtg) ptgs[2];
+ AttrPtg goto1 = (AttrPtg) ptgs[3];
+ StringPtg n = (StringPtg) ptgs[4];
+
+
+ assertEquals(true, flag.getValue());
+ assertEquals("Y", y.getValue());
+ assertEquals("N", n.getValue());
+ assertEquals("IF", funif.toFormulaString((HSSFWorkbook) null));
+ assertTrue("Goto ptg exists", goto1.isGoto());
+ }
+
+ public void testSimpleIf() {
+ String formula = "IF(1=1,0,1)";
+
+ Class[] expectedClasses = {
+ IntPtg.class,
+ IntPtg.class,
+ EqualPtg.class,
+ AttrPtg.class,
+ IntPtg.class,
+ AttrPtg.class,
+ IntPtg.class,
+ AttrPtg.class,
+ FuncVarPtg.class,
+ };
+ confirmTokenClasses(formula, expectedClasses);
- FuncVarPtg funcPtg = (FuncVarPtg)asts[8];
+ Ptg[] ptgs = parseFormula(formula);
+
+ AttrPtg ifPtg = (AttrPtg) ptgs[3];
+ AttrPtg ptgGoto= (AttrPtg) ptgs[5];
+ assertEquals("Goto 1 Length", 10, ptgGoto.getData());
+
+ AttrPtg ptgGoto2 = (AttrPtg) ptgs[7];
+ assertEquals("Goto 2 Length", 3, ptgGoto2.getData());
+ assertEquals("If FALSE offset", 7, ifPtg.getData());
}
/**
@@ -176,753 +155,714 @@ public final class TestFormulaParser extends TestCase {
*
*/
public void testNestedFunctionIf() {
- String function = "IF(A1=B1,AVERAGE(A1:B1),AVERAGE(A2:B2))";
+ Ptg[] ptgs = parseFormula("IF(A1=B1,AVERAGE(A1:B1),AVERAGE(A2:B2))");
+ assertEquals(11, ptgs.length);
- FormulaParser fp = new FormulaParser(function, null);
- fp.parse();
- Ptg[] asts = fp.getRPNPtg();
- assertEquals("11 Ptgs expected", 11, asts.length);
-
- assertTrue("IF Attr set correctly", (asts[3] instanceof AttrPtg));
- AttrPtg ifFunc = (AttrPtg)asts[3];
+ assertTrue("IF Attr set correctly", (ptgs[3] instanceof AttrPtg));
+ AttrPtg ifFunc = (AttrPtg)ptgs[3];
assertTrue("It is not an if", ifFunc.isOptimizedIf());
-
- assertTrue("Average Function set correctly", (asts[5] instanceof FuncVarPtg));
+
+ assertTrue("Average Function set correctly", (ptgs[5] instanceof FuncVarPtg));
}
-
- public void testIfSingleCondition(){
- String function = "IF(1=1,10)";
- FormulaParser fp = new FormulaParser(function, null);
- fp.parse();
- Ptg[] asts = fp.getRPNPtg();
- assertEquals("7 Ptgs expected", 7, asts.length);
+ public void testIfSingleCondition(){
+ Ptg[] ptgs = parseFormula("IF(1=1,10)");
+ assertEquals(7, ptgs.length);
- assertTrue("IF Attr set correctly", (asts[3] instanceof AttrPtg));
- AttrPtg ifFunc = (AttrPtg)asts[3];
+ assertTrue("IF Attr set correctly", (ptgs[3] instanceof AttrPtg));
+ AttrPtg ifFunc = (AttrPtg)ptgs[3];
assertTrue("It is not an if", ifFunc.isOptimizedIf());
-
- assertTrue("Single Value is not an IntPtg", (asts[4] instanceof IntPtg));
- IntPtg intPtg = (IntPtg)asts[4];
+
+ assertTrue("Single Value is not an IntPtg", (ptgs[4] instanceof IntPtg));
+ IntPtg intPtg = (IntPtg)ptgs[4];
assertEquals("Result", (short)10, intPtg.getValue());
-
- assertTrue("Ptg is not a Variable Function", (asts[6] instanceof FuncVarPtg));
- FuncVarPtg funcPtg = (FuncVarPtg)asts[6];
+
+ assertTrue("Ptg is not a Variable Function", (ptgs[6] instanceof FuncVarPtg));
+ FuncVarPtg funcPtg = (FuncVarPtg)ptgs[6];
assertEquals("Arguments", 2, funcPtg.getNumberOfOperands());
}
public void testSumIf() {
- String function ="SUMIF(A1:A5,\">4000\",B1:B5)";
- FormulaParser fp = new FormulaParser(function, null);
- fp.parse();
- Ptg[] asts = fp.getRPNPtg();
- assertEquals("4 Ptgs expected", 4, asts.length);
+ Ptg[] ptgs = parseFormula("SUMIF(A1:A5,\">4000\",B1:B5)");
+ assertEquals(4, ptgs.length);
}
-
+
/**
* Bug Reported by xt-jens.riis@nokia.com (Jens Riis)
* Refers to Bug <a href="http://issues.apache.org/bugzilla/show_bug.cgi?id=17582">#17582</a>
*
*/
- public void testNonAlphaFormula(){
+ public void testNonAlphaFormula() {
String currencyCell = "F3";
- String function="\"TOTAL[\"&"+currencyCell+"&\"]\"";
+ Ptg[] ptgs = parseFormula("\"TOTAL[\"&"+currencyCell+"&\"]\"");
+ assertEquals(5, ptgs.length);
+ assertTrue ("Ptg[0] is a string", (ptgs[0] instanceof StringPtg));
+ StringPtg firstString = (StringPtg)ptgs[0];
- Ptg[] asts = parseFormula(function);
- assertEquals("5 ptgs expected", 5, asts.length);
- assertTrue ("Ptg[0] is a string", (asts[0] instanceof StringPtg));
- StringPtg firstString = (StringPtg)asts[0];
-
assertEquals("TOTAL[", firstString.getValue());
//the PTG order isn't 100% correct but it still works - dmui
}
public void testSimpleLogical() {
- Ptg[] ptgs = parseFormula("IF(A1<A2,B1,B2)");
- assertEquals("Ptg array length", 9, ptgs.length);
- assertEquals("3rd Ptg is less than", LessThanPtg.class, ptgs[2].getClass());
+ Ptg[] ptgs = parseFormula("IF(A1<A2,B1,B2)");
+ assertEquals(9, ptgs.length);
+ assertEquals("3rd Ptg is less than", LessThanPtg.class, ptgs[2].getClass());
}
-
+
public void testParenIf() {
Ptg[] ptgs = parseFormula("IF((A1+A2)<=3,\"yes\",\"no\")");
- assertEquals("Ptg array length", 12, ptgs.length);
+ assertEquals(12, ptgs.length);
assertEquals("6th Ptg is less than equal",LessEqualPtg.class,ptgs[5].getClass());
assertEquals("11th Ptg is not a goto (Attr) ptg",AttrPtg.class,ptgs[10].getClass());
}
-
+
public void testEmbeddedIf() {
Ptg[] ptgs = parseFormula("IF(3>=1,\"*\",IF(4<>1,\"first\",\"second\"))");
- assertEquals("Ptg array length", 17, ptgs.length);
-
+ assertEquals(17, ptgs.length);
+
assertEquals("6th Ptg is not a goto (Attr) ptg",AttrPtg.class,ptgs[5].getClass());
assertEquals("9th Ptg is not a not equal ptg",NotEqualPtg.class,ptgs[8].getClass());
assertEquals("15th Ptg is not the inner IF variable function ptg",FuncVarPtg.class,ptgs[14].getClass());
}
-
- public void testMacroFunction() {
- HSSFWorkbook w = new HSSFWorkbook();
- FormulaParser fp = new FormulaParser("FOO()", w);
- fp.parse();
- Ptg[] ptg = fp.getRPNPtg();
-
- // the name gets encoded as the first arg
- NamePtg tname = (NamePtg) ptg[0];
- assertEquals("FOO", tname.toFormulaString(w));
-
- AbstractFunctionPtg tfunc = (AbstractFunctionPtg) ptg[1];
- assertTrue(tfunc.isExternalFunction());
- }
-
- public void testEmbeddedSlash() {
- FormulaParser fp = new FormulaParser("HYPERLINK(\"http://www.jakarta.org\",\"Jakarta\")",null);
- fp.parse();
- Ptg[] ptg = fp.getRPNPtg();
- assertTrue("first ptg is string",ptg[0] instanceof StringPtg);
- assertTrue("second ptg is string",ptg[1] instanceof StringPtg);
- }
-
- public void testConcatenate() {
- FormulaParser fp = new FormulaParser("CONCATENATE(\"first\",\"second\")", null);
- fp.parse();
- Ptg[] ptg = fp.getRPNPtg();
- assertTrue("first ptg is string", ptg[0] instanceof StringPtg);
- assertTrue("second ptg is string", ptg[1] instanceof StringPtg);
- }
-
- public void testWorksheetReferences()
- {
- HSSFWorkbook wb = new HSSFWorkbook();
-
- wb.createSheet("NoQuotesNeeded");
- wb.createSheet("Quotes Needed Here &#$@");
-
- HSSFSheet sheet = wb.createSheet("Test");
- HSSFRow row = sheet.createRow(0);
- HSSFCell cell;
-
- cell = row.createCell((short)0);
- cell.setCellFormula("NoQuotesNeeded!A1");
-
- cell = row.createCell((short)1);
- cell.setCellFormula("'Quotes Needed Here &#$@'!A1");
- }
-
- public void testUnaryMinus()
- {
- FormulaParser fp = new FormulaParser("-A1", null);
- fp.parse();
- Ptg[] ptg = fp.getRPNPtg();
- assertTrue("got 2 ptgs", ptg.length == 2);
- assertTrue("first ptg is reference",ptg[0] instanceof ReferencePtg);
- assertTrue("second ptg is Minus",ptg[1] instanceof UnaryMinusPtg);
- }
-
- public void testUnaryPlus()
- {
- FormulaParser fp = new FormulaParser("+A1", null);
+
+ public void testMacroFunction() {
+ HSSFWorkbook w = new HSSFWorkbook();
+ FormulaParser fp = new FormulaParser("FOO()", w);
fp.parse();
Ptg[] ptg = fp.getRPNPtg();
- assertTrue("got 2 ptgs", ptg.length == 2);
- assertTrue("first ptg is reference",ptg[0] instanceof ReferencePtg);
- assertTrue("second ptg is Plus",ptg[1] instanceof UnaryPlusPtg);
- }
- public void testLeadingSpaceInString()
- {
+ // the name gets encoded as the first arg
+ NamePtg tname = (NamePtg) ptg[0];
+ assertEquals("FOO", tname.toFormulaString(w));
+
+ AbstractFunctionPtg tfunc = (AbstractFunctionPtg) ptg[1];
+ assertTrue(tfunc.isExternalFunction());
+ }
+
+ public void testEmbeddedSlash() {
+ Ptg[] ptgs = parseFormula("HYPERLINK(\"http://www.jakarta.org\",\"Jakarta\")");
+ assertTrue("first ptg is string", ptgs[0] instanceof StringPtg);
+ assertTrue("second ptg is string", ptgs[1] instanceof StringPtg);
+ }
+
+ public void testConcatenate() {
+ Ptg[] ptgs = parseFormula("CONCATENATE(\"first\",\"second\")");
+ assertTrue("first ptg is string", ptgs[0] instanceof StringPtg);
+ assertTrue("second ptg is string", ptgs[1] instanceof StringPtg);
+ }
+
+ public void testWorksheetReferences() {
+ HSSFWorkbook wb = new HSSFWorkbook();
+
+ wb.createSheet("NoQuotesNeeded");
+ wb.createSheet("Quotes Needed Here &#$@");
+
+ HSSFSheet sheet = wb.createSheet("Test");
+ HSSFRow row = sheet.createRow(0);
+ HSSFCell cell;
+
+ cell = row.createCell((short)0);
+ cell.setCellFormula("NoQuotesNeeded!A1");
+
+ cell = row.createCell((short)1);
+ cell.setCellFormula("'Quotes Needed Here &#$@'!A1");
+ }
+
+ public void testUnaryMinus() {
+ Ptg[] ptgs = parseFormula("-A1");
+ assertEquals(2, ptgs.length);
+ assertTrue("first ptg is reference",ptgs[0] instanceof ReferencePtg);
+ assertTrue("second ptg is Minus",ptgs[1] instanceof UnaryMinusPtg);
+ }
+
+ public void testUnaryPlus() {
+ Ptg[] ptgs = parseFormula("+A1");
+ assertEquals(2, ptgs.length);
+ assertTrue("first ptg is reference",ptgs[0] instanceof ReferencePtg);
+ assertTrue("second ptg is Plus",ptgs[1] instanceof UnaryPlusPtg);
+ }
+
+ public void testLeadingSpaceInString() {
String value = " hi ";
- FormulaParser fp = new FormulaParser("\"" + value + "\"", null);
- fp.parse();
- Ptg[] ptg = fp.getRPNPtg();
+ Ptg[] ptgs = parseFormula("\"" + value + "\"");
- assertTrue("got 1 ptg", ptg.length == 1);
- assertTrue("ptg0 is a StringPtg", ptg[0] instanceof StringPtg);
- assertTrue("ptg0 contains exact value", ((StringPtg)ptg[0]).getValue().equals(value));
+ assertEquals(1, ptgs.length);
+ assertTrue("ptg0 is a StringPtg", ptgs[0] instanceof StringPtg);
+ assertTrue("ptg0 contains exact value", ((StringPtg)ptgs[0]).getValue().equals(value));
}
-
- public void testLookupAndMatchFunctionArgs()
- {
- FormulaParser fp = new FormulaParser("lookup(A1, A3:A52, B3:B52)", null);
- fp.parse();
- Ptg[] ptg = fp.getRPNPtg();
- assertTrue("got 4 ptg", ptg.length == 4);
- assertTrue("ptg0 has Value class", ptg[0].getPtgClass() == Ptg.CLASS_VALUE);
-
- fp = new FormulaParser("match(A1, A3:A52)", null);
- fp.parse();
- ptg = fp.getRPNPtg();
+ public void testLookupAndMatchFunctionArgs() {
+ Ptg[] ptgs = parseFormula("lookup(A1, A3:A52, B3:B52)");
+
+ assertEquals(4, ptgs.length);
+ assertTrue("ptg0 has Value class", ptgs[0].getPtgClass() == Ptg.CLASS_VALUE);
- assertTrue("got 3 ptg", ptg.length == 3);
- assertTrue("ptg0 has Value class", ptg[0].getPtgClass() == Ptg.CLASS_VALUE);
+ ptgs = parseFormula("match(A1, A3:A52)");
+
+ assertEquals(3, ptgs.length);
+ assertTrue("ptg0 has Value class", ptgs[0].getPtgClass() == Ptg.CLASS_VALUE);
}
-
+
/** bug 33160*/
public void testLargeInt() {
- FormulaParser fp = new FormulaParser("40", null);
- fp.parse();
- Ptg[] ptg=fp.getRPNPtg();
- assertTrue("ptg is Int, is "+ptg[0].getClass(),ptg[0] instanceof IntPtg);
-
- fp = new FormulaParser("40000", null);
- fp.parse();
- ptg=fp.getRPNPtg();
- assertTrue("ptg should be IntPtg, is "+ptg[0].getClass(), ptg[0] instanceof IntPtg);
+ Ptg[] ptgs = parseFormula("40");
+ assertTrue("ptg is Int, is "+ptgs[0].getClass(),ptgs[0] instanceof IntPtg);
+
+ ptgs = parseFormula("40000");
+ assertTrue("ptg should be IntPtg, is "+ptgs[0].getClass(), ptgs[0] instanceof IntPtg);
}
/** bug 33160, testcase by Amol Deshmukh*/
public void testSimpleLongFormula() {
- FormulaParser fp = new FormulaParser("40000/2", null);
- fp.parse();
- Ptg[] ptgs = fp.getRPNPtg();
- assertTrue("three tokens expected, got " + ptgs.length, ptgs.length == 3);
+ Ptg[] ptgs = parseFormula("40000/2");
+ assertEquals(3, ptgs.length);
assertTrue("IntPtg", (ptgs[0] instanceof IntPtg));
assertTrue("IntPtg", (ptgs[1] instanceof IntPtg));
assertTrue("DividePtg", (ptgs[2] instanceof DividePtg));
}
-
+
/** bug 35027, underscore in sheet name */
public void testUnderscore() {
HSSFWorkbook wb = new HSSFWorkbook();
-
- wb.createSheet("Cash_Flow");
-
- HSSFSheet sheet = wb.createSheet("Test");
- HSSFRow row = sheet.createRow(0);
- HSSFCell cell;
-
- cell = row.createCell((short)0);
- cell.setCellFormula("Cash_Flow!A1");
-
+
+ wb.createSheet("Cash_Flow");
+
+ HSSFSheet sheet = wb.createSheet("Test");
+ HSSFRow row = sheet.createRow(0);
+ HSSFCell cell;
+
+ cell = row.createCell((short)0);
+ cell.setCellFormula("Cash_Flow!A1");
+ }
+
+ // bug 38396 : Formula with exponential numbers not parsed correctly.
+ public void testExponentialParsing() {
+ Ptg[] ptgs;
+ ptgs = parseFormula("1.3E21/2");
+ assertEquals(3, ptgs.length);
+ assertTrue("NumberPtg", (ptgs[0] instanceof NumberPtg));
+ assertTrue("IntPtg", (ptgs[1] instanceof IntPtg));
+ assertTrue("DividePtg", (ptgs[2] instanceof DividePtg));
+
+ ptgs = parseFormula("1322E21/2");
+ assertEquals(3, ptgs.length);
+ assertTrue("NumberPtg", (ptgs[0] instanceof NumberPtg));
+ assertTrue("IntPtg", (ptgs[1] instanceof IntPtg));
+ assertTrue("DividePtg", (ptgs[2] instanceof DividePtg));
+
+ ptgs = parseFormula("1.3E1/2");
+ assertEquals(3, ptgs.length);
+ assertTrue("NumberPtg", (ptgs[0] instanceof NumberPtg));
+ assertTrue("IntPtg", (ptgs[1] instanceof IntPtg));
+ assertTrue("DividePtg", (ptgs[2] instanceof DividePtg));
}
- // bug 38396 : Formula with exponential numbers not parsed correctly.
- public void testExponentialParsing() {
- FormulaParser fp = new FormulaParser("1.3E21/2", null);
- fp.parse();
- Ptg[] ptgs = fp.getRPNPtg();
- assertTrue("three tokens expected, got " + ptgs.length, ptgs.length == 3);
- assertTrue("NumberPtg", (ptgs[0] instanceof NumberPtg));
- assertTrue("IntPtg", (ptgs[1] instanceof IntPtg));
- assertTrue("DividePtg", (ptgs[2] instanceof DividePtg));
-
- fp = new FormulaParser("1322E21/2", null);
- fp.parse();
- ptgs = fp.getRPNPtg();
- assertTrue("three tokens expected, got " + ptgs.length, ptgs.length == 3);
- assertTrue("NumberPtg", (ptgs[0] instanceof NumberPtg));
- assertTrue("IntPtg", (ptgs[1] instanceof IntPtg));
- assertTrue("DividePtg", (ptgs[2] instanceof DividePtg));
-
- fp = new FormulaParser("1.3E1/2", null);
- fp.parse();
- ptgs = fp.getRPNPtg();
- assertTrue("three tokens expected, got " + ptgs.length, ptgs.length == 3);
- assertTrue("NumberPtg", (ptgs[0] instanceof NumberPtg));
- assertTrue("IntPtg", (ptgs[1] instanceof IntPtg));
- assertTrue("DividePtg", (ptgs[2] instanceof DividePtg));
-
- }
- public void testExponentialInSheet() throws Exception {
- HSSFWorkbook wb = new HSSFWorkbook();
-
- wb.createSheet("Cash_Flow");
-
- HSSFSheet sheet = wb.createSheet("Test");
- HSSFRow row = sheet.createRow(0);
- HSSFCell cell = row.createCell((short)0);
- String formula = null;
+ public void testExponentialInSheet() {
+ HSSFWorkbook wb = new HSSFWorkbook();
+
+ wb.createSheet("Cash_Flow");
+
+ HSSFSheet sheet = wb.createSheet("Test");
+ HSSFRow row = sheet.createRow(0);
+ HSSFCell cell = row.createCell((short)0);
+ String formula = null;
+
+ cell.setCellFormula("1.3E21/3");
+ formula = cell.getCellFormula();
+ assertEquals("Exponential formula string", "1.3E21/3", formula);
+
+ cell.setCellFormula("-1.3E21/3");
+ formula = cell.getCellFormula();
+ assertEquals("Exponential formula string", "-1.3E21/3", formula);
+
+ cell.setCellFormula("1322E21/3");
+ formula = cell.getCellFormula();
+ assertEquals("Exponential formula string", "1.322E24/3", formula);
+
+ cell.setCellFormula("-1322E21/3");
+ formula = cell.getCellFormula();
+ assertEquals("Exponential formula string", "-1.322E24/3", formula);
+
+ cell.setCellFormula("1.3E1/3");
+ formula = cell.getCellFormula();
+ assertEquals("Exponential formula string", "13.0/3", formula);
+
+ cell.setCellFormula("-1.3E1/3");
+ formula = cell.getCellFormula();
+ assertEquals("Exponential formula string", "-13.0/3", formula);
+
+ cell.setCellFormula("1.3E-4/3");
+ formula = cell.getCellFormula();
+ assertEquals("Exponential formula string", "1.3E-4/3", formula);
- cell.setCellFormula("1.3E21/3");
- formula = cell.getCellFormula();
- assertEquals("Exponential formula string", "1.3E21/3", formula);
-
- cell.setCellFormula("-1.3E21/3");
- formula = cell.getCellFormula();
- assertEquals("Exponential formula string", "-1.3E21/3", formula);
+ cell.setCellFormula("-1.3E-4/3");
+ formula = cell.getCellFormula();
+ assertEquals("Exponential formula string", "-1.3E-4/3", formula);
- cell.setCellFormula("1322E21/3");
- formula = cell.getCellFormula();
- assertEquals("Exponential formula string", "1.322E24/3", formula);
+ cell.setCellFormula("13E-15/3");
+ formula = cell.getCellFormula();
+ assertEquals("Exponential formula string", "1.3E-14/3", formula);
- cell.setCellFormula("-1322E21/3");
- formula = cell.getCellFormula();
- assertEquals("Exponential formula string", "-1.322E24/3", formula);
+ cell.setCellFormula("-13E-15/3");
+ formula = cell.getCellFormula();
+ assertEquals("Exponential formula string", "-1.3E-14/3", formula);
- cell.setCellFormula("1.3E1/3");
- formula = cell.getCellFormula();
- assertEquals("Exponential formula string", "13.0/3", formula);
+ cell.setCellFormula("1.3E3/3");
+ formula = cell.getCellFormula();
+ assertEquals("Exponential formula string", "1300.0/3", formula);
- cell.setCellFormula("-1.3E1/3");
- formula = cell.getCellFormula();
- assertEquals("Exponential formula string", "-13.0/3", formula);
+ cell.setCellFormula("-1.3E3/3");
+ formula = cell.getCellFormula();
+ assertEquals("Exponential formula string", "-1300.0/3", formula);
- cell.setCellFormula("1.3E-4/3");
- formula = cell.getCellFormula();
- assertEquals("Exponential formula string", "1.3E-4/3", formula);
+ cell.setCellFormula("1300000000000000/3");
+ formula = cell.getCellFormula();
+ assertEquals("Exponential formula string", "1.3E15/3", formula);
- cell.setCellFormula("-1.3E-4/3");
- formula = cell.getCellFormula();
- assertEquals("Exponential formula string", "-1.3E-4/3", formula);
-
- cell.setCellFormula("13E-15/3");
- formula = cell.getCellFormula();
- assertEquals("Exponential formula string", "1.3E-14/3", formula);
-
- cell.setCellFormula("-13E-15/3");
- formula = cell.getCellFormula();
- assertEquals("Exponential formula string", "-1.3E-14/3", formula);
-
- cell.setCellFormula("1.3E3/3");
- formula = cell.getCellFormula();
- assertEquals("Exponential formula string", "1300.0/3", formula);
-
- cell.setCellFormula("-1.3E3/3");
- formula = cell.getCellFormula();
- assertEquals("Exponential formula string", "-1300.0/3", formula);
-
- cell.setCellFormula("1300000000000000/3");
- formula = cell.getCellFormula();
- assertEquals("Exponential formula string", "1.3E15/3", formula);
-
- cell.setCellFormula("-1300000000000000/3");
- formula = cell.getCellFormula();
- assertEquals("Exponential formula string", "-1.3E15/3", formula);
-
- cell.setCellFormula("-10E-1/3.1E2*4E3/3E4");
- formula = cell.getCellFormula();
- assertEquals("Exponential formula string", "-1.0/310.0*4000.0/30000.0", formula);
- }
-
- public static void main(String [] args) {
- System.out.println("Testing org.apache.poi.hssf.record.formula.FormulaParser");
- junit.textui.TestRunner.run(TestFormulaParser.class);
- }
-
- public void testNumbers() {
- HSSFWorkbook wb = new HSSFWorkbook();
-
- wb.createSheet("Cash_Flow");
-
- HSSFSheet sheet = wb.createSheet("Test");
- HSSFRow row = sheet.createRow(0);
- HSSFCell cell = row.createCell((short)0);
- String formula = null;
-
- // starts from decimal point
-
- cell.setCellFormula(".1");
- formula = cell.getCellFormula();
- assertEquals("0.1", formula);
-
- cell.setCellFormula("+.1");
- formula = cell.getCellFormula();
- assertEquals("+0.1", formula);
-
- cell.setCellFormula("-.1");
- formula = cell.getCellFormula();
- assertEquals("-0.1", formula);
-
- // has exponent
-
- cell.setCellFormula("10E1");
- formula = cell.getCellFormula();
- assertEquals("100.0", formula);
-
- cell.setCellFormula("10E+1");
- formula = cell.getCellFormula();
- assertEquals("100.0", formula);
-
- cell.setCellFormula("10E-1");
- formula = cell.getCellFormula();
- assertEquals("1.0", formula);
- }
-
- public void testRanges() {
- HSSFWorkbook wb = new HSSFWorkbook();
-
- wb.createSheet("Cash_Flow");
-
- HSSFSheet sheet = wb.createSheet("Test");
- HSSFRow row = sheet.createRow(0);
- HSSFCell cell = row.createCell((short)0);
- String formula = null;
-
- cell.setCellFormula("A1.A2");
- formula = cell.getCellFormula();
- assertEquals("A1:A2", formula);
-
- cell.setCellFormula("A1..A2");
- formula = cell.getCellFormula();
- assertEquals("A1:A2", formula);
-
- cell.setCellFormula("A1...A2");
- formula = cell.getCellFormula();
- assertEquals("A1:A2", formula);
- }
-
- /**
- * Test for bug observable at svn revision 618865 (5-Feb-2008)<br/>
- * a formula consisting of a single no-arg function got rendered without the function braces
- */
- public void testToFormulaStringZeroArgFunction() {
- HSSFWorkbook book = new HSSFWorkbook();
-
- Ptg[] ptgs = {
- new FuncPtg(10),
- };
- assertEquals("NA()", FormulaParser.toFormulaString(book, ptgs));
- }
-
- public void testPercent() {
- Ptg[] ptgs;
- ptgs = parseFormula("5%");
- assertEquals(2, ptgs.length);
- assertEquals(ptgs[0].getClass(), IntPtg.class);
- assertEquals(ptgs[1].getClass(), PercentPtg.class);
-
- // spaces OK
- ptgs = parseFormula(" 250 % ");
- assertEquals(2, ptgs.length);
- assertEquals(ptgs[0].getClass(), IntPtg.class);
- assertEquals(ptgs[1].getClass(), PercentPtg.class);
-
-
- // double percent OK
- ptgs = parseFormula("12345.678%%");
- assertEquals(3, ptgs.length);
- assertEquals(ptgs[0].getClass(), NumberPtg.class);
- assertEquals(ptgs[1].getClass(), PercentPtg.class);
- assertEquals(ptgs[2].getClass(), PercentPtg.class);
-
- // percent of a bracketed expression
- ptgs = parseFormula("(A1+35)%*B1%");
- assertEquals(8, ptgs.length);
- assertEquals(ptgs[4].getClass(), PercentPtg.class);
- assertEquals(ptgs[6].getClass(), PercentPtg.class);
-
- // percent of a text quantity
- ptgs = parseFormula("\"8.75\"%");
- assertEquals(2, ptgs.length);
- assertEquals(ptgs[0].getClass(), StringPtg.class);
- assertEquals(ptgs[1].getClass(), PercentPtg.class);
-
- // percent to the power of
- ptgs = parseFormula("50%^3");
- assertEquals(4, ptgs.length);
- assertEquals(ptgs[0].getClass(), IntPtg.class);
- assertEquals(ptgs[1].getClass(), PercentPtg.class);
- assertEquals(ptgs[2].getClass(), IntPtg.class);
- assertEquals(ptgs[3].getClass(), PowerPtg.class);
-
- //
- // things that parse OK but would *evaluate* to an error
-
- ptgs = parseFormula("\"abc\"%");
- assertEquals(2, ptgs.length);
- assertEquals(ptgs[0].getClass(), StringPtg.class);
- assertEquals(ptgs[1].getClass(), PercentPtg.class);
-
- ptgs = parseFormula("#N/A%");
- assertEquals(2, ptgs.length);
- assertEquals(ptgs[0].getClass(), ErrPtg.class);
- assertEquals(ptgs[1].getClass(), PercentPtg.class);
- }
-
- /**
- * Tests combinations of various operators in the absence of brackets
- */
- public void testPrecedenceAndAssociativity() {
-
- Class[] expClss;
-
- // TRUE=TRUE=2=2 evaluates to FALSE
- expClss = new Class[] { BoolPtg.class, BoolPtg.class, EqualPtg.class,
- IntPtg.class, EqualPtg.class, IntPtg.class, EqualPtg.class, };
- confirmTokenClasses("TRUE=TRUE=2=2", expClss);
-
-
- // 2^3^2 evaluates to 64 not 512
- expClss = new Class[] { IntPtg.class, IntPtg.class, PowerPtg.class,
- IntPtg.class, PowerPtg.class, };
- confirmTokenClasses("2^3^2", expClss);
-
- // "abc" & 2 + 3 & "def" evaluates to "abc5def"
- expClss = new Class[] { StringPtg.class, IntPtg.class, IntPtg.class,
- AddPtg.class, ConcatPtg.class, StringPtg.class, ConcatPtg.class, };
- confirmTokenClasses("\"abc\"&2+3&\"def\"", expClss);
-
-
- // (1 / 2) - (3 * 4)
- expClss = new Class[] { IntPtg.class, IntPtg.class, DividePtg.class,
- IntPtg.class, IntPtg.class, MultiplyPtg.class, SubtractPtg.class, };
- confirmTokenClasses("1/2-3*4", expClss);
-
- // 2 * (2^2)
- expClss = new Class[] { IntPtg.class, IntPtg.class, IntPtg.class, PowerPtg.class, MultiplyPtg.class, };
- // NOT: (2 *2) ^ 2 -> int int multiply int power
- confirmTokenClasses("2*2^2", expClss);
-
- // 2^200% -> 2 not 1.6E58
- expClss = new Class[] { IntPtg.class, IntPtg.class, PercentPtg.class, PowerPtg.class, };
- confirmTokenClasses("2^200%", expClss);
- }
-
- private static void confirmTokenClasses(String formula, Class[] expectedClasses) {
- Ptg[] ptgs = parseFormula(formula);
- assertEquals(expectedClasses.length, ptgs.length);
- for (int i = 0; i < expectedClasses.length; i++) {
- if(expectedClasses[i] != ptgs[i].getClass()) {
- fail("difference at token[" + i + "]: expected ("
- + expectedClasses[i].getName() + ") but got ("
- + ptgs[i].getClass().getName() + ")");
- }
- }
- }
-
- public void testPower() {
- confirmTokenClasses("2^5", new Class[] { IntPtg.class, IntPtg.class, PowerPtg.class, });
- }
-
- private static Ptg parseSingleToken(String formula, Class ptgClass) {
- Ptg[] ptgs = parseFormula(formula);
- assertEquals(1, ptgs.length);
- Ptg result = ptgs[0];
- assertEquals(ptgClass, result.getClass());
- return result;
- }
-
- public void testParseNumber() {
- IntPtg ip;
-
- // bug 33160
- ip = (IntPtg) parseSingleToken("40", IntPtg.class);
- assertEquals(40, ip.getValue());
- ip = (IntPtg) parseSingleToken("40000", IntPtg.class);
- assertEquals(40000, ip.getValue());
-
- // check the upper edge of the IntPtg range:
- ip = (IntPtg) parseSingleToken("65535", IntPtg.class);
- assertEquals(65535, ip.getValue());
- NumberPtg np = (NumberPtg) parseSingleToken("65536", NumberPtg.class);
- assertEquals(65536, np.getValue(), 0);
-
- np = (NumberPtg) parseSingleToken("65534.6", NumberPtg.class);
- assertEquals(65534.6, np.getValue(), 0);
- }
-
- public void testMissingArgs() {
-
- Class[] expClss;
-
- expClss = new Class[] { ReferencePtg.class, MissingArgPtg.class, ReferencePtg.class,
- FuncVarPtg.class, };
- confirmTokenClasses("if(A1, ,C1)", expClss);
-
- expClss = new Class[] { MissingArgPtg.class, AreaPtg.class, MissingArgPtg.class,
- FuncVarPtg.class, };
- confirmTokenClasses("counta( , A1:B2, )", expClss);
- }
-
- public void testParseErrorLiterals() {
-
- confirmParseErrorLiteral(ErrPtg.NULL_INTERSECTION, "#NULL!");
- confirmParseErrorLiteral(ErrPtg.DIV_ZERO, "#DIV/0!");
- confirmParseErrorLiteral(ErrPtg.VALUE_INVALID, "#VALUE!");
- confirmParseErrorLiteral(ErrPtg.REF_INVALID, "#REF!");
- confirmParseErrorLiteral(ErrPtg.NAME_INVALID, "#NAME?");
- confirmParseErrorLiteral(ErrPtg.NUM_ERROR, "#NUM!");
- confirmParseErrorLiteral(ErrPtg.N_A, "#N/A");
- }
-
- private static void confirmParseErrorLiteral(ErrPtg expectedToken, String formula) {
- assertEquals(expectedToken, parseSingleToken(formula, ErrPtg.class));
- }
-
- /**
- * To aid readability the parameters have been encoded with single quotes instead of double
- * quotes. This method converts single quotes to double quotes before performing the parse
- * and result check.
- */
- private static void confirmStringParse(String singleQuotedValue) {
- // formula: internal quotes become double double, surround with double quotes
- String formula = '"' + singleQuotedValue.replaceAll("'", "\"\"") + '"';
- String expectedValue = singleQuotedValue.replace('\'', '"');
-
- StringPtg sp = (StringPtg) parseSingleToken(formula, StringPtg.class);
- assertEquals(expectedValue, sp.getValue());
- }
- public void testParseStringLiterals_bug28754() {
-
- StringPtg sp;
- try {
- sp = (StringPtg) parseSingleToken("\"test\"\"ing\"", StringPtg.class);
- } catch (RuntimeException e) {
- if(e.getMessage().startsWith("Cannot Parse")) {
- throw new AssertionFailedError("Identified bug 28754a");
- }
- throw e;
- }
- assertEquals("test\"ing", sp.getValue());
-
- HSSFWorkbook wb = new HSSFWorkbook();
- HSSFSheet sheet = wb.createSheet();
- wb.setSheetName(0, "Sheet1");
-
- HSSFRow row = sheet.createRow(0);
- HSSFCell cell = row.createCell((short)0);
- cell.setCellFormula("right(\"test\"\"ing\", 3)");
- String actualCellFormula = cell.getCellFormula();
- if("RIGHT(\"test\"ing\",3)".equals(actualCellFormula)) {
- throw new AssertionFailedError("Identified bug 28754b");
- }
- assertEquals("RIGHT(\"test\"\"ing\",3)", actualCellFormula);
- }
-
- public void testParseStringLiterals() {
- confirmStringParse("goto considered harmful");
-
- confirmStringParse("goto 'considered' harmful");
-
- confirmStringParse("");
- confirmStringParse("'");
- confirmStringParse("''");
- confirmStringParse("' '");
- confirmStringParse(" ' ");
- }
-
- public void testParseSumIfSum() {
- String formulaString;
- Ptg[] ptgs;
- ptgs = parseFormula("sum(5, 2, if(3>2, sum(A1:A2), 6))");
- formulaString = FormulaParser.toFormulaString(null, ptgs);
- assertEquals("SUM(5,2,IF(3>2,SUM(A1:A2),6))", formulaString);
-
- ptgs = parseFormula("if(1<2,sum(5, 2, if(3>2, sum(A1:A2), 6)),4)");
- formulaString = FormulaParser.toFormulaString(null, ptgs);
- assertEquals("IF(1<2,SUM(5,2,IF(3>2,SUM(A1:A2),6)),4)", formulaString);
- }
- public void testParserErrors() {
- parseExpectedException("1 2");
- parseExpectedException(" 12 . 345 ");
- parseExpectedException("1 .23 ");
-
- parseExpectedException("sum(#NAME)");
- parseExpectedException("1 + #N / A * 2");
- parseExpectedException("#value?");
- parseExpectedException("#DIV/ 0+2");
-
-
- parseExpectedException("IF(TRUE)");
- parseExpectedException("countif(A1:B5, C1, D1)");
- }
-
- private static void parseExpectedException(String formula) {
- try {
- parseFormula(formula);
- throw new AssertionFailedError("expected parse exception");
- } catch (FormulaParseException e) {
- // expected during successful test
- assertNotNull(e.getMessage());
- } catch (RuntimeException e) {
- e.printStackTrace();
- fail("Wrong exception:" + e.getMessage());
- }
- }
-
- public void testSetFormulaWithRowBeyond32768_Bug44539() {
-
- HSSFWorkbook wb = new HSSFWorkbook();
- HSSFSheet sheet = wb.createSheet();
- wb.setSheetName(0, "Sheet1");
-
- HSSFRow row = sheet.createRow(0);
- HSSFCell cell = row.createCell((short)0);
- cell.setCellFormula("SUM(A32769:A32770)");
- if("SUM(A-32767:A-32766)".equals(cell.getCellFormula())) {
- fail("Identified bug 44539");
- }
- assertEquals("SUM(A32769:A32770)", cell.getCellFormula());
- }
-
- public void testSpaceAtStartOfFormula() {
- // Simulating cell formula of "= 4" (note space)
- // The same Ptg array can be observed if an excel file is saved with that exact formula
-
- AttrPtg spacePtg = AttrPtg.createSpace(AttrPtg.SpaceType.SPACE_BEFORE, 1);
- Ptg[] ptgs = { spacePtg, new IntPtg(4), };
- String formulaString;
- try {
- formulaString = FormulaParser.toFormulaString(null, ptgs);
- } catch (IllegalStateException e) {
- if(e.getMessage().equalsIgnoreCase("too much stuff left on the stack")) {
- throw new AssertionFailedError("Identified bug 44609");
- }
- // else some unexpected error
- throw e;
- }
- // FormulaParser strips spaces anyway
- assertEquals("4", formulaString);
-
- ptgs = new Ptg[] { new IntPtg(3), spacePtg, new IntPtg(4), spacePtg, new AddPtg()};
- formulaString = FormulaParser.toFormulaString(null, ptgs);
- assertEquals("3+4", formulaString);
- }
-
- /**
- * Checks some internal error detecting logic ('stack underflow error' in toFormulaString)
- */
- public void testTooFewOperandArgs() {
- // Simulating badly encoded cell formula of "=/1"
- // Not sure if Excel could ever produce this
- Ptg[] ptgs = {
- // Excel would probably have put tMissArg here
- new IntPtg(1),
- new DividePtg(),
- };
- try {
- FormulaParser.toFormulaString(null, ptgs);
- fail("Expected exception was not thrown");
- } catch (IllegalStateException e) {
- // expected during successful test
- assertTrue(e.getMessage().startsWith("Too few arguments suppled to operation token"));
- }
- }
- /**
- * Make sure that POI uses the right Func Ptg when encoding formulas. Functions with variable
- * number of args should get FuncVarPtg, functions with fixed args should get FuncPtg.<p/>
- *
- * Prior to the fix for bug 44675 POI would encode FuncVarPtg for all functions. In many cases
- * Excel tolerates the wrong Ptg and evaluates the formula OK (e.g. SIN), but in some cases
- * (e.g. COUNTIF) Excel fails to evaluate the formula, giving '#VALUE!' instead.
- */
- public void testFuncPtgSelection() {
- HSSFWorkbook book = new HSSFWorkbook();
- Ptg[] ptgs;
- ptgs = FormulaParser.parse("countif(A1:A2, 1)", book);
- assertEquals(3, ptgs.length);
- if(FuncVarPtg.class == ptgs[2].getClass()) {
- throw new AssertionFailedError("Identified bug 44675");
- }
- assertEquals(FuncPtg.class, ptgs[2].getClass());
- ptgs = FormulaParser.parse("sin(1)", book);
- assertEquals(2, ptgs.length);
- assertEquals(FuncPtg.class, ptgs[1].getClass());
- }
-
- public void testWrongNumberOfFunctionArgs() {
- confirmArgCountMsg("sin()", "Too few arguments to function 'SIN'. Expected 1 but got 0.");
- confirmArgCountMsg("countif(1, 2, 3, 4)", "Too many arguments to function 'COUNTIF'. Expected 2 but got 4.");
- confirmArgCountMsg("index(1, 2, 3, 4, 5, 6)", "Too many arguments to function 'INDEX'. At most 4 were expected but got 6.");
- confirmArgCountMsg("vlookup(1, 2)", "Too few arguments to function 'VLOOKUP'. At least 3 were expected but got 2.");
- }
-
- private static void confirmArgCountMsg(String formula, String expectedMessage) {
- HSSFWorkbook book = new HSSFWorkbook();
- try {
- FormulaParser.parse(formula, book);
- throw new AssertionFailedError("Didn't get parse exception as expected");
- } catch (FormulaParseException e) {
- assertEquals(expectedMessage, e.getMessage());
- }
- }
+ cell.setCellFormula("-1300000000000000/3");
+ formula = cell.getCellFormula();
+ assertEquals("Exponential formula string", "-1.3E15/3", formula);
+
+ cell.setCellFormula("-10E-1/3.1E2*4E3/3E4");
+ formula = cell.getCellFormula();
+ assertEquals("Exponential formula string", "-1.0/310.0*4000.0/30000.0", formula);
+ }
+
+ public void testNumbers() {
+ HSSFWorkbook wb = new HSSFWorkbook();
+
+ wb.createSheet("Cash_Flow");
+
+ HSSFSheet sheet = wb.createSheet("Test");
+ HSSFRow row = sheet.createRow(0);
+ HSSFCell cell = row.createCell((short)0);
+ String formula = null;
+
+ // starts from decimal point
+
+ cell.setCellFormula(".1");
+ formula = cell.getCellFormula();
+ assertEquals("0.1", formula);
+
+ cell.setCellFormula("+.1");
+ formula = cell.getCellFormula();
+ assertEquals("+0.1", formula);
+
+ cell.setCellFormula("-.1");
+ formula = cell.getCellFormula();
+ assertEquals("-0.1", formula);
+
+ // has exponent
+
+ cell.setCellFormula("10E1");
+ formula = cell.getCellFormula();
+ assertEquals("100.0", formula);
+
+ cell.setCellFormula("10E+1");
+ formula = cell.getCellFormula();
+ assertEquals("100.0", formula);
+
+ cell.setCellFormula("10E-1");
+ formula = cell.getCellFormula();
+ assertEquals("1.0", formula);
+ }
+
+ public void testRanges() {
+ HSSFWorkbook wb = new HSSFWorkbook();
+
+ wb.createSheet("Cash_Flow");
+
+ HSSFSheet sheet = wb.createSheet("Test");
+ HSSFRow row = sheet.createRow(0);
+ HSSFCell cell = row.createCell((short)0);
+ String formula = null;
+
+ cell.setCellFormula("A1.A2");
+ formula = cell.getCellFormula();
+ assertEquals("A1:A2", formula);
+
+ cell.setCellFormula("A1..A2");
+ formula = cell.getCellFormula();
+ assertEquals("A1:A2", formula);
+
+ cell.setCellFormula("A1...A2");
+ formula = cell.getCellFormula();
+ assertEquals("A1:A2", formula);
+ }
+
+ /**
+ * Test for bug observable at svn revision 618865 (5-Feb-2008)<br/>
+ * a formula consisting of a single no-arg function got rendered without the function braces
+ */
+ public void testToFormulaStringZeroArgFunction() {
+ HSSFWorkbook book = new HSSFWorkbook();
+
+ Ptg[] ptgs = {
+ new FuncPtg(10),
+ };
+ assertEquals("NA()", FormulaParser.toFormulaString(book, ptgs));
+ }
+
+ public void testPercent() {
+ Ptg[] ptgs;
+ ptgs = parseFormula("5%");
+ assertEquals(2, ptgs.length);
+ assertEquals(ptgs[0].getClass(), IntPtg.class);
+ assertEquals(ptgs[1].getClass(), PercentPtg.class);
+
+ // spaces OK
+ ptgs = parseFormula(" 250 % ");
+ assertEquals(2, ptgs.length);
+ assertEquals(ptgs[0].getClass(), IntPtg.class);
+ assertEquals(ptgs[1].getClass(), PercentPtg.class);
+
+
+ // double percent OK
+ ptgs = parseFormula("12345.678%%");
+ assertEquals(3, ptgs.length);
+ assertEquals(ptgs[0].getClass(), NumberPtg.class);
+ assertEquals(ptgs[1].getClass(), PercentPtg.class);
+ assertEquals(ptgs[2].getClass(), PercentPtg.class);
+
+ // percent of a bracketed expression
+ ptgs = parseFormula("(A1+35)%*B1%");
+ assertEquals(8, ptgs.length);
+ assertEquals(ptgs[4].getClass(), PercentPtg.class);
+ assertEquals(ptgs[6].getClass(), PercentPtg.class);
+
+ // percent of a text quantity
+ ptgs = parseFormula("\"8.75\"%");
+ assertEquals(2, ptgs.length);
+ assertEquals(ptgs[0].getClass(), StringPtg.class);
+ assertEquals(ptgs[1].getClass(), PercentPtg.class);
+
+ // percent to the power of
+ ptgs = parseFormula("50%^3");
+ assertEquals(4, ptgs.length);
+ assertEquals(ptgs[0].getClass(), IntPtg.class);
+ assertEquals(ptgs[1].getClass(), PercentPtg.class);
+ assertEquals(ptgs[2].getClass(), IntPtg.class);
+ assertEquals(ptgs[3].getClass(), PowerPtg.class);
+
+ //
+ // things that parse OK but would *evaluate* to an error
+
+ ptgs = parseFormula("\"abc\"%");
+ assertEquals(2, ptgs.length);
+ assertEquals(ptgs[0].getClass(), StringPtg.class);
+ assertEquals(ptgs[1].getClass(), PercentPtg.class);
+
+ ptgs = parseFormula("#N/A%");
+ assertEquals(2, ptgs.length);
+ assertEquals(ptgs[0].getClass(), ErrPtg.class);
+ assertEquals(ptgs[1].getClass(), PercentPtg.class);
+ }
+
+ /**
+ * Tests combinations of various operators in the absence of brackets
+ */
+ public void testPrecedenceAndAssociativity() {
+
+ Class[] expClss;
+
+ // TRUE=TRUE=2=2 evaluates to FALSE
+ expClss = new Class[] { BoolPtg.class, BoolPtg.class, EqualPtg.class,
+ IntPtg.class, EqualPtg.class, IntPtg.class, EqualPtg.class, };
+ confirmTokenClasses("TRUE=TRUE=2=2", expClss);
+
+
+ // 2^3^2 evaluates to 64 not 512
+ expClss = new Class[] { IntPtg.class, IntPtg.class, PowerPtg.class,
+ IntPtg.class, PowerPtg.class, };
+ confirmTokenClasses("2^3^2", expClss);
+
+ // "abc" & 2 + 3 & "def" evaluates to "abc5def"
+ expClss = new Class[] { StringPtg.class, IntPtg.class, IntPtg.class,
+ AddPtg.class, ConcatPtg.class, StringPtg.class, ConcatPtg.class, };
+ confirmTokenClasses("\"abc\"&2+3&\"def\"", expClss);
+
+
+ // (1 / 2) - (3 * 4)
+ expClss = new Class[] { IntPtg.class, IntPtg.class, DividePtg.class,
+ IntPtg.class, IntPtg.class, MultiplyPtg.class, SubtractPtg.class, };
+ confirmTokenClasses("1/2-3*4", expClss);
+
+ // 2 * (2^2)
+ expClss = new Class[] { IntPtg.class, IntPtg.class, IntPtg.class, PowerPtg.class, MultiplyPtg.class, };
+ // NOT: (2 *2) ^ 2 -> int int multiply int power
+ confirmTokenClasses("2*2^2", expClss);
+
+ // 2^200% -> 2 not 1.6E58
+ expClss = new Class[] { IntPtg.class, IntPtg.class, PercentPtg.class, PowerPtg.class, };
+ confirmTokenClasses("2^200%", expClss);
+ }
+
+ private static void confirmTokenClasses(String formula, Class[] expectedClasses) {
+ Ptg[] ptgs = parseFormula(formula);
+ assertEquals(expectedClasses.length, ptgs.length);
+ for (int i = 0; i < expectedClasses.length; i++) {
+ if(expectedClasses[i] != ptgs[i].getClass()) {
+ fail("difference at token[" + i + "]: expected ("
+ + expectedClasses[i].getName() + ") but got ("
+ + ptgs[i].getClass().getName() + ")");
+ }
+ }
+ }
+
+ public void testPower() {
+ confirmTokenClasses("2^5", new Class[] { IntPtg.class, IntPtg.class, PowerPtg.class, });
+ }
+
+ private static Ptg parseSingleToken(String formula, Class ptgClass) {
+ Ptg[] ptgs = parseFormula(formula);
+ assertEquals(1, ptgs.length);
+ Ptg result = ptgs[0];
+ assertEquals(ptgClass, result.getClass());
+ return result;
+ }
+
+ public void testParseNumber() {
+ IntPtg ip;
+
+ // bug 33160
+ ip = (IntPtg) parseSingleToken("40", IntPtg.class);
+ assertEquals(40, ip.getValue());
+ ip = (IntPtg) parseSingleToken("40000", IntPtg.class);
+ assertEquals(40000, ip.getValue());
+
+ // check the upper edge of the IntPtg range:
+ ip = (IntPtg) parseSingleToken("65535", IntPtg.class);
+ assertEquals(65535, ip.getValue());
+ NumberPtg np = (NumberPtg) parseSingleToken("65536", NumberPtg.class);
+ assertEquals(65536, np.getValue(), 0);
+
+ np = (NumberPtg) parseSingleToken("65534.6", NumberPtg.class);
+ assertEquals(65534.6, np.getValue(), 0);
+ }
+
+ public void testMissingArgs() {
+
+ Class[] expClss;
+
+ expClss = new Class[] { ReferencePtg.class, MissingArgPtg.class, ReferencePtg.class,
+ FuncVarPtg.class, };
+ confirmTokenClasses("if(A1, ,C1)", expClss);
+
+ expClss = new Class[] { MissingArgPtg.class, AreaPtg.class, MissingArgPtg.class,
+ FuncVarPtg.class, };
+ confirmTokenClasses("counta( , A1:B2, )", expClss);
+ }
+
+ public void testParseErrorLiterals() {
+
+ confirmParseErrorLiteral(ErrPtg.NULL_INTERSECTION, "#NULL!");
+ confirmParseErrorLiteral(ErrPtg.DIV_ZERO, "#DIV/0!");
+ confirmParseErrorLiteral(ErrPtg.VALUE_INVALID, "#VALUE!");
+ confirmParseErrorLiteral(ErrPtg.REF_INVALID, "#REF!");
+ confirmParseErrorLiteral(ErrPtg.NAME_INVALID, "#NAME?");
+ confirmParseErrorLiteral(ErrPtg.NUM_ERROR, "#NUM!");
+ confirmParseErrorLiteral(ErrPtg.N_A, "#N/A");
+ }
+
+ private static void confirmParseErrorLiteral(ErrPtg expectedToken, String formula) {
+ assertEquals(expectedToken, parseSingleToken(formula, ErrPtg.class));
+ }
+
+ /**
+ * To aid readability the parameters have been encoded with single quotes instead of double
+ * quotes. This method converts single quotes to double quotes before performing the parse
+ * and result check.
+ */
+ private static void confirmStringParse(String singleQuotedValue) {
+ // formula: internal quotes become double double, surround with double quotes
+ String formula = '"' + singleQuotedValue.replaceAll("'", "\"\"") + '"';
+ String expectedValue = singleQuotedValue.replace('\'', '"');
+
+ StringPtg sp = (StringPtg) parseSingleToken(formula, StringPtg.class);
+ assertEquals(expectedValue, sp.getValue());
+ }
+ public void testParseStringLiterals_bug28754() {
+
+ StringPtg sp;
+ try {
+ sp = (StringPtg) parseSingleToken("\"test\"\"ing\"", StringPtg.class);
+ } catch (RuntimeException e) {
+ if(e.getMessage().startsWith("Cannot Parse")) {
+ throw new AssertionFailedError("Identified bug 28754a");
+ }
+ throw e;
+ }
+ assertEquals("test\"ing", sp.getValue());
+
+ HSSFWorkbook wb = new HSSFWorkbook();
+ HSSFSheet sheet = wb.createSheet();
+ wb.setSheetName(0, "Sheet1");
+
+ HSSFRow row = sheet.createRow(0);
+ HSSFCell cell = row.createCell((short)0);
+ cell.setCellFormula("right(\"test\"\"ing\", 3)");
+ String actualCellFormula = cell.getCellFormula();
+ if("RIGHT(\"test\"ing\",3)".equals(actualCellFormula)) {
+ throw new AssertionFailedError("Identified bug 28754b");
+ }
+ assertEquals("RIGHT(\"test\"\"ing\",3)", actualCellFormula);
+ }
+
+ public void testParseStringLiterals() {
+ confirmStringParse("goto considered harmful");
+
+ confirmStringParse("goto 'considered' harmful");
+
+ confirmStringParse("");
+ confirmStringParse("'");
+ confirmStringParse("''");
+ confirmStringParse("' '");
+ confirmStringParse(" ' ");
+ }
+
+ public void testParseSumIfSum() {
+ String formulaString;
+ Ptg[] ptgs;
+ ptgs = parseFormula("sum(5, 2, if(3>2, sum(A1:A2), 6))");
+ formulaString = FormulaParser.toFormulaString(null, ptgs);
+ assertEquals("SUM(5,2,IF(3>2,SUM(A1:A2),6))", formulaString);
+
+ ptgs = parseFormula("if(1<2,sum(5, 2, if(3>2, sum(A1:A2), 6)),4)");
+ formulaString = FormulaParser.toFormulaString(null, ptgs);
+ assertEquals("IF(1<2,SUM(5,2,IF(3>2,SUM(A1:A2),6)),4)", formulaString);
+ }
+ public void testParserErrors() {
+ parseExpectedException("1 2");
+ parseExpectedException(" 12 . 345 ");
+ parseExpectedException("1 .23 ");
+
+ parseExpectedException("sum(#NAME)");
+ parseExpectedException("1 + #N / A * 2");
+ parseExpectedException("#value?");
+ parseExpectedException("#DIV/ 0+2");
+
+
+ parseExpectedException("IF(TRUE)");
+ parseExpectedException("countif(A1:B5, C1, D1)");
+ }
+
+ private static void parseExpectedException(String formula) {
+ try {
+ parseFormula(formula);
+ throw new AssertionFailedError("expected parse exception");
+ } catch (FormulaParseException e) {
+ // expected during successful test
+ assertNotNull(e.getMessage());
+ } catch (RuntimeException e) {
+ e.printStackTrace();
+ fail("Wrong exception:" + e.getMessage());
+ }
+ }
+
+ public void testSetFormulaWithRowBeyond32768_Bug44539() {
+
+ HSSFWorkbook wb = new HSSFWorkbook();
+ HSSFSheet sheet = wb.createSheet();
+ wb.setSheetName(0, "Sheet1");
+
+ HSSFRow row = sheet.createRow(0);
+ HSSFCell cell = row.createCell((short)0);
+ cell.setCellFormula("SUM(A32769:A32770)");
+ if("SUM(A-32767:A-32766)".equals(cell.getCellFormula())) {
+ fail("Identified bug 44539");
+ }
+ assertEquals("SUM(A32769:A32770)", cell.getCellFormula());
+ }
+
+ public void testSpaceAtStartOfFormula() {
+ // Simulating cell formula of "= 4" (note space)
+ // The same Ptg array can be observed if an excel file is saved with that exact formula
+
+ AttrPtg spacePtg = AttrPtg.createSpace(AttrPtg.SpaceType.SPACE_BEFORE, 1);
+ Ptg[] ptgs = { spacePtg, new IntPtg(4), };
+ String formulaString;
+ try {
+ formulaString = FormulaParser.toFormulaString(null, ptgs);
+ } catch (IllegalStateException e) {
+ if(e.getMessage().equalsIgnoreCase("too much stuff left on the stack")) {
+ throw new AssertionFailedError("Identified bug 44609");
+ }
+ // else some unexpected error
+ throw e;
+ }
+ // FormulaParser strips spaces anyway
+ assertEquals("4", formulaString);
+
+ ptgs = new Ptg[] { new IntPtg(3), spacePtg, new IntPtg(4), spacePtg, new AddPtg()};
+ formulaString = FormulaParser.toFormulaString(null, ptgs);
+ assertEquals("3+4", formulaString);
+ }
+
+ /**
+ * Checks some internal error detecting logic ('stack underflow error' in toFormulaString)
+ */
+ public void testTooFewOperandArgs() {
+ // Simulating badly encoded cell formula of "=/1"
+ // Not sure if Excel could ever produce this
+ Ptg[] ptgs = {
+ // Excel would probably have put tMissArg here
+ new IntPtg(1),
+ new DividePtg(),
+ };
+ try {
+ FormulaParser.toFormulaString(null, ptgs);
+ fail("Expected exception was not thrown");
+ } catch (IllegalStateException e) {
+ // expected during successful test
+ assertTrue(e.getMessage().startsWith("Too few arguments suppled to operation token"));
+ }
+ }
+ /**
+ * Make sure that POI uses the right Func Ptg when encoding formulas. Functions with variable
+ * number of args should get FuncVarPtg, functions with fixed args should get FuncPtg.<p/>
+ *
+ * Prior to the fix for bug 44675 POI would encode FuncVarPtg for all functions. In many cases
+ * Excel tolerates the wrong Ptg and evaluates the formula OK (e.g. SIN), but in some cases
+ * (e.g. COUNTIF) Excel fails to evaluate the formula, giving '#VALUE!' instead.
+ */
+ public void testFuncPtgSelection() {
+
+ Ptg[] ptgs;
+ ptgs = parseFormula("countif(A1:A2, 1)");
+ assertEquals(3, ptgs.length);
+ if(FuncVarPtg.class == ptgs[2].getClass()) {
+ throw new AssertionFailedError("Identified bug 44675");
+ }
+ assertEquals(FuncPtg.class, ptgs[2].getClass());
+ ptgs = parseFormula("sin(1)");
+ assertEquals(2, ptgs.length);
+ assertEquals(FuncPtg.class, ptgs[1].getClass());
+ }
+
+ public void testWrongNumberOfFunctionArgs() {
+ confirmArgCountMsg("sin()", "Too few arguments to function 'SIN'. Expected 1 but got 0.");
+ confirmArgCountMsg("countif(1, 2, 3, 4)", "Too many arguments to function 'COUNTIF'. Expected 2 but got 4.");
+ confirmArgCountMsg("index(1, 2, 3, 4, 5, 6)", "Too many arguments to function 'INDEX'. At most 4 were expected but got 6.");
+ confirmArgCountMsg("vlookup(1, 2)", "Too few arguments to function 'VLOOKUP'. At least 3 were expected but got 2.");
+ }
+
+ private static void confirmArgCountMsg(String formula, String expectedMessage) {
+ HSSFWorkbook book = new HSSFWorkbook();
+ try {
+ FormulaParser.parse(formula, book);
+ throw new AssertionFailedError("Didn't get parse exception as expected");
+ } catch (FormulaParseException e) {
+ assertEquals(expectedMessage, e.getMessage());
+ }
+ }
+
+ public void testParseErrorExpecteMsg() {
+
+ try {
+ parseFormula("round(3.14;2)");
+ throw new AssertionFailedError("Didn't get parse exception as expected");
+ } catch (FormulaParseException e) {
+ assertEquals("Parse error near char 10 ';' in specified formula 'round(3.14;2)'. Expected ',' or ')'", e.getMessage());
+ }
+ }
}
diff --git a/src/testcases/org/apache/poi/hssf/model/TestSheet.java b/src/testcases/org/apache/poi/hssf/model/TestSheet.java
index 9281eb80d7..3bdcae57cb 100644
--- a/src/testcases/org/apache/poi/hssf/model/TestSheet.java
+++ b/src/testcases/org/apache/poi/hssf/model/TestSheet.java
@@ -17,6 +17,7 @@
package org.apache.poi.hssf.model;
+import junit.framework.AssertionFailedError;
import junit.framework.TestCase;
import org.apache.poi.hssf.record.*;
import org.apache.poi.hssf.record.aggregates.ColumnInfoRecordsAggregate;
@@ -351,5 +352,25 @@ public final class TestSheet extends TestCase {
xfindex = sheet.getXFIndexForColAt((short) 10);
assertEquals(DEFAULT_IDX, xfindex);
}
+
+ /**
+ * Prior to bug 45066, POI would get the estimated sheet size wrong
+ * when an <tt>UncalcedRecord</tt> was present.<p/>
+ */
+ public void testUncalcSize_bug45066() {
+
+ List records = new ArrayList();
+ records.add(new BOFRecord());
+ records.add(new UncalcedRecord());
+ records.add(new EOFRecord());
+ Sheet sheet = Sheet.createSheet( records, 0, 0 );
+
+ int estimatedSize = sheet.getSize();
+ int serializedSize = sheet.serialize(0, new byte[estimatedSize]);
+ if (serializedSize != estimatedSize) {
+ throw new AssertionFailedError("Identified bug 45066 b");
+ }
+ assertEquals(50, serializedSize);
+ }
}
diff --git a/src/testcases/org/apache/poi/hssf/record/formula/function/ExcelFileFormatDocFunctionExtractor.java b/src/testcases/org/apache/poi/hssf/record/formula/function/ExcelFileFormatDocFunctionExtractor.java
index 47137df4f6..7702fce3d4 100644
--- a/src/testcases/org/apache/poi/hssf/record/formula/function/ExcelFileFormatDocFunctionExtractor.java
+++ b/src/testcases/org/apache/poi/hssf/record/formula/function/ExcelFileFormatDocFunctionExtractor.java
@@ -26,9 +26,12 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
+import java.math.BigInteger;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@@ -37,7 +40,6 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
-import java.util.zip.CRC32;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;
@@ -149,7 +151,6 @@ public final class ExcelFileFormatDocFunctionExtractor {
private static final class FunctionDataCollector {
-
private final Map _allFunctionsByIndex;
private final Map _allFunctionsByName;
private final Set _groupFunctionIndexes;
@@ -184,25 +185,29 @@ public final class ExcelFileFormatDocFunctionExtractor {
_allFunctionsByName.put(funcName, fd);
}
+ /**
+ * Some extra validation here.
+ * Any function which changes definition will have a footnote in the source document
+ */
private void checkRedefinedFunction(boolean hasNote, String funcName, Integer funcIxKey) {
FunctionData fdPrev;
+ // check by index
fdPrev = (FunctionData) _allFunctionsByIndex.get(funcIxKey);
if(fdPrev != null) {
- if(fdPrev.hasFootnote() && hasNote) {
- // func def can change if both have a foot-note
- _allFunctionsByName.remove(fdPrev.getName());
- } else {
- throw new RuntimeException("changing function definition without foot-note");
+ if(!fdPrev.hasFootnote() || !hasNote) {
+ throw new RuntimeException("changing function ["
+ + funcIxKey + "] definition without foot-note");
}
+ _allFunctionsByName.remove(fdPrev.getName());
}
+ // check by name
fdPrev = (FunctionData) _allFunctionsByName.get(funcName);
if(fdPrev != null) {
- if(fdPrev.hasFootnote() && hasNote) {
- // func def can change if both have a foot-note
- _allFunctionsByIndex.remove(new Integer(fdPrev.getIndex()));
- } else {
- throw new RuntimeException("changing function definition without foot-note");
+ if(!fdPrev.hasFootnote() || !hasNote) {
+ throw new RuntimeException("changing function '"
+ + funcName + "' definition without foot-note");
}
+ _allFunctionsByIndex.remove(new Integer(fdPrev.getIndex()));
}
}
@@ -237,9 +242,13 @@ public final class ExcelFileFormatDocFunctionExtractor {
private static final String[] TABLE_CELL_RELPATH_NAMES = {
"table:table-row", "table:table-cell", "text:p",
};
- private static final String[] NOTE_REF_RELPATH_NAMES = {
+ // after May 2008 there was one more style applied to the footnotes
+ private static final String[] NOTE_REF_RELPATH_NAMES_OLD = {
"table:table-row", "table:table-cell", "text:p", "text:span", "text:note-ref",
};
+ private static final String[] NOTE_REF_RELPATH_NAMES = {
+ "table:table-row", "table:table-cell", "text:p", "text:span", "text:span", "text:note-ref",
+ };
private final Stack _elemNameStack;
@@ -368,6 +377,8 @@ public final class ExcelFileFormatDocFunctionExtractor {
} else if(matchesRelPath(TABLE_CELL_RELPATH_NAMES)) {
_textNodeBuffer.setLength(0);
_cellHasNote = false;
+ } else if(matchesRelPath(NOTE_REF_RELPATH_NAMES_OLD)) {
+ _cellHasNote = true;
} else if(matchesRelPath(NOTE_REF_RELPATH_NAMES)) {
_cellHasNote = true;
}
@@ -456,6 +467,9 @@ public final class ExcelFileFormatDocFunctionExtractor {
}
private static void processFile(File effDocFile, File outFile) {
+ if(!effDocFile.exists()) {
+ throw new RuntimeException("file '" + effDocFile.getAbsolutePath() + "' does not exist");
+ }
OutputStream os;
try {
os = new FileOutputStream(outFile);
@@ -475,7 +489,7 @@ public final class ExcelFileFormatDocFunctionExtractor {
ps.println("# Created by (" + genClass.getName() + ")");
// identify the source file
ps.print("# from source file '" + SOURCE_DOC_FILE_NAME + "'");
- ps.println(" (size=" + effDocFile.length() + ", crc=" + getFileCRC(effDocFile) + ")");
+ ps.println(" (size=" + effDocFile.length() + ", md5=" + getFileMD5(effDocFile) + ")");
ps.println("#");
ps.println("#Columns: (index, name, minParams, maxParams, returnClass, paramClasses, isVolatile, hasFootnote )");
ps.println("");
@@ -490,6 +504,14 @@ public final class ExcelFileFormatDocFunctionExtractor {
throw new RuntimeException(e);
}
ps.close();
+
+ String canonicalOutputFileName;
+ try {
+ canonicalOutputFileName = outFile.getCanonicalPath();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ System.out.println("Successfully output to '" + canonicalOutputFileName + "'");
}
private static void outputLicenseHeader(PrintStream ps) {
@@ -519,8 +541,14 @@ public final class ExcelFileFormatDocFunctionExtractor {
/**
* Helps identify the source file
*/
- private static String getFileCRC(File f) {
- CRC32 crc = new CRC32();
+ private static String getFileMD5(File f) {
+ MessageDigest m;
+ try {
+ m = MessageDigest.getInstance("MD5");
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException(e);
+ }
+
byte[]buf = new byte[2048];
try {
InputStream is = new FileInputStream(f);
@@ -529,21 +557,17 @@ public final class ExcelFileFormatDocFunctionExtractor {
if(bytesRead<1) {
break;
}
- crc.update(buf, 0, bytesRead);
+ m.update(buf, 0, bytesRead);
}
is.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
- return "0x" + Long.toHexString(crc.getValue()).toUpperCase();
+
+ return "0x" + new BigInteger(1, m.digest()).toString(16);
}
- private static File getSourceFile() {
- if (false) {
- File dir = new File("c:/temp");
- File effDocFile = new File(dir, SOURCE_DOC_FILE_NAME);
- return effDocFile;
- }
+ private static File downloadSourceFile() {
URL url;
try {
url = new URL("http://sc.openoffice.org/" + SOURCE_DOC_FILE_NAME);
@@ -557,7 +581,7 @@ public final class ExcelFileFormatDocFunctionExtractor {
URLConnection conn = url.openConnection();
InputStream is = conn.getInputStream();
System.out.println("downloading " + url.toExternalForm());
- result = File.createTempFile("excelfileformat", "odt");
+ result = File.createTempFile("excelfileformat", ".odt");
OutputStream os = new FileOutputStream(result);
while(true) {
int bytesRead = is.read(buf);
@@ -577,12 +601,17 @@ public final class ExcelFileFormatDocFunctionExtractor {
public static void main(String[] args) {
- File effDocFile = getSourceFile();
- if(!effDocFile.exists()) {
- throw new RuntimeException("file '" + effDocFile.getAbsolutePath() + "' does not exist");
- }
-
File outFile = new File("functionMetadata-asGenerated.txt");
- processFile(effDocFile, outFile);
+
+ if (false) { // set true to use local file
+ File dir = new File("c:/temp");
+ File effDocFile = new File(dir, SOURCE_DOC_FILE_NAME);
+ processFile(effDocFile, outFile);
+ return;
+ }
+
+ File tempEFFDocFile = downloadSourceFile();
+ processFile(tempEFFDocFile, outFile);
+ tempEFFDocFile.delete();
}
}
diff --git a/src/testcases/org/apache/poi/hssf/record/formula/function/TestParseMissingBuiltInFuncs.java b/src/testcases/org/apache/poi/hssf/record/formula/function/TestParseMissingBuiltInFuncs.java
index 1e26fa706e..7030c5a508 100644
--- a/src/testcases/org/apache/poi/hssf/record/formula/function/TestParseMissingBuiltInFuncs.java
+++ b/src/testcases/org/apache/poi/hssf/record/formula/function/TestParseMissingBuiltInFuncs.java
@@ -21,7 +21,6 @@ import junit.framework.AssertionFailedError;
import junit.framework.TestCase;
import org.apache.poi.hssf.model.FormulaParser;
-import org.apache.poi.hssf.model.Workbook;
import org.apache.poi.hssf.record.formula.AbstractFunctionPtg;
import org.apache.poi.hssf.record.formula.FuncPtg;
import org.apache.poi.hssf.record.formula.FuncVarPtg;
@@ -29,7 +28,7 @@ import org.apache.poi.hssf.record.formula.Ptg;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
/**
* Tests parsing of some built-in functions that were not properly
- * registered in POI as bug #44675, #44733 (March/April 2008).
+ * registered in POI as of bug #44675, #44733 (March/April 2008).
*
* @author Josh Micich
*/
@@ -76,7 +75,7 @@ public final class TestParseMissingBuiltInFuncs extends TestCase {
}
public void testUsdollar() {
- confirmFunc("USDOLLAR(1)", 2, false, 204);
+ confirmFunc("USDOLLAR(1)", 2, true, 204);
}
public void testDBCS() {
diff --git a/src/testcases/org/apache/poi/hssf/record/formula/function/TestReadMissingBuiltInFuncs.java b/src/testcases/org/apache/poi/hssf/record/formula/function/TestReadMissingBuiltInFuncs.java
index 6766f2fc07..0a62d64cdb 100644
--- a/src/testcases/org/apache/poi/hssf/record/formula/function/TestReadMissingBuiltInFuncs.java
+++ b/src/testcases/org/apache/poi/hssf/record/formula/function/TestReadMissingBuiltInFuncs.java
@@ -17,22 +17,18 @@
package org.apache.poi.hssf.record.formula.function;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
+import junit.framework.AssertionFailedError;
+import junit.framework.TestCase;
+
import org.apache.poi.hssf.HSSFTestDataSamples;
import org.apache.poi.hssf.record.RecordFormatException;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-
-import junit.framework.AssertionFailedError;
-import junit.framework.TestCase;
/**
* Tests reading from a sample spreadsheet some built-in functions that were not properly
- * registered in POI as bug #44675, #44733 (March/April 2008).
+ * registered in POI as of bug #44675, #44733 (March/April 2008).
*
* @author Josh Micich
*/
diff --git a/src/testcases/org/apache/poi/hssf/usermodel/AllUserModelTests.java b/src/testcases/org/apache/poi/hssf/usermodel/AllUserModelTests.java
index 0e18e21e52..363e58c142 100755
--- a/src/testcases/org/apache/poi/hssf/usermodel/AllUserModelTests.java
+++ b/src/testcases/org/apache/poi/hssf/usermodel/AllUserModelTests.java
@@ -28,7 +28,7 @@ import junit.framework.TestSuite;
public class AllUserModelTests {
public static Test suite() {
- TestSuite result = new TestSuite("Tests for org.apache.poi.hssf.usermodel");
+ TestSuite result = new TestSuite(AllUserModelTests.class.getName());
result.addTestSuite(TestBugs.class);
result.addTestSuite(TestCellStyle.class);
@@ -58,6 +58,7 @@ public class AllUserModelTests {
result.addTestSuite(TestHSSFSheetSetOrder.class);
result.addTestSuite(TestHSSFTextbox.class);
result.addTestSuite(TestHSSFWorkbook.class);
+ result.addTestSuite(TestLinkTable.class);
result.addTestSuite(TestNamedRange.class);
result.addTestSuite(TestOLE2Embeding.class);
result.addTestSuite(TestPOIFSProperties.class);
diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFCell.java b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFCell.java
index a2e8bd3baa..7f43758477 100644
--- a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFCell.java
+++ b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFCell.java
@@ -58,6 +58,30 @@ public final class TestHSSFCell extends TestCase {
}
}
+ public void testSetValues() throws Exception {
+ HSSFWorkbook book = new HSSFWorkbook();
+ HSSFSheet sheet = book.createSheet("test");
+ HSSFRow row = sheet.createRow(0);
+
+ HSSFCell cell = row.createCell((short)0);
+
+ cell.setCellValue(1.2);
+ assertEquals(1.2, cell.getNumericCellValue(), 0.0001);
+ assertEquals(HSSFCell.CELL_TYPE_NUMERIC, cell.getCellType());
+
+ cell.setCellValue(false);
+ assertEquals(false, cell.getBooleanCellValue());
+ assertEquals(HSSFCell.CELL_TYPE_BOOLEAN, cell.getCellType());
+
+ cell.setCellValue(new HSSFRichTextString("Foo"));
+ assertEquals("Foo", cell.getRichStringCellValue().getString());
+ assertEquals(HSSFCell.CELL_TYPE_STRING, cell.getCellType());
+
+ cell.setCellValue(new HSSFRichTextString("345"));
+ assertEquals("345", cell.getRichStringCellValue().getString());
+ assertEquals(HSSFCell.CELL_TYPE_STRING, cell.getCellType());
+ }
+
/**
* test that Boolean and Error types (BoolErrRecord) are supported properly.
*/
diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFDateUtil.java b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFDateUtil.java
index cd0901a291..76c098da2d 100644
--- a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFDateUtil.java
+++ b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFDateUtil.java
@@ -266,6 +266,8 @@ public class TestHSSFDateUtil extends TestCase {
formats = new String[] {
"yyyy-mm-dd hh:mm:ss", "yyyy/mm/dd HH:MM:SS",
"mm/dd HH:MM", "yy/mmm/dd SS",
+ "mm/dd HH:MM AM", "mm/dd HH:MM am",
+ "mm/dd HH:MM PM", "mm/dd HH:MM pm"
};
for(int i=0; i<formats.length; i++) {
assertTrue( HSSFDateUtil.isADateFormat(formatId, formats[i]) );
diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFSheet.java b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFSheet.java
index 7599f2a166..3b154b2562 100644
--- a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFSheet.java
+++ b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFSheet.java
@@ -36,7 +36,6 @@ import org.apache.poi.hssf.record.VCenterRecord;
import org.apache.poi.hssf.record.WSBoolRecord;
import org.apache.poi.hssf.record.WindowTwoRecord;
import org.apache.poi.ss.util.Region;
-import org.apache.poi.util.TempFile;
/**
* Tests HSSFSheet. This test case is very incomplete at the moment.
@@ -54,10 +53,7 @@ public final class TestHSSFSheet extends TestCase {
/**
* Test the gridset field gets set as expected.
*/
-
- public void testBackupRecord()
- throws Exception
- {
+ public void testBackupRecord() {
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet s = wb.createSheet();
Sheet sheet = s.getSheet();
@@ -70,10 +66,7 @@ public final class TestHSSFSheet extends TestCase {
/**
* Test vertically centered output.
*/
-
- public void testVerticallyCenter()
- throws Exception
- {
+ public void testVerticallyCenter() {
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet s = wb.createSheet();
Sheet sheet = s.getSheet();
@@ -90,10 +83,7 @@ public final class TestHSSFSheet extends TestCase {
/**
* Test horizontally centered output.
*/
-
- public void testHorizontallyCenter()
- throws Exception
- {
+ public void testHorizontallyCenter() {
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet s = wb.createSheet();
Sheet sheet = s.getSheet();
@@ -103,16 +93,13 @@ public final class TestHSSFSheet extends TestCase {
assertEquals(false, record.getHCenter());
s.setHorizontallyCenter(true);
assertEquals(true, record.getHCenter());
-
}
/**
* Test WSBboolRecord fields get set in the user model.
*/
-
- public void testWSBool()
- {
+ public void testWSBool() {
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet s = wb.createSheet();
Sheet sheet = s.getSheet();
@@ -158,9 +145,7 @@ public final class TestHSSFSheet extends TestCase {
assertEquals(true, s.getRowSumsRight());
}
- public void testReadBooleans()
- throws Exception
- {
+ public void testReadBooleans() {
HSSFWorkbook workbook = new HSSFWorkbook();
HSSFSheet sheet = workbook.createSheet("Test boolean");
HSSFRow row = sheet.createRow((short) 2);
@@ -168,23 +153,16 @@ public final class TestHSSFSheet extends TestCase {
cell.setCellValue(true);
cell = row.createCell((short) 11);
cell.setCellValue(true);
- File tempFile = TempFile.createTempFile("bool", "test.xls");
- FileOutputStream stream = new FileOutputStream(tempFile);
- workbook.write(stream);
- stream.close();
+
+ workbook = HSSFTestDataSamples.writeOutAndReadBack(workbook);
- FileInputStream readStream = new FileInputStream(tempFile);
- workbook = new HSSFWorkbook(readStream);
sheet = workbook.getSheetAt(0);
row = sheet.getRow(2);
- stream.close();
- tempFile.delete();
assertNotNull(row);
assertEquals(2, row.getPhysicalNumberOfCells());
}
- public void testRemoveRow()
- {
+ public void testRemoveRow() {
HSSFWorkbook workbook = new HSSFWorkbook();
HSSFSheet sheet = workbook.createSheet("Test boolean");
HSSFRow row = sheet.createRow((short) 2);
@@ -197,8 +175,8 @@ public final class TestHSSFSheet extends TestCase {
HSSFRow row = sheet.createRow(0);
HSSFCell cell = row.createCell((short) 0);
HSSFCell cell2 = row.createCell((short) 1);
- cell.setCellValue(new HSSFRichTextString("clone_test"));
- cell2.setCellFormula("sin(1)");
+ cell.setCellValue(new HSSFRichTextString("clone_test"));
+ cell2.setCellFormula("sin(1)");
HSSFSheet clonedSheet = workbook.cloneSheet(0);
HSSFRow clonedRow = clonedSheet.getRow(0);
@@ -234,7 +212,7 @@ public final class TestHSSFSheet extends TestCase {
assertNotNull(workbook.getSheet("Test Clone"));
assertNotNull(workbook.getSheet("Test Clone(1)"));
- assertNotNull(workbook.getSheet("Test Clone(2)"));
+ assertNotNull(workbook.getSheet("Test Clone(2)"));
}
/**
@@ -275,7 +253,7 @@ public final class TestHSSFSheet extends TestCase {
/**
* Setting landscape and portrait stuff on existing sheets
*/
- public void testPrintSetupLandscapeExisting() throws Exception {
+ public void testPrintSetupLandscapeExisting() {
HSSFWorkbook workbook = openSample("SimpleWithPageBreaks.xls");
assertEquals(3, workbook.getNumberOfSheets());
@@ -306,9 +284,7 @@ public final class TestHSSFSheet extends TestCase {
assertEquals(1, sheetLS.getPrintSetup().getCopies());
// Save and re-load, and check still there
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- workbook.write(baos);
- workbook = new HSSFWorkbook(new ByteArrayInputStream(baos.toByteArray()));
+ workbook = HSSFTestDataSamples.writeOutAndReadBack(workbook);
assertTrue(sheetL.getPrintSetup().getLandscape());
assertFalse(sheetPM.getPrintSetup().getLandscape());
@@ -318,7 +294,7 @@ public final class TestHSSFSheet extends TestCase {
assertEquals(1, sheetLS.getPrintSetup().getCopies());
}
- public void testGroupRows() throws Exception {
+ public void testGroupRows() {
HSSFWorkbook workbook = new HSSFWorkbook();
HSSFSheet s = workbook.createSheet();
HSSFRow r1 = s.createRow(0);
@@ -342,11 +318,7 @@ public final class TestHSSFSheet extends TestCase {
assertEquals(0, r5.getOutlineLevel());
// Save and re-open
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- workbook.write(baos);
- workbook = new HSSFWorkbook(
- new ByteArrayInputStream(baos.toByteArray())
- );
+ workbook = HSSFTestDataSamples.writeOutAndReadBack(workbook);
s = workbook.getSheetAt(0);
r1 = s.getRow(0);
@@ -362,7 +334,7 @@ public final class TestHSSFSheet extends TestCase {
assertEquals(0, r5.getOutlineLevel());
}
- public void testGroupRowsExisting() throws Exception {
+ public void testGroupRowsExisting() {
HSSFWorkbook workbook = openSample("NoGutsRecords.xls");
HSSFSheet s = workbook.getSheetAt(0);
@@ -391,11 +363,11 @@ public final class TestHSSFSheet extends TestCase {
assertEquals(0, r6.getOutlineLevel());
// Save and re-open
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- workbook.write(baos);
- workbook = new HSSFWorkbook(
- new ByteArrayInputStream(baos.toByteArray())
- );
+ try {
+ workbook = HSSFTestDataSamples.writeOutAndReadBack(workbook);
+ } catch (OutOfMemoryError e) {
+ throw new AssertionFailedError("Identified bug 39903");
+ }
s = workbook.getSheetAt(0);
r1 = s.getRow(0);
@@ -413,7 +385,7 @@ public final class TestHSSFSheet extends TestCase {
assertEquals(0, r6.getOutlineLevel());
}
- public void testGetDrawings() throws Exception {
+ public void testGetDrawings() {
HSSFWorkbook wb1c = openSample("WithChart.xls");
HSSFWorkbook wb2c = openSample("WithTwoCharts.xls");
@@ -440,7 +412,7 @@ public final class TestHSSFSheet extends TestCase {
HSSFSheet hssfSheet = workbook.createSheet();
Sheet sheet = hssfSheet.getSheet();
ProtectRecord protect = sheet.getProtect();
-
+
assertFalse(protect.getProtect());
// This will tell us that cloneSheet, and by extension,
@@ -454,12 +426,12 @@ public final class TestHSSFSheet extends TestCase {
public void testProtectSheet() {
short expected = (short)0xfef1;
- HSSFWorkbook wb = new HSSFWorkbook();
+ HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet s = wb.createSheet();
s.protectSheet("abcdefghij");
Sheet sheet = s.getSheet();
- ProtectRecord protect = sheet.getProtect();
- PasswordRecord pass = sheet.getPassword();
+ ProtectRecord protect = sheet.getProtect();
+ PasswordRecord pass = sheet.getPassword();
assertTrue("protection should be on",protect.getProtect());
assertTrue("object protection should be on",sheet.isProtected()[1]);
assertTrue("scenario protection should be on",sheet.isProtected()[2]);
@@ -467,9 +439,7 @@ public final class TestHSSFSheet extends TestCase {
}
- public void testZoom()
- throws Exception
- {
+ public void testZoom() {
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet sheet = wb.createSheet();
assertEquals(-1, sheet.getSheet().findFirstRecordLocBySid(SCLRecord.sid));
@@ -482,7 +452,6 @@ public final class TestHSSFSheet extends TestCase {
int sclLoc = sheet.getSheet().findFirstRecordLocBySid(SCLRecord.sid);
int window2Loc = sheet.getSheet().findFirstRecordLocBySid(WindowTwoRecord.sid);
assertTrue(sclLoc == window2Loc + 1);
-
}
@@ -493,7 +462,7 @@ public final class TestHSSFSheet extends TestCase {
public void testRemoveMerged() {
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet sheet = wb.createSheet();
- Region region = new Region(0, (short)0, 1, (short)1);
+ Region region = new Region(0, (short)0, 1, (short)1);
sheet.addMergedRegion(region);
region = new Region(1, (short)0, 2, (short)1);
sheet.addMergedRegion(region);
@@ -522,7 +491,6 @@ public final class TestHSSFSheet extends TestCase {
assertTrue("there isn't more than one merged region in there", 1 <= sheet.getNumMergedRegions());
region = sheet.getMergedRegionAt(0);
assertEquals("the merged row to doesnt match the one we put in ", 4, region.getRowTo());
-
}
public void testShiftMerged() {
@@ -536,33 +504,25 @@ public final class TestHSSFSheet extends TestCase {
cell = row.createCell((short)1);
cell.setCellValue(new HSSFRichTextString("second row, second cell"));
- Region region = new Region(1, (short)0, 1, (short)1);
+ Region region = new Region(1, (short)0, 1, (short)1);
sheet.addMergedRegion(region);
sheet.shiftRows(1, 1, 1);
region = sheet.getMergedRegionAt(0);
assertEquals("Merged region not moved over to row 2", 2, region.getRowFrom());
-
}
/**
* Tests the display of gridlines, formulas, and rowcolheadings.
* @author Shawn Laubach (slaubach at apache dot org)
*/
- public void testDisplayOptions() throws Exception {
+ public void testDisplayOptions() {
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet sheet = wb.createSheet();
- File tempFile = TempFile.createTempFile("display", "test.xls");
- FileOutputStream stream = new FileOutputStream(tempFile);
- wb.write(stream);
- stream.close();
-
- FileInputStream readStream = new FileInputStream(tempFile);
- wb = new HSSFWorkbook(readStream);
+ wb = HSSFTestDataSamples.writeOutAndReadBack(wb);
sheet = wb.getSheetAt(0);
- readStream.close();
assertEquals(sheet.isDisplayGridlines(), true);
assertEquals(sheet.isDisplayRowColHeadings(), true);
@@ -572,16 +532,8 @@ public final class TestHSSFSheet extends TestCase {
sheet.setDisplayRowColHeadings(false);
sheet.setDisplayFormulas(true);
- tempFile = TempFile.createTempFile("display", "test.xls");
- stream = new FileOutputStream(tempFile);
- wb.write(stream);
- stream.close();
-
- readStream = new FileInputStream(tempFile);
- wb = new HSSFWorkbook(readStream);
+ wb = HSSFTestDataSamples.writeOutAndReadBack(wb);
sheet = wb.getSheetAt(0);
- readStream.close();
-
assertEquals(sheet.isDisplayGridlines(), false);
assertEquals(sheet.isDisplayRowColHeadings(), false);
@@ -593,7 +545,7 @@ public final class TestHSSFSheet extends TestCase {
* Make sure the excel file loads work
*
*/
- public void testPageBreakFiles() throws Exception{
+ public void testPageBreakFiles() {
HSSFWorkbook wb = openSample("SimpleWithPageBreaks.xls");
HSSFSheet sheet = wb.getSheetAt(0);
@@ -611,27 +563,19 @@ public final class TestHSSFSheet extends TestCase {
assertEquals("row breaks number", 2, sheet.getRowBreaks().length);
assertEquals("column breaks number", 2, sheet.getColumnBreaks().length);
- File tempFile = TempFile.createTempFile("display", "testPagebreaks.xls");
- FileOutputStream stream = new FileOutputStream(tempFile);
- wb.write(stream);
- stream.close();
-
- wb = new HSSFWorkbook(new FileInputStream(tempFile));
+ wb = HSSFTestDataSamples.writeOutAndReadBack(wb);
sheet = wb.getSheetAt(0);
assertTrue("No row page break", sheet.isRowBroken(22));
assertTrue("No column page break", sheet.isColumnBroken((short)4));
-
assertEquals("row breaks number", 2, sheet.getRowBreaks().length);
assertEquals("column breaks number", 2, sheet.getColumnBreaks().length);
-
-
}
- public void testDBCSName () throws Exception {
+ public void testDBCSName () {
HSSFWorkbook wb = openSample("DBCSSheetName.xls");
- HSSFSheet s= wb.getSheetAt(1);
+ wb.getSheetAt(1);
assertEquals ("DBCS Sheet Name 2", wb.getSheetName(1),"\u090f\u0915" );
assertEquals("DBCS Sheet Name 1", wb.getSheetName(0),"\u091c\u093e");
}
@@ -684,17 +628,15 @@ public final class TestHSSFSheet extends TestCase {
/**
*
*/
- public void testAddEmptyRow() throws Exception {
+ public void testAddEmptyRow() {
//try to add 5 empty rows to a new sheet
HSSFWorkbook workbook = new HSSFWorkbook();
HSSFSheet sheet = workbook.createSheet();
- for (int i = 0; i < 5; i++) sheet.createRow(i);
-
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- workbook.write(out);
- out.close();
+ for (int i = 0; i < 5; i++) {
+ sheet.createRow(i);
+ }
- workbook = new HSSFWorkbook(new ByteArrayInputStream(out.toByteArray()));
+ workbook = HSSFTestDataSamples.writeOutAndReadBack(workbook);
//try adding empty rows in an existing worksheet
workbook = openSample("Simple.xls");
@@ -702,14 +644,10 @@ public final class TestHSSFSheet extends TestCase {
sheet = workbook.getSheetAt(0);
for (int i = 3; i < 10; i++) sheet.createRow(i);
- out = new ByteArrayOutputStream();
- workbook.write(out);
- out.close();
-
- workbook = new HSSFWorkbook(new ByteArrayInputStream(out.toByteArray()));
+ workbook = HSSFTestDataSamples.writeOutAndReadBack(workbook);
}
- public void testAutoSizeColumn() throws Exception {
+ public void testAutoSizeColumn() {
HSSFWorkbook wb = openSample("43902.xls");
String sheetName = "my sheet";
HSSFSheet sheet = wb.getSheet(sheetName);
@@ -719,7 +657,7 @@ public final class TestHSSFSheet extends TestCase {
// machines based on the fonts available.
// So, we use ranges, which are pretty large, but
// thankfully don't overlap!
- int minWithRow1And2 = 6400;
+ int minWithRow1And2 = 6400;
int maxWithRow1And2 = 7800;
int minWithRow1Only = 2750;
int maxWithRow1Only = 3300;
@@ -733,13 +671,10 @@ public final class TestHSSFSheet extends TestCase {
//create a region over the 2nd row and auto size the first column
sheet.addMergedRegion(new Region(1,(short)0,1,(short)1));
sheet.autoSizeColumn((short)0);
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- wb.write(out);
- out.close();
+ HSSFWorkbook wb2 = HSSFTestDataSamples.writeOutAndReadBack(wb);
- // check that the autoSized column width has ignored the 2nd row
+ // check that the autoSized column width has ignored the 2nd row
// because it is included in a merged region (Excel like behavior)
- HSSFWorkbook wb2 = new HSSFWorkbook(new ByteArrayInputStream(out.toByteArray()));
HSSFSheet sheet2 = wb2.getSheet(sheetName);
assertTrue(sheet2.getColumnWidth((short)0) >= minWithRow1Only);
assertTrue(sheet2.getColumnWidth((short)0) <= maxWithRow1Only);
@@ -747,10 +682,7 @@ public final class TestHSSFSheet extends TestCase {
// remove the 2nd row merged region and check that the 2nd row value is used to the autoSizeColumn width
sheet2.removeMergedRegion(1);
sheet2.autoSizeColumn((short)0);
- out = new ByteArrayOutputStream();
- wb2.write(out);
- out.close();
- HSSFWorkbook wb3 = new HSSFWorkbook(new ByteArrayInputStream(out.toByteArray()));
+ HSSFWorkbook wb3 = HSSFTestDataSamples.writeOutAndReadBack(wb2);
HSSFSheet sheet3 = wb3.getSheet(sheetName);
assertTrue(sheet3.getColumnWidth((short)0) >= minWithRow1And2);
assertTrue(sheet3.getColumnWidth((short)0) <= maxWithRow1And2);
@@ -827,7 +759,7 @@ public final class TestHSSFSheet extends TestCase {
assertTrue(wb3.getSheetAt(3).getForceFormulaRecalculation());
}
- public void testColumnWidth() throws Exception {
+ public void testColumnWidth() {
//check we can correctly read column widths from a reference workbook
HSSFWorkbook wb = openSample("colwidth.xls");
@@ -867,11 +799,8 @@ public final class TestHSSFSheet extends TestCase {
}
//serialize and read again
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- wb.write(out);
- out.close();
+ wb = HSSFTestDataSamples.writeOutAndReadBack(wb);
- wb = new HSSFWorkbook(new ByteArrayInputStream(out.toByteArray()));
sh = wb.getSheetAt(0);
assertEquals(10, sh.getDefaultColumnWidth());
//columns A-C have default width
diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFWorkbook.java b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFWorkbook.java
index cb5b3d3554..b9873fa4b6 100644
--- a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFWorkbook.java
+++ b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFWorkbook.java
@@ -20,12 +20,16 @@ package org.apache.poi.hssf.usermodel;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.util.List;
import junit.framework.AssertionFailedError;
import junit.framework.TestCase;
import org.apache.poi.hssf.HSSFTestDataSamples;
+import org.apache.poi.hssf.model.Sheet;
import org.apache.poi.hssf.record.NameRecord;
+import org.apache.poi.hssf.record.Record;
+import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.util.TempFile;
/**
*
@@ -376,4 +380,49 @@ public final class TestHSSFWorkbook extends TestCase {
assertEquals("active", expectedActive, sheet.isActive());
assertEquals("selected", expectedSelected, sheet.isSelected());
}
-}
+
+ /**
+ * If Sheet.getSize() returns a different result to Sheet.serialize(), this will cause the BOF
+ * records to be written with invalid offset indexes. Excel does not like this, and such
+ * errors are particularly hard to track down. This test ensures that HSSFWorkbook throws
+ * a specific exception as soon as the situation is detected. See bugzilla 45066
+ */
+ public void testSheetSerializeSizeMismatch_bug45066() {
+ HSSFWorkbook wb = new HSSFWorkbook();
+ Sheet sheet = wb.createSheet("Sheet1").getSheet();
+ List sheetRecords = sheet.getRecords();
+ // one way (of many) to cause the discrepancy is with a badly behaved record:
+ sheetRecords.add(new BadlyBehavedRecord());
+ // There is also much logic inside Sheet that (if buggy) might also cause the discrepancy
+ try {
+ wb.getBytes();
+ throw new AssertionFailedError("Identified bug 45066 a");
+ } catch (IllegalStateException e) {
+ // Expected badly behaved sheet record to cause exception
+ assertTrue(e.getMessage().startsWith("Actual serialized sheet size"));
+ }
+ }
+ /**
+ * result returned by getRecordSize() differs from result returned by serialize()
+ */
+ private static final class BadlyBehavedRecord extends Record {
+ public BadlyBehavedRecord() {
+ //
+ }
+ protected void fillFields(RecordInputStream in) {
+ throw new RuntimeException("Should not be called");
+ }
+ public short getSid() {
+ return 0x777;
+ }
+ public int serialize(int offset, byte[] data) {
+ return 4;
+ }
+ protected void validateSid(short id) {
+ throw new RuntimeException("Should not be called");
+ }
+ public int getRecordSize() {
+ return 8;
+ }
+ }
+ }
diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestLinkTable.java b/src/testcases/org/apache/poi/hssf/usermodel/TestLinkTable.java
new file mode 100644
index 0000000000..7d1082e861
--- /dev/null
+++ b/src/testcases/org/apache/poi/hssf/usermodel/TestLinkTable.java
@@ -0,0 +1,44 @@
+package org.apache.poi.hssf.usermodel;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.TestCase;
+
+import org.apache.poi.hssf.HSSFTestDataSamples;
+/**
+ * Tests for LinkTable
+ *
+ * @author Josh Micich
+ */
+public final class TestLinkTable extends TestCase {
+
+ /**
+ * The example file attached to bugzilla 45046 is a clear example of Name records being present
+ * without an External Book (SupBook) record. Excel has no trouble reading this file.<br/>
+ * TODO get OOO documentation updated to reflect this (that EXTERNALBOOK is optional).
+ *
+ * It's not clear what exact steps need to be taken in Excel to create such a workbook
+ */
+ public void testLinkTableWithoutExternalBookRecord_bug45046() {
+ HSSFWorkbook wb;
+
+ try {
+ wb = HSSFTestDataSamples.openSampleWorkbook("ex45046-21984.xls");
+ } catch (RuntimeException e) {
+ if ("DEFINEDNAME is part of LinkTable".equals(e.getMessage())) {
+ throw new AssertionFailedError("Identified bug 45046 b");
+ }
+ throw e;
+ }
+ // some other sanity checks
+ assertEquals(3, wb.getNumberOfSheets());
+ String formula = wb.getSheetAt(0).getRow(4).getCell(13).getCellFormula();
+
+ if ("ipcSummenproduktIntern($P5,N$6,$A$9,N$5)".equals(formula)) {
+ // The reported symptom of this bugzilla is an earlier bug (already fixed)
+ throw new AssertionFailedError("Identified bug 41726");
+ // This is observable in version 3.0
+ }
+
+ assertEquals("ipcSummenproduktIntern($C5,N$2,$A$9,N$1)", formula);
+ }
+}
diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestSheetHiding.java b/src/testcases/org/apache/poi/hssf/usermodel/TestSheetHiding.java
index fc2a24b782..62a26e90b5 100644
--- a/src/testcases/org/apache/poi/hssf/usermodel/TestSheetHiding.java
+++ b/src/testcases/org/apache/poi/hssf/usermodel/TestSheetHiding.java
@@ -45,8 +45,8 @@ public final class TestSheetHiding extends TestCase {
*/
public void testTextSheets() throws Exception {
// Both should have two sheets
- assertEquals(2, wbH.sheets.size());
- assertEquals(2, wbU.sheets.size());
+ assertEquals(2, wbH.getNumberOfSheets());
+ assertEquals(2, wbU.getNumberOfSheets());
// All sheets should have one row
assertEquals(0, wbH.getSheetAt(0).getLastRowNum());