Browse Source

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
tags/REL_3_5_BETA2
Nick Burch 16 years ago
parent
commit
877e4efa74
36 changed files with 1590 additions and 1484 deletions
  1. 1
    0
      build.xml
  2. 6
    0
      src/documentation/content/xdocs/changes.xml
  3. 6
    0
      src/documentation/content/xdocs/status.xml
  4. 80
    0
      src/examples/src/org/apache/poi/hslf/usermodel/examples/SoundFinder.java
  5. 6
    0
      src/java/org/apache/poi/POIDocument.java
  6. 42
    50
      src/java/org/apache/poi/hssf/model/FormulaParser.java
  7. 19
    15
      src/java/org/apache/poi/hssf/model/LinkTable.java
  8. 39
    59
      src/java/org/apache/poi/hssf/model/Sheet.java
  9. 1
    2
      src/java/org/apache/poi/hssf/model/Workbook.java
  10. 10
    14
      src/java/org/apache/poi/hssf/record/DBCellRecord.java
  11. 12
    20
      src/java/org/apache/poi/hssf/record/formula/Area3DPtg.java
  12. 9
    30
      src/java/org/apache/poi/hssf/record/formula/AreaPtg.java
  13. 82
    103
      src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java
  14. 58
    45
      src/java/org/apache/poi/hssf/util/AreaReference.java
  15. 113
    163
      src/java/org/apache/poi/hssf/util/HSSFColor.java
  16. 3
    1
      src/java/org/apache/poi/ss/usermodel/DateUtil.java
  17. 6
    4
      src/resources/main/org/apache/poi/hssf/record/formula/function/functionMetadata-asGenerated.txt
  18. 2
    4
      src/resources/main/org/apache/poi/hssf/record/formula/function/functionMetadata.txt
  19. 12
    3
      src/scratchpad/src/org/apache/poi/hdgf/HDGFDiagram.java
  20. 18
    14
      src/scratchpad/src/org/apache/poi/hwpf/model/FSPATable.java
  21. 10
    0
      src/scratchpad/src/org/apache/poi/hwpf/model/FileInformationBlock.java
  22. 8
    0
      src/scratchpad/src/org/apache/poi/hwpf/model/TextPiece.java
  23. 56
    0
      src/scratchpad/src/org/apache/poi/hwpf/usermodel/Range.java
  24. BIN
      src/testcases/org/apache/poi/hssf/data/ex45046-21984.xls
  25. 731
    791
      src/testcases/org/apache/poi/hssf/model/TestFormulaParser.java
  26. 21
    0
      src/testcases/org/apache/poi/hssf/model/TestSheet.java
  27. 60
    31
      src/testcases/org/apache/poi/hssf/record/formula/function/ExcelFileFormatDocFunctionExtractor.java
  28. 2
    3
      src/testcases/org/apache/poi/hssf/record/formula/function/TestParseMissingBuiltInFuncs.java
  29. 4
    8
      src/testcases/org/apache/poi/hssf/record/formula/function/TestReadMissingBuiltInFuncs.java
  30. 2
    1
      src/testcases/org/apache/poi/hssf/usermodel/AllUserModelTests.java
  31. 24
    0
      src/testcases/org/apache/poi/hssf/usermodel/TestHSSFCell.java
  32. 2
    0
      src/testcases/org/apache/poi/hssf/usermodel/TestHSSFDateUtil.java
  33. 49
    120
      src/testcases/org/apache/poi/hssf/usermodel/TestHSSFSheet.java
  34. 50
    1
      src/testcases/org/apache/poi/hssf/usermodel/TestHSSFWorkbook.java
  35. 44
    0
      src/testcases/org/apache/poi/hssf/usermodel/TestLinkTable.java
  36. 2
    2
      src/testcases/org/apache/poi/hssf/usermodel/TestSheetHiding.java

+ 1
- 0
build.xml View File

@@ -245,6 +245,7 @@ under the License.
<path id="examples.classpath">
<path refid="main.classpath"/>
<pathelement location="${main.output.dir}"/>
<pathelement location="${scratchpad.output.dir}"/>
</path>



+ 6
- 0
src/documentation/content/xdocs/changes.xml View File

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

+ 6
- 0
src/documentation/content/xdocs/status.xml View File

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

+ 80
- 0
src/examples/src/org/apache/poi/hslf/usermodel/examples/SoundFinder.java View File

@@ -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;
}
}

+ 6
- 0
src/java/org/apache/poi/POIDocument.java View File

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

+ 42
- 50
src/java/org/apache/poi/hssf/model/FormulaParser.java View File

@@ -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");
}

+ 19
- 15
src/java/org/apache/poi/hssf/model/LinkTable.java View File

@@ -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;
}
}

+ 39
- 59
src/java/org/apache/poi/hssf/model/Sheet.java View File

@@ -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;
}

/**

+ 1
- 2
src/java/org/apache/poi/hssf/model/Workbook.java View File

@@ -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 :

+ 10
- 14
src/java/org/apache/poi/hssf/record/DBCellRecord.java View File

@@ -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()

+ 12
- 20
src/java/org/apache/poi/hssf/record/formula/Area3DPtg.java View File

@@ -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;

+ 9
- 30
src/java/org/apache/poi/hssf/record/formula/AreaPtg.java View File

@@ -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() {

+ 82
- 103
src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java View File

@@ -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;
}


+ 58
- 45
src/java/org/apache/poi/hssf/util/AreaReference.java View File

@@ -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(" [");

+ 113
- 163
src/java/org/apache/poi/hssf/util/HSSFColor.java View File

@@ -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;
}

+ 3
- 1
src/java/org/apache/poi/ss/usermodel/DateUtil.java View File

@@ -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;
}

+ 6
- 4
src/resources/main/org/apache/poi/hssf/record/formula/function/functionMetadata-asGenerated.txt View File

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

+ 2
- 4
src/resources/main/org/apache/poi/hssf/record/formula/function/functionMetadata.txt View File

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

+ 12
- 3
src/scratchpad/src/org/apache/poi/hdgf/HDGFDiagram.java View File

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

+ 18
- 14
src/scratchpad/src/org/apache/poi/hwpf/model/FSPATable.java View File

@@ -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");

+ 10
- 0
src/scratchpad/src/org/apache/poi/hwpf/model/FileInformationBlock.java View File

@@ -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();

+ 8
- 0
src/scratchpad/src/org/apache/poi/hwpf/model/TextPiece.java View File

@@ -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);

+ 56
- 0
src/scratchpad/src/org/apache/poi/hwpf/usermodel/Range.java View File

@@ -226,6 +226,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.
*
@@ -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));
}

/**
@@ -827,6 +859,19 @@ public class Range
_sectionRangeFound = false;
}

/**
* 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
@@ -834,6 +879,7 @@ public class Range
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;
}
}

BIN
src/testcases/org/apache/poi/hssf/data/ex45046-21984.xls View File


+ 731
- 791
src/testcases/org/apache/poi/hssf/model/TestFormulaParser.java
File diff suppressed because it is too large
View File


+ 21
- 0
src/testcases/org/apache/poi/hssf/model/TestSheet.java View File

@@ -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);
}
}


+ 60
- 31
src/testcases/org/apache/poi/hssf/record/formula/function/ExcelFileFormatDocFunctionExtractor.java View File

@@ -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();
}
}

+ 2
- 3
src/testcases/org/apache/poi/hssf/record/formula/function/TestParseMissingBuiltInFuncs.java View File

@@ -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() {

+ 4
- 8
src/testcases/org/apache/poi/hssf/record/formula/function/TestReadMissingBuiltInFuncs.java View File

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

+ 2
- 1
src/testcases/org/apache/poi/hssf/usermodel/AllUserModelTests.java View File

@@ -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);

+ 24
- 0
src/testcases/org/apache/poi/hssf/usermodel/TestHSSFCell.java View File

@@ -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.
*/

+ 2
- 0
src/testcases/org/apache/poi/hssf/usermodel/TestHSSFDateUtil.java View File

@@ -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]) );

+ 49
- 120
src/testcases/org/apache/poi/hssf/usermodel/TestHSSFSheet.java View File

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

+ 50
- 1
src/testcases/org/apache/poi/hssf/usermodel/TestHSSFWorkbook.java View File

@@ -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;
}
}
}

+ 44
- 0
src/testcases/org/apache/poi/hssf/usermodel/TestLinkTable.java View File

@@ -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);
}
}

+ 2
- 2
src/testcases/org/apache/poi/hssf/usermodel/TestSheetHiding.java View File

@@ -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());

Loading…
Cancel
Save