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
This commit is contained in:
Nick Burch 2008-05-23 09:48:23 +00:00
parent d643dc1cf1
commit 877e4efa74
36 changed files with 1592 additions and 1486 deletions

View File

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

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> <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>
<release version="3.1-final" date="2008-06-??"> <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">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="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> <action dev="POI-DEVELOPERS" type="fix">44824 - Avoid an infinite loop when reading some HWPF pictures</action>

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> <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>
<release version="3.1-final" date="2008-06-??"> <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">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="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> <action dev="POI-DEVELOPERS" type="fix">44824 - Avoid an infinite loop when reading some HWPF pictures</action>

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

View File

@ -20,6 +20,7 @@ package org.apache.poi;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; 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"); 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 * Copies nodes from one POIFS to the other minus the excepts

View File

@ -55,7 +55,7 @@ public final class FormulaParser {
*/ */
static final class FormulaParseException extends RuntimeException { static final class FormulaParseException extends RuntimeException {
// This class was given package scope until it would become clear that it is useful to // 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) { public FormulaParseException(String msg) {
super(msg); super(msg);
} }
@ -127,42 +127,34 @@ public final class FormulaParser {
// Just return if so and reset 'look' to something to keep // Just return if so and reset 'look' to something to keep
// SkipWhitespace from spinning // SkipWhitespace from spinning
look = (char)0; look = (char)0;
} }
pointer++; pointer++;
//System.out.println("Got char: "+ look); //System.out.println("Got char: "+ look);
} }
/** Report What Was Expected */ /** Report What Was Expected */
private RuntimeException expected(String s) { 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 " + " in specified formula '" + formulaString + "'. Expected "
+ s; + s;
return new FormulaParseException(msg); return new FormulaParseException(msg);
} }
/** Recognize an Alpha Character */ /** Recognize an Alpha Character */
private boolean IsAlpha(char c) { private boolean IsAlpha(char c) {
return Character.isLetter(c) || c == '$' || c=='_'; return Character.isLetter(c) || c == '$' || c=='_';
} }
/** Recognize a Decimal Digit */ /** Recognize a Decimal Digit */
private boolean IsDigit(char c) { private boolean IsDigit(char c) {
//System.out.println("Checking digit for"+c);
return Character.isDigit(c); return Character.isDigit(c);
} }
/** Recognize an Alphanumeric */ /** Recognize an Alphanumeric */
private boolean IsAlNum(char c) { private boolean IsAlNum(char c) {
return (IsAlpha(c) || IsDigit(c)); return (IsAlpha(c) || IsDigit(c));
} }
/** Recognize White Space */ /** Recognize White Space */
private boolean IsWhite( char c) { private boolean IsWhite( char c) {
return (c ==' ' || c== TAB); 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 * 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 * unchecked exception. This method does <b>not</b> consume whitespace (before or after the
* matched character). * matched character).
*/ */
private void Match(char x) { private void Match(char x) {
if (look != x) { if (look != x) {
@ -218,7 +210,6 @@ public final class FormulaParser {
return Token.toString(); return Token.toString();
} }
/** Get a Number */ /** Get a Number */
private String GetNum() { private String GetNum() {
StringBuffer value = new StringBuffer(); StringBuffer value = new StringBuffer();
@ -281,18 +272,18 @@ public final class FormulaParser {
// This can be either a cell ref or a named range // This can be either a cell ref or a named range
// Try to spot which it is // Try to spot which it is
boolean cellRef = CELL_REFERENCE_PATTERN.matcher(name).matches(); boolean cellRef = CELL_REFERENCE_PATTERN.matcher(name).matches();
if (cellRef) { if (cellRef) {
return new ReferencePtg(name); return new ReferencePtg(name);
} }
for(int i = 0; i < book.getNumberOfNames(); i++) { for(int i = 0; i < book.getNumberOfNames(); i++) {
// named range name matching is case insensitive // 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); 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!"); + 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 * 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 * 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. * Excel function, and has not been encountered before.
* *
* @param name case preserved function name (as it was entered/appeared in the formula). * @param name case preserved function name (as it was entered/appeared in the formula).
*/ */
private Ptg function(String name) { private Ptg function(String name) {
int numArgs =0 ; int numArgs =0 ;
// Note regarding parameter - // Note regarding parameter -
if(!AbstractFunctionPtg.isInternalFunctionName(name)) { if(!AbstractFunctionPtg.isInternalFunctionName(name)) {
// external functions get a Name token which points to a defined name record // external functions get a Name token which points to a defined name record
NamePtg nameToken = new NamePtg(name, this.book); NamePtg nameToken = new NamePtg(name, this.book);
// in the token tree, the name is more or less the first argument // in the token tree, the name is more or less the first argument
numArgs++; numArgs++;
tokens.add(nameToken); tokens.add(nameToken);
} }
//average 2 args per function //average 2 args per function
@ -477,26 +468,25 @@ public final class FormulaParser {
private static boolean isArgumentDelimiter(char ch) { private static boolean isArgumentDelimiter(char ch) {
return ch == ',' || ch == ')'; return ch == ',' || ch == ')';
} }
/** get arguments to a function */ /** get arguments to a function */
private int Arguments(List argumentPointers) { private int Arguments(List argumentPointers) {
SkipWhite(); SkipWhite();
if(look == ')') { if(look == ')') {
return 0; return 0;
} }
boolean missedPrevArg = true; boolean missedPrevArg = true;
int numArgs = 0; int numArgs = 0;
while(true) { while (true) {
SkipWhite(); SkipWhite();
if(isArgumentDelimiter(look)) { if (isArgumentDelimiter(look)) {
if(missedPrevArg) { if (missedPrevArg) {
tokens.add(new MissingArgPtg()); tokens.add(new MissingArgPtg());
addArgumentPointer(argumentPointers); addArgumentPointer(argumentPointers);
numArgs++; numArgs++;
} }
if(look == ')') { if (look == ')') {
break; break;
} }
Match(','); Match(',');
@ -507,6 +497,10 @@ public final class FormulaParser {
addArgumentPointer(argumentPointers); addArgumentPointer(argumentPointers);
numArgs++; numArgs++;
missedPrevArg = false; missedPrevArg = false;
SkipWhite();
if (!isArgumentDelimiter(look)) {
throw expected("',' or ')'");
}
} }
return numArgs; return numArgs;
} }
@ -524,7 +518,7 @@ public final class FormulaParser {
tokens.add(new PowerPtg()); tokens.add(new PowerPtg());
} }
} }
private void percentFactor() { private void percentFactor() {
tokens.add(parseSimpleFactor()); tokens.add(parseSimpleFactor());
while(true) { while(true) {
@ -536,8 +530,8 @@ public final class FormulaParser {
tokens.add(new PercentPtg()); tokens.add(new PercentPtg());
} }
} }
/** /**
* factors (without ^ or % ) * factors (without ^ or % )
*/ */
@ -561,9 +555,6 @@ public final class FormulaParser {
return new ParenthesisPtg(); return new ParenthesisPtg();
case '"': case '"':
return parseStringLiteral(); return parseStringLiteral();
case ',':
case ')':
return new MissingArgPtg(); // TODO - not quite the right place to recognise a missing arg
} }
if (IsAlpha(look) || look == '\''){ if (IsAlpha(look) || look == '\''){
return parseIdent(); return parseIdent();
@ -707,10 +698,9 @@ public final class FormulaParser {
} }
private StringPtg parseStringLiteral() private StringPtg parseStringLiteral() {
{
Match('"'); Match('"');
StringBuffer token = new StringBuffer(); StringBuffer token = new StringBuffer();
while (true) { while (true) {
if (look == '"') { if (look == '"') {
@ -745,7 +735,7 @@ public final class FormulaParser {
return; // finished with Term return; // finished with Term
} }
} }
private void comparisonExpression() { private void comparisonExpression() {
concatExpression(); concatExpression();
while (true) { while (true) {
@ -787,7 +777,7 @@ public final class FormulaParser {
} }
return new LessThanPtg(); return new LessThanPtg();
} }
private void concatExpression() { private void concatExpression() {
additiveExpression(); additiveExpression();
@ -801,7 +791,7 @@ public final class FormulaParser {
tokens.add(new ConcatPtg()); tokens.add(new ConcatPtg());
} }
} }
/** Parse and Translate an Expression */ /** Parse and Translate an Expression */
private void additiveExpression() { 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() { public void parse() {
pointer=0; pointer=0;
@ -847,8 +838,8 @@ end;
comparisonExpression(); comparisonExpression();
if(pointer <= formulaLength) { if(pointer <= formulaLength) {
String msg = "Unused input [" + formulaString.substring(pointer-1) String msg = "Unused input [" + formulaString.substring(pointer-1)
+ "] after attempting to parse the formula [" + formulaString + "]"; + "] after attempting to parse the formula [" + formulaString + "]";
throw new FormulaParseException(msg); throw new FormulaParseException(msg);
} }
} }
@ -863,11 +854,12 @@ end;
* a result of the parsing * a result of the parsing
*/ */
public Ptg[] getRPNPtg() { public Ptg[] getRPNPtg() {
return getRPNPtg(FORMULA_TYPE_CELL); return getRPNPtg(FORMULA_TYPE_CELL);
} }
public Ptg[] getRPNPtg(int formulaType) { public Ptg[] getRPNPtg(int formulaType) {
Node node = createTree(); Node node = createTree();
// RVA is for 'operand class': 'reference', 'value', 'array'
setRootLevelRVA(node, formulaType); setRootLevelRVA(node, formulaType);
setParameterRVA(node,formulaType); setParameterRVA(node,formulaType);
return (Ptg[]) tokens.toArray(new Ptg[0]); 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. * other toFormulaString signature.
* @param book workbook for 3D and named references * @param book workbook for 3D and named references
* @param lptgs list of Ptg, can be null or empty * @param lptgs list of Ptg, can be null or empty
@ -963,7 +955,7 @@ end;
return retval; 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 * other toFormulaString signature. Works on the current
* workbook for 3D and named references * workbook for 3D and named references
* @param lptgs list of Ptg, can be null or empty * @param lptgs list of Ptg, can be null or empty
@ -1011,7 +1003,7 @@ end;
continue; continue;
// but if it ever did, care must be taken: // but if it ever did, care must be taken:
// tAttrSpace comes *before* the operand it applies to, which may be consistent // 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()) { if (attrPtg.isSemiVolatile()) {
// similar to tAttrSpace - RPN is violated // similar to tAttrSpace - RPN is violated
@ -1038,7 +1030,7 @@ end;
stack.push(o.toFormulaString(operands)); stack.push(o.toFormulaString(operands));
} }
if(stack.isEmpty()) { 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. // stack.push(). So this is either an internal error or impossible.
throw new IllegalStateException("Stack underflow"); throw new IllegalStateException("Stack underflow");
} }

View File

@ -41,7 +41,7 @@ import org.apache.poi.hssf.record.SupBookRecord;
* *
* In BIFF8 the Link Table consists of * In BIFF8 the Link Table consists of
* <ul> * <ul>
* <li>one or more EXTERNALBOOK Blocks<p/> * <li>zero or more EXTERNALBOOK Blocks<p/>
* each consisting of * each consisting of
* <ul> * <ul>
* <li>exactly one EXTERNALBOOK (0x01AE) record</li> * <li>exactly one EXTERNALBOOK (0x01AE) record</li>
@ -55,7 +55,7 @@ import org.apache.poi.hssf.record.SupBookRecord;
* </li> * </li>
* </ul> * </ul>
* </li> * </li>
* <li>exactly one EXTERNSHEET (0x0017) record</li> * <li>zero or one EXTERNSHEET (0x0017) record</li>
* <li>zero or more DEFINEDNAME (0x0018) records</li> * <li>zero or more DEFINEDNAME (0x0018) records</li>
* </ul> * </ul>
* *
@ -63,6 +63,7 @@ import org.apache.poi.hssf.record.SupBookRecord;
* @author Josh Micich * @author Josh Micich
*/ */
final class LinkTable { final class LinkTable {
// TODO make this class into a record aggregate
private static final class CRNBlock { private static final class CRNBlock {
@ -79,8 +80,8 @@ final class LinkTable {
_crns = crns; _crns = crns;
} }
public CRNRecord[] getCrns() { public CRNRecord[] getCrns() {
return (CRNRecord[]) _crns.clone(); return (CRNRecord[]) _crns.clone();
} }
} }
private static final class ExternalBookBlock { private static final class ExternalBookBlock {
@ -136,16 +137,19 @@ final class LinkTable {
while(rs.peekNextClass() == SupBookRecord.class) { while(rs.peekNextClass() == SupBookRecord.class) {
temp.add(new ExternalBookBlock(rs)); temp.add(new ExternalBookBlock(rs));
} }
if(temp.size() < 1) {
throw new RuntimeException("Need at least one EXTERNALBOOK blocks");
}
_externalBookBlocks = new ExternalBookBlock[temp.size()]; _externalBookBlocks = new ExternalBookBlock[temp.size()];
temp.toArray(_externalBookBlocks); temp.toArray(_externalBookBlocks);
temp.clear(); temp.clear();
// If link table is present, there is always 1 of ExternSheetRecord if (_externalBookBlocks.length > 0) {
Record next = rs.getNext(); // If any ExternalBookBlock present, there is always 1 of ExternSheetRecord
_externSheetRecord = (ExternSheetRecord)next; Record next = rs.getNext();
_externSheetRecord = (ExternSheetRecord) next;
} else {
_externSheetRecord = null;
}
_definedNames = new ArrayList(); _definedNames = new ArrayList();
// collect zero or more DEFINEDNAMEs id=0x18 // collect zero or more DEFINEDNAMEs id=0x18
while(rs.peekNextClass() == NameRecord.class) { while(rs.peekNextClass() == NameRecord.class) {
@ -222,7 +226,7 @@ final class LinkTable {
public void addName(NameRecord name) { public void addName(NameRecord name) {
_definedNames.add(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 // Not the most efficient way but the other way was causing too many bugs
int idx = findFirstRecordLocBySid(ExternSheetRecord.sid); int idx = findFirstRecordLocBySid(ExternSheetRecord.sid);
if (idx == -1) idx = findFirstRecordLocBySid(SupBookRecord.sid); if (idx == -1) idx = findFirstRecordLocBySid(SupBookRecord.sid);
@ -242,8 +246,8 @@ final class LinkTable {
public int getSheetIndexFromExternSheetIndex(int externSheetNumber) { public int getSheetIndexFromExternSheetIndex(int externSheetNumber) {
if (externSheetNumber >= _externSheetRecord.getNumOfREFStructures()) { if (externSheetNumber >= _externSheetRecord.getNumOfREFStructures()) {
return -1; return -1;
} }
return _externSheetRecord.getREFRecordAt(externSheetNumber).getIndexToFirstSupBook(); return _externSheetRecord.getREFRecordAt(externSheetNumber).getIndexToFirstSupBook();
} }
@ -265,7 +269,7 @@ final class LinkTable {
ExternSheetSubRecord esr = _externSheetRecord.getREFRecordAt(i); ExternSheetSubRecord esr = _externSheetRecord.getREFRecordAt(i);
if (esr.getIndexToFirstSupBook() == sheetNumber if (esr.getIndexToFirstSupBook() == sheetNumber
&& esr.getIndexToLastSupBook() == sheetNumber){ && esr.getIndexToLastSupBook() == sheetNumber){
return i; return i;
} }
} }

View File

@ -96,8 +96,8 @@ public final class Sheet implements Model {
protected List condFormatting = new ArrayList(); protected List condFormatting = new ArrayList();
/** Add an UncalcedRecord if not true indicating formulas have not been calculated */ /** 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_LOWER_RIGHT = (byte)0;
public static final byte PANE_UPPER_RIGHT = (byte)1; public static final byte PANE_UPPER_RIGHT = (byte)1;
public static final byte PANE_LOWER_LEFT = (byte)2; 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) { else if (rec.getSid() == UncalcedRecord.sid) {
retval.uncalced = true; retval._isUncalced = true;
} }
else if (rec.getSid() == DimensionsRecord.sid) else if (rec.getSid() == DimensionsRecord.sid)
{ {
@ -329,16 +329,8 @@ public final class Sheet implements Model {
} }
} }
retval.records = records; retval.records = records;
// if (retval.rows == null)
// {
// retval.rows = new RowRecordsAggregate();
// }
retval.checkCells(); retval.checkCells();
retval.checkRows(); retval.checkRows();
// if (retval.cells == null)
// {
// retval.cells = new ValueRecordsAggregate();
// }
if (log.check( POILogger.DEBUG )) if (log.check( POILogger.DEBUG ))
log.log(POILogger.DEBUG, "sheet createSheet (existing file) exited"); log.log(POILogger.DEBUG, "sheet createSheet (existing file) exited");
return retval; return retval;
@ -816,17 +808,17 @@ public final class Sheet implements Model {
// Once the rows have been found in the list of records, start // Once the rows have been found in the list of records, start
// writing out the blocked row information. This includes the DBCell references // writing out the blocked row information. This includes the DBCell references
if (record instanceof RowRecordsAggregate) { 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) { } else if (record instanceof ValueRecordsAggregate) {
//Do nothing here. The records were serialized during the RowRecordAggregate block serialization //Do nothing here. The records were serialized during the RowRecordAggregate block serialization
} else { } 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 the BOF record was just serialized then add the IndexRecord
if (record.getSid() == BOFRecord.sid) { if (record.getSid() == BOFRecord.sid) {
// Add an optional UncalcedRecord // Add an optional UncalcedRecord
if (uncalced) { if (_isUncalced) {
UncalcedRecord rec = new UncalcedRecord(); UncalcedRecord rec = new UncalcedRecord();
pos += rec.serialize(pos, data); pos += rec.serialize(pos, data);
} }
@ -837,31 +829,10 @@ public final class Sheet implements Model {
pos += serializeIndexRecord(k, pos, data); 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 "); log.log(POILogger.DEBUG, "Sheet.serialize returning ");
}
return pos-offset; return pos-offset;
} }
@ -875,10 +846,17 @@ public final class Sheet implements Model {
for (int j = BOFRecordIndex+1; j < records.size(); j++) for (int j = BOFRecordIndex+1; j < records.size(); j++)
{ {
Record tmpRec = (( Record ) records.get(j)); Record tmpRec = (( Record ) records.get(j));
if (tmpRec instanceof RowRecordsAggregate) if (tmpRec instanceof UncalcedRecord) {
break; continue;
}
if (tmpRec instanceof RowRecordsAggregate) {
break;
}
sheetRecSize+= tmpRec.getRecordSize(); sheetRecSize+= tmpRec.getRecordSize();
} }
if (_isUncalced) {
sheetRecSize += UncalcedRecord.getStaticRecordSize();
}
//Add the references to the DBCells in the IndexRecord (one for each block) //Add the references to the DBCells in the IndexRecord (one for each block)
int blockCount = rows.getRowBlockCount(); int blockCount = rows.getRowBlockCount();
//Calculate the size of this IndexRecord //Calculate the size of this IndexRecord
@ -2017,31 +1995,33 @@ public final class Sheet implements Model {
{ {
int retval = 0; int retval = 0;
for ( int k = 0; k < records.size(); k++ ) for ( int k = 0; k < records.size(); k++) {
{ Record record = (Record) records.get(k);
retval += ( (Record) records.get( k ) ).getRecordSize(); if (record instanceof UncalcedRecord) {
} // skip the UncalcedRecord if present, it's only encoded if the isUncalced flag is set
//Add space for the IndexRecord continue;
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;
} }
retval += record.getRecordSize();
}
if (rows != null) {
// 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 // Add space for UncalcedRecord
if (uncalced) { if (_isUncalced) {
retval += UncalcedRecord.getStaticRecordSize(); retval += UncalcedRecord.getStaticRecordSize();
} }
return retval; return retval;
} }
@ -2518,13 +2498,13 @@ public final class Sheet implements Model {
* @return whether an uncalced record must be inserted or not at generation * @return whether an uncalced record must be inserted or not at generation
*/ */
public boolean getUncalced() { public boolean getUncalced() {
return uncalced; return _isUncalced;
} }
/** /**
* @param uncalced whether an uncalced record must be inserted or not at generation * @param uncalced whether an uncalced record must be inserted or not at generation
*/ */
public void setUncalced(boolean uncalced) { public void setUncalced(boolean uncalced) {
this.uncalced = uncalced; this._isUncalced = uncalced;
} }
/** /**

View File

@ -191,12 +191,11 @@ public class Workbook implements Model
case ExternSheetRecord.sid : case ExternSheetRecord.sid :
throw new RuntimeException("Extern sheet is part of LinkTable"); throw new RuntimeException("Extern sheet is part of LinkTable");
case NameRecord.sid : case NameRecord.sid :
throw new RuntimeException("DEFINEDNAME is part of LinkTable");
case SupBookRecord.sid : case SupBookRecord.sid :
// LinkTable can start with either of these
if (log.check( POILogger.DEBUG )) if (log.check( POILogger.DEBUG ))
log.log(DEBUG, "found SupBook record at " + k); log.log(DEBUG, "found SupBook record at " + k);
retval.linkTable = new LinkTable(recs, k, retval.records); retval.linkTable = new LinkTable(recs, k, retval.records);
// retval.records.supbookpos = k;
k+=retval.linkTable.getRecordCount() - 1; k+=retval.linkTable.getRecordCount() - 1;
continue; continue;
case FormatRecord.sid : case FormatRecord.sid :

View File

@ -1,4 +1,3 @@
/* ==================================================================== /* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with contributor license agreements. See the NOTICE file distributed with
@ -15,7 +14,6 @@
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
==================================================================== */ ==================================================================== */
package org.apache.poi.hssf.record; package org.apache.poi.hssf.record;
@ -29,10 +27,7 @@ import org.apache.poi.util.LittleEndian;
* @author Jason Height * @author Jason Height
* @version 2.0-pre * @version 2.0-pre
*/ */
public final class DBCellRecord extends Record {
public class DBCellRecord
extends Record
{
public final static int BLOCK_SIZE = 32; public final static int BLOCK_SIZE = 32;
public final static short sid = 0xd7; public final static short sid = 0xd7;
private int field_1_row_offset; private int field_1_row_offset;
@ -46,7 +41,6 @@ public class DBCellRecord
* Constructs a DBCellRecord and sets its fields appropriately * Constructs a DBCellRecord and sets its fields appropriately
* @param in the RecordInputstream to read the record from * @param in the RecordInputstream to read the record from
*/ */
public DBCellRecord(RecordInputStream in) public DBCellRecord(RecordInputStream in)
{ {
super(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 * @param offset offset to the start of the first cell in the next DBCell block
*/ */
public void setRowOffset(int offset) public void setRowOffset(int offset)
{ {
field_1_row_offset = 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 * @return rowoffset to the start of the first cell in the next DBCell block
*/ */
public int getRowOffset() public int getRowOffset()
{ {
return field_1_row_offset; return field_1_row_offset;
@ -120,7 +112,6 @@ public class DBCellRecord
* @param index of the cell offset to retrieve * @param index of the cell offset to retrieve
* @return celloffset from the celloffset array * @return celloffset from the celloffset array
*/ */
public short getCellOffsetAt(int index) public short getCellOffsetAt(int index)
{ {
return field_2_cell_offsets[ index ]; return field_2_cell_offsets[ index ];
@ -131,7 +122,6 @@ public class DBCellRecord
* *
* @return number of cell offsets * @return number of cell offsets
*/ */
public int getNumCellOffsets() public int getNumCellOffsets()
{ {
return field_2_cell_offsets.length; return field_2_cell_offsets.length;
@ -175,9 +165,15 @@ public class DBCellRecord
return 8 + (getNumCellOffsets() * 2); 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) { * @returns the size of the group of <tt>DBCellRecord</tt>s needed to encode
return 8 + (rows * 2); * 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() public short getSid()

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> * Description: Defined a area in Extern Sheet. <P>
* REFERENCE: <P> * REFERENCE: <P>
* @author Libin Roman (Vista Portal LDT. Developer) * @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) * @author Jason Height (jheight at chariot dot net dot au)
* @version 1.0-pre * @version 1.0-pre
*/ */
public class Area3DPtg extends Ptg implements AreaI public class Area3DPtg extends Ptg implements AreaI
{ {
public final static byte sid = 0x3b; public final static byte sid = 0x3b;
@ -84,23 +83,15 @@ public class Area3DPtg extends Ptg implements AreaI
setExternSheetIndex(externalSheetIndex); setExternSheetIndex(externalSheetIndex);
} }
public String toString() public String toString() {
{ StringBuffer sb = new StringBuffer();
StringBuffer buffer = new StringBuffer(); sb.append(getClass().getName());
sb.append(" [");
buffer.append( "AreaPtg\n" ); sb.append("sheetIx=").append(getExternSheetIndex());
buffer.append( "Index to Extern Sheet = " + getExternSheetIndex() ).append( "\n" ); sb.append(" ! ");
buffer.append( "firstRow = " + getFirstRow() ).append( "\n" ); sb.append(AreaReference.formatAsString(this));
buffer.append( "lastRow = " + getLastRow() ).append( "\n" ); sb.append("]");
buffer.append( "firstCol = " + getFirstColumn() ).append( "\n" ); return sb.toString();
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 void writeBytes( byte[] array, int offset ) public void writeBytes( byte[] array, int offset )
@ -284,7 +275,7 @@ public class Area3DPtg extends Ptg implements AreaI
} }
// Now the normal area bit // Now the normal area bit
retval.append( AreaPtg.toFormulaString(this, book) ); retval.append(AreaReference.formatAsString(this));
// All done // All done
return retval.toString(); return retval.toString();
@ -326,6 +317,7 @@ public class Area3DPtg extends Ptg implements AreaI
public int hashCode() public int hashCode()
{ {
// TODO - hashCode seems to be unused
int result; int result;
result = (int) field_1_index_extern_sheet; result = (int) field_1_index_extern_sheet;
result = 29 * result + (int) field_2_first_row; result = 29 * result + (int) field_2_first_row;

View File

@ -114,23 +114,13 @@ public class AreaPtg extends Ptg implements AreaI {
return "AreaPtg"; return "AreaPtg";
} }
public String toString() public String toString() {
{ StringBuffer sb = new StringBuffer();
StringBuffer buffer = new StringBuffer(); sb.append(getClass().getName());
sb.append(" [");
buffer.append(getAreaPtgName()); sb.append(AreaReference.formatAsString(this));
buffer.append("\n"); sb.append("]");
buffer.append("firstRow = " + getFirstRow()).append("\n"); return sb.toString();
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 void writeBytes(byte [] array, int offset) { public void writeBytes(byte [] array, int offset) {
@ -307,19 +297,8 @@ public class AreaPtg extends Ptg implements AreaI {
field_4_last_column = column; field_4_last_column = column;
} }
public String toFormulaString(Workbook book) public String toFormulaString(Workbook book) {
{ return AreaReference.formatAsString(this);
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 byte getDefaultOperandClass() { public byte getDefaultOperandClass() {

View File

@ -15,12 +15,6 @@
limitations under the License. limitations under the License.
==================================================================== */ ==================================================================== */
/*
* HSSFWorkbook.java
*
* Created on September 30, 2001, 3:37 PM
*/
package org.apache.poi.hssf.usermodel; package org.apache.poi.hssf.usermodel;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
@ -81,7 +75,6 @@ import org.apache.poi.util.POILogger;
* @author Shawn Laubach (slaubach at apache dot org) * @author Shawn Laubach (slaubach at apache dot org)
* @version 2.0-pre * @version 2.0-pre
*/ */
public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.usermodel.Workbook public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.usermodel.Workbook
{ {
private static final int DEBUG = POILogger.DEBUG; 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 * this holds the HSSFSheet objects attached to this workbook
*/ */
protected ArrayList sheets; protected List _sheets;
/** /**
* this holds the HSSFName objects attached to this workbook * 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); super(null, null);
workbook = book; workbook = book;
sheets = new ArrayList( INITIAL_CAPACITY ); _sheets = new ArrayList( INITIAL_CAPACITY );
names = 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; this.directory = null;
} }
sheets = new ArrayList(INITIAL_CAPACITY); _sheets = new ArrayList(INITIAL_CAPACITY);
names = new ArrayList(INITIAL_CAPACITY); names = new ArrayList(INITIAL_CAPACITY);
// Grab the data from the workbook stream, however // 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); HSSFSheet hsheet = new HSSFSheet(this, sheet);
sheets.add(hsheet); _sheets.add(hsheet);
// workbook.setSheetName(sheets.size() -1, "Sheet"+sheets.size()); // 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 ) { 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); workbook.setSheetOrder(sheetname, pos);
} }
private void validateSheetIndex(int index) { private void validateSheetIndex(int index) {
int lastSheetIx = sheets.size() - 1; int lastSheetIx = _sheets.size() - 1;
if (index < 0 || index > lastSheetIx) { if (index < 0 || index > lastSheetIx) {
throw new IllegalArgumentException("Sheet index (" throw new IllegalArgumentException("Sheet index ("
+ index +") is out of range (0.." + lastSheetIx + ")"); + 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) { public void setSelectedTab(int index) {
validateSheetIndex(index); validateSheetIndex(index);
int nSheets = sheets.size(); int nSheets = _sheets.size();
for (int i=0; i<nSheets; i++) { for (int i=0; i<nSheets; i++) {
getSheetAt(i).setSelected(i == index); 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++) { for (int i = 0; i < indexes.length; i++) {
validateSheetIndex(indexes[i]); validateSheetIndex(indexes[i]);
} }
int nSheets = sheets.size(); int nSheets = _sheets.size();
for (int i=0; i<nSheets; i++) { for (int i=0; i<nSheets; i++) {
boolean bSelect = false; boolean bSelect = false;
for (int j = 0; j < indexes.length; j++) { 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) { public void setActiveSheet(int index) {
validateSheetIndex(index); validateSheetIndex(index);
int nSheets = sheets.size(); int nSheets = _sheets.size();
for (int i=0; i<nSheets; i++) { for (int i=0; i<nSheets; i++) {
getSheetAt(i).setActive(i == index); getSheetAt(i).setActive(i == index);
} }
@ -509,19 +502,15 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
* set the sheet name. * set the sheet name.
* Will throw IllegalArgumentException if the name is greater than 31 chars * Will throw IllegalArgumentException if the name is greater than 31 chars
* or contains /\?*[] * 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" ); 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);
workbook.setSheetName( sheet, name); workbook.setSheetName(sheetIx, name);
} }
@ -533,15 +522,12 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
* or contains /\?*[] * or contains /\?*[]
* @param sheet number (0 based) * @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" ); 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 ) { switch ( encoding ) {
case ENCODING_COMPRESSED_UNICODE: case ENCODING_COMPRESSED_UNICODE:
@ -553,51 +539,39 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
throw new RuntimeException( "Unsupported encoding" ); throw new RuntimeException( "Unsupported encoding" );
} }
workbook.setSheetName( sheet, name, encoding ); workbook.setSheetName( sheetIx, name, encoding );
} }
/** /**
* get the sheet name * get the sheet name
* @param sheet Number * @param sheetIx Number
* @return Sheet name * @return Sheet name
*/ */
public String getSheetName(int sheetIx)
public String getSheetName(int sheet)
{ {
if (sheet > (sheets.size() - 1)) validateSheetIndex(sheetIx);
{ return workbook.getSheetName(sheetIx);
throw new RuntimeException("Sheet out of bounds");
}
return workbook.getSheetName(sheet);
} }
/** /**
* check whether a sheet is hidden * check whether a sheet is hidden
* @param sheet Number * @param sheetIx Number
* @return True if sheet is hidden * @return True if sheet is hidden
*/ */
public boolean isSheetHidden(int sheetIx) {
public boolean isSheetHidden(int sheet) { validateSheetIndex(sheetIx);
if (sheet > (sheets.size() - 1)) return workbook.isSheetHidden(sheetIx);
{
throw new RuntimeException("Sheet out of bounds");
}
return workbook.isSheetHidden(sheet);
} }
/** /**
* Hide or unhide a sheet * 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 * @param hidden True to mark the sheet as hidden, false otherwise
*/ */
public void setSheetHidden(int sheetIx, boolean hidden) {
public void setSheetHidden(int sheet, boolean hidden) { validateSheetIndex(sheetIx);
if (sheet > (sheets.size() - 1)) workbook.setSheetHidden(sheetIx, hidden);
{
throw new RuntimeException("Sheet out of bounds");
}
workbook.setSheetHidden(sheet,hidden);
} }
/* /*
@ -619,12 +593,12 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
/** Returns the index of the given sheet /** Returns the index of the given sheet
* @param sheet the sheet to look up * @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) public int getSheetIndex(org.apache.poi.ss.usermodel.Sheet sheet)
{ {
for(int i=0; i<sheets.size(); i++) { for(int i=0; i<_sheets.size(); i++) {
if(sheets.get(i) == sheet) { if(_sheets.get(i) == sheet) {
return i; return i;
} }
} }
@ -653,9 +627,9 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
{ {
HSSFSheet sheet = new HSSFSheet(this); HSSFSheet sheet = new HSSFSheet(this);
sheets.add(sheet); _sheets.add(sheet);
workbook.setSheetName(sheets.size() - 1, "Sheet" + (sheets.size() - 1)); workbook.setSheetName(_sheets.size() - 1, "Sheet" + (_sheets.size() - 1));
boolean isOnlySheet = sheets.size() == 1; boolean isOnlySheet = _sheets.size() == 1;
sheet.setSelected(isOnlySheet); sheet.setSelected(isOnlySheet);
sheet.setActive(isOnlySheet); sheet.setActive(isOnlySheet);
return sheet; return sheet;
@ -669,13 +643,13 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
public HSSFSheet cloneSheet(int sheetNum) { public HSSFSheet cloneSheet(int sheetNum) {
validateSheetIndex(sheetNum); validateSheetIndex(sheetNum);
HSSFSheet srcSheet = (HSSFSheet) sheets.get(sheetNum); HSSFSheet srcSheet = (HSSFSheet) _sheets.get(sheetNum);
String srcName = workbook.getSheetName(sheetNum); String srcName = workbook.getSheetName(sheetNum);
HSSFSheet clonedSheet = srcSheet.cloneSheet(this); HSSFSheet clonedSheet = srcSheet.cloneSheet(this);
clonedSheet.setSelected(false); clonedSheet.setSelected(false);
clonedSheet.setActive(false); clonedSheet.setActive(false);
sheets.add(clonedSheet); _sheets.add(clonedSheet);
int i = 1; int i = 1;
while (true) { while (true) {
// Try and find the next sheet name that is unique // 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 the sheet name is unique, then set it otherwise move on to the next number.
if (workbook.getSheetIndex(name) == -1) { if (workbook.getSheetIndex(name) == -1) {
workbook.setSheetName(sheets.size()-1, name); workbook.setSheetName(_sheets.size()-1, name);
break; break;
} }
} }
@ -710,14 +684,14 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
public HSSFSheet createSheet(String sheetname) 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" ); throw new IllegalArgumentException( "The workbook already contains a sheet of this name" );
HSSFSheet sheet = new HSSFSheet(this); HSSFSheet sheet = new HSSFSheet(this);
sheets.add(sheet); _sheets.add(sheet);
workbook.setSheetName(sheets.size() - 1, sheetname); workbook.setSheetName(_sheets.size() - 1, sheetname);
boolean isOnlySheet = sheets.size() == 1; boolean isOnlySheet = _sheets.size() == 1;
sheet.setSelected(isOnlySheet); sheet.setSelected(isOnlySheet);
sheet.setActive(isOnlySheet); sheet.setActive(isOnlySheet);
return sheet; return sheet;
@ -730,13 +704,19 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
public int getNumberOfSheets() public int getNumberOfSheets()
{ {
return sheets.size(); return _sheets.size();
} }
public int getSheetIndexFromExternSheetIndex(int externSheetNumber) { public int getSheetIndexFromExternSheetIndex(int externSheetNumber) {
return workbook.getSheetIndexFromExternSheetIndex(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. * Get the HSSFSheet object at the given index.
* @param index of the sheet number (0-based physical & logical) * @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) 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; HSSFSheet retval = null;
for (int k = 0; k < sheets.size(); k++) for (int k = 0; k < _sheets.size(); k++)
{ {
String sheetname = workbook.getSheetName(k); String sheetname = workbook.getSheetName(k);
if (sheetname.equalsIgnoreCase(name)) if (sheetname.equalsIgnoreCase(name))
{ {
retval = (HSSFSheet) sheets.get(k); retval = (HSSFSheet) _sheets.get(k);
} }
} }
return retval; return retval;
@ -793,11 +773,11 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
boolean wasActive = getSheetAt(index).isActive(); boolean wasActive = getSheetAt(index).isActive();
boolean wasSelected = getSheetAt(index).isSelected(); boolean wasSelected = getSheetAt(index).isSelected();
sheets.remove(index); _sheets.remove(index);
workbook.removeSheet(index); workbook.removeSheet(index);
// set the remaining active/selected sheet // set the remaining active/selected sheet
int nSheets = sheets.size(); int nSheets = _sheets.size();
if (nSheets < 1) { if (nSheets < 1) {
// nothing more to do if there are no sheets left // nothing more to do if there are no sheets left
return; return;
@ -1173,48 +1153,47 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
public byte[] getBytes() public byte[] getBytes()
{ {
if (log.check( POILogger.DEBUG )) if (log.check( POILogger.DEBUG )) {
log.log(DEBUG, "HSSFWorkbook.getBytes()"); log.log(DEBUG, "HSSFWorkbook.getBytes()");
}
HSSFSheet[] sheets = getSheets();
int nSheets = sheets.length;
// before getting the workbook size we must tell the sheets that // before getting the workbook size we must tell the sheets that
// serialization is about to occur. // serialization is about to occur.
for (int k = 0; k < sheets.size(); k++) for (int i = 0; i < nSheets; i++) {
((HSSFSheet) sheets.get(k)).getSheet().preSerialize(); sheets[i].getSheet().preSerialize();
}
int wbsize = workbook.getSize(); int totalsize = workbook.getSize();
// log.debug("REMOVEME: old sizing method "+workbook.serialize().length); // pre-calculate all the sheet sizes and set BOF indexes
// ArrayList sheetbytes = new ArrayList(sheets.size()); int[] estimatedSheetSizes = new int[nSheets];
int totalsize = wbsize; for (int k = 0; k < nSheets; k++) {
for (int k = 0; k < sheets.size(); k++)
{
workbook.setSheetBof(k, totalsize); 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]; byte[] retval = new byte[totalsize];
int pos = workbook.serialize(0, retval); int pos = workbook.serialize(0, retval);
// System.arraycopy(wb, 0, retval, 0, wb.length); for (int k = 0; k < nSheets; k++) {
for (int k = 0; k < sheets.size(); 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.
// byte[] sb = (byte[])sheetbytes.get(k); // For books with more than one sheet, this discrepancy would cause excel
// System.arraycopy(sb, 0, retval, pos, sb.length); // to report errors and loose data while reading the workbook
int len = ((HSSFSheet) sheets.get(k)).getSheet().serialize(pos, throw new IllegalStateException("Actual serialized sheet size (" + serializedSize
retval); + ") differs from pre-calculated size (" + estimatedSheetSizes[k]
pos += len; // sb.length; + ") 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; return retval;
} }

View File

@ -15,12 +15,13 @@
limitations under the License. limitations under the License.
==================================================================== */ ==================================================================== */
package org.apache.poi.hssf.util; package org.apache.poi.hssf.util;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.StringTokenizer; import java.util.StringTokenizer;
import org.apache.poi.hssf.record.formula.AreaI;
public final class AreaReference { public final class AreaReference {
/** The character (!) that separates sheet names from cell references */ /** The character (!) that separates sheet names from cell references */
@ -50,13 +51,13 @@ public final class AreaReference {
// Special handling for whole-column references // Special handling for whole-column references
if(parts.length == 2 && parts[0].length() == 1 && if(parts.length == 2 && parts[0].length() == 1 &&
parts[1].length() == 1 && parts[1].length() == 1 &&
parts[0].charAt(0) >= 'A' && parts[0].charAt(0) <= 'Z' && parts[0].charAt(0) >= 'A' && parts[0].charAt(0) <= 'Z' &&
parts[1].charAt(0) >= 'A' && parts[1].charAt(0) <= 'Z') { parts[1].charAt(0) >= 'A' && parts[1].charAt(0) <= 'Z') {
// Represented internally as x$1 to x$65536 // Represented internally as x$1 to x$65536
// which is the maximum range of rows // which is the maximum range of rows
parts[0] = parts[0] + "$1"; parts[0] = parts[0] + "$1";
parts[1] = parts[1] + "$65536"; parts[1] = parts[1] + "$65536";
} }
_firstCell = new CellReference(parts[0]); _firstCell = new CellReference(parts[0]);
@ -74,9 +75,9 @@ public final class AreaReference {
* Creates an area ref from a pair of Cell References. * Creates an area ref from a pair of Cell References.
*/ */
public AreaReference(CellReference topLeft, CellReference botRight) { public AreaReference(CellReference topLeft, CellReference botRight) {
_firstCell = topLeft; _firstCell = topLeft;
_lastCell = botRight; _lastCell = botRight;
_isSingleCell = false; _isSingleCell = false;
} }
/** /**
@ -98,17 +99,17 @@ public final class AreaReference {
* such as C:C or D:G ? * such as C:C or D:G ?
*/ */
public static boolean isWholeColumnReference(CellReference topLeft, CellReference botRight) { public static boolean isWholeColumnReference(CellReference topLeft, CellReference botRight) {
// These are represented as something like // These are represented as something like
// C$1:C$65535 or D$1:F$0 // C$1:C$65535 or D$1:F$0
// i.e. absolute from 1st row to 0th one // i.e. absolute from 1st row to 0th one
if(topLeft.getRow() == 0 && topLeft.isRowAbsolute() && if(topLeft.getRow() == 0 && topLeft.isRowAbsolute() &&
botRight.getRow() == 65535 && botRight.isRowAbsolute()) { botRight.getRow() == 65535 && botRight.isRowAbsolute()) {
return true; return true;
} }
return false; return false;
} }
public boolean isWholeColumnReference() { 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 * Returns a reference to every cell covered by this area
*/ */
public CellReference[] getAllReferencedCells() { public CellReference[] getAllReferencedCells() {
// Special case for single cell reference // Special case for single cell reference
if(_isSingleCell) { if(_isSingleCell) {
return new CellReference[] { _firstCell, }; return new CellReference[] { _firstCell, };
} }
// Interpolate between the two // Interpolate between the two
int minRow = Math.min(_firstCell.getRow(), _lastCell.getRow()); int minRow = Math.min(_firstCell.getRow(), _lastCell.getRow());
int maxRow = Math.max(_firstCell.getRow(), _lastCell.getRow()); int maxRow = Math.max(_firstCell.getRow(), _lastCell.getRow());
int minCol = Math.min(_firstCell.getCol(), _lastCell.getCol()); int minCol = Math.min(_firstCell.getCol(), _lastCell.getCol());
int maxCol = Math.max(_firstCell.getCol(), _lastCell.getCol()); int maxCol = Math.max(_firstCell.getCol(), _lastCell.getCol());
String sheetName = _firstCell.getSheetName(); String sheetName = _firstCell.getSheetName();
ArrayList refs = new ArrayList(); ArrayList refs = new ArrayList();
for(int row=minRow; row<=maxRow; row++) { for(int row=minRow; row<=maxRow; row++) {
for(int col=minCol; col<=maxCol; col++) { for(int col=minCol; col<=maxCol; col++) {
CellReference ref = new CellReference(sheetName, row, col, _firstCell.isRowAbsolute(), _firstCell.isColAbsolute()); CellReference ref = new CellReference(sheetName, row, col, _firstCell.isRowAbsolute(), _firstCell.isColAbsolute());
refs.add(ref); refs.add(ref);
} }
} }
return (CellReference[])refs.toArray(new CellReference[refs.size()]); 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. * @return the text representation of this area reference as it would appear in a formula.
*/ */
public String formatAsString() { public String formatAsString() {
// Special handling for whole-column references // Special handling for whole-column references
if(isWholeColumnReference()) { if(isWholeColumnReference()) {
return return
CellReference.convertNumToColString(_firstCell.getCol()) CellReference.convertNumToColString(_firstCell.getCol())
+ ":" + + ":" +
CellReference.convertNumToColString(_lastCell.getCol()); CellReference.convertNumToColString(_lastCell.getCol());
} }
StringBuffer sb = new StringBuffer(32); StringBuffer sb = new StringBuffer(32);
sb.append(_firstCell.formatAsString()); sb.append(_firstCell.formatAsString());
if(!_isSingleCell) { if(!_isSingleCell) {
@ -210,6 +211,18 @@ public final class AreaReference {
} }
return sb.toString(); 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() { public String toString() {
StringBuffer sb = new StringBuffer(64); StringBuffer sb = new StringBuffer(64);
sb.append(getClass().getName()).append(" ["); sb.append(getClass().getName()).append(" [");

View File

@ -15,16 +15,16 @@
limitations under the License. limitations under the License.
==================================================================== */ ==================================================================== */
package org.apache.poi.hssf.util; package org.apache.poi.hssf.util;
import java.lang.reflect.Field;
import java.util.Hashtable; import java.util.Hashtable;
import org.apache.poi.ss.usermodel.Color; import org.apache.poi.ss.usermodel.Color;
/** /**
* Intends to provide support for the very evil index to triplet issue and * 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. * This class contains static inner class members for representing colors.
* Each color has an index (for the standard palette in Excel (tm) ), * Each color has an index (for the standard palette in Excel (tm) ),
* native (RGB) triplet and string triplet. The string triplet is as the * 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 Andrew C. Oliver (acoliver at apache dot org)
* @author Brian Sanders (bsanders at risklabs dot com) - full default color palette * @author Brian Sanders (bsanders at risklabs dot com) - full default color palette
*/ */
public class HSSFColor implements Color {
public class HSSFColor implements Color // TODO make subclass instances immutable
{
private final static int PALETTE_SIZE = 56;
private final static int DISTINCT_COLOR_COUNT = 46;
/** Creates a new instance of HSSFColor */ /** Creates a new instance of HSSFColor */
public 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 * it takes to create it once per request but you will not hold onto it
* if you have none of those requests. * if you have none of those requests.
* *
* @return a hashtable containing all colors mapped to their excel-style * @return a hashtable containing all colors keyed by <tt>Integer</tt> excel-style palette indexes
* pallette index
*/ */
public final static Hashtable getIndexHash() { public final static Hashtable getIndexHash() {
Hashtable hash = new Hashtable(PALETTE_SIZE); return createColorsByIndexMap();
}
hash.put(new Integer(HSSFColor.BLACK.index), new HSSFColor.BLACK()); private static Hashtable createColorsByIndexMap() {
hash.put(new Integer(HSSFColor.BROWN.index), new HSSFColor.BROWN()); HSSFColor[] colors = getAllColors();
hash.put(new Integer(HSSFColor.OLIVE_GREEN.index), Hashtable result = new Hashtable(colors.length * 3 / 2);
new HSSFColor.OLIVE_GREEN());
hash.put(new Integer(HSSFColor.DARK_GREEN.index), new HSSFColor.DARK_GREEN()); for (int i = 0; i < colors.length; i++) {
hash.put(new Integer(HSSFColor.DARK_TEAL.index), new HSSFColor.DARK_TEAL()); HSSFColor color = colors[i];
hash.put(new Integer(HSSFColor.DARK_BLUE.index), new HSSFColor.DARK_BLUE());
hash.put(new Integer(HSSFColor.DARK_BLUE.index2), new HSSFColor.DARK_BLUE()); Integer index1 = new Integer(color.getIndex());
hash.put(new Integer(HSSFColor.INDIGO.index), new HSSFColor.INDIGO()); if (result.containsKey(index1)) {
hash.put(new Integer(HSSFColor.GREY_80_PERCENT.index), HSSFColor prevColor = (HSSFColor)result.get(index1);
new HSSFColor.GREY_80_PERCENT()); throw new RuntimeException("Dup color index (" + index1
hash.put(new Integer(HSSFColor.ORANGE.index), new HSSFColor.ORANGE()); + ") for colors (" + prevColor.getClass().getName()
hash.put(new Integer(HSSFColor.DARK_YELLOW.index), + "),(" + color.getClass().getName() + ")");
new HSSFColor.DARK_YELLOW()); }
hash.put(new Integer(HSSFColor.GREEN.index), new HSSFColor.GREEN()); result.put(index1, color);
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()); for (int i = 0; i < colors.length; i++) {
hash.put(new Integer(HSSFColor.BLUE.index2), new HSSFColor.BLUE()); HSSFColor color = colors[i];
hash.put(new Integer(HSSFColor.BLUE_GREY.index), new HSSFColor.BLUE_GREY()); Integer index2 = getIndex2(color);
hash.put(new Integer(HSSFColor.GREY_50_PERCENT.index), if (index2 == null) {
new HSSFColor.GREY_50_PERCENT()); // most colors don't have a second index
hash.put(new Integer(HSSFColor.RED.index), new HSSFColor.RED()); continue;
hash.put(new Integer(HSSFColor.LIGHT_ORANGE.index), }
new HSSFColor.LIGHT_ORANGE()); if (result.containsKey(index2)) {
hash.put(new Integer(HSSFColor.LIME.index), new HSSFColor.LIME()); if (false) { // Many of the second indexes clash
hash.put(new Integer(HSSFColor.SEA_GREEN.index), new HSSFColor.SEA_GREEN()); HSSFColor prevColor = (HSSFColor)result.get(index2);
hash.put(new Integer(HSSFColor.AQUA.index), new HSSFColor.AQUA()); throw new RuntimeException("Dup color index (" + index2
hash.put(new Integer(HSSFColor.LIGHT_BLUE.index), new HSSFColor.LIGHT_BLUE()); + ") for colors (" + prevColor.getClass().getName()
hash.put(new Integer(HSSFColor.VIOLET.index), new HSSFColor.VIOLET()); + "),(" + color.getClass().getName() + ")");
hash.put(new Integer(HSSFColor.VIOLET.index2), new HSSFColor.VIOLET()); }
hash.put(new Integer(HSSFColor.GREY_40_PERCENT.index), }
new HSSFColor.GREY_40_PERCENT()); result.put(index2, color);
hash.put(new Integer(HSSFColor.PINK.index), new HSSFColor.PINK()); }
hash.put(new Integer(HSSFColor.PINK.index2), new HSSFColor.PINK()); return result;
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()); private static Integer getIndex2(HSSFColor color) {
hash.put(new Integer(HSSFColor.BRIGHT_GREEN.index),
new HSSFColor.BRIGHT_GREEN()); Field f;
hash.put(new Integer(HSSFColor.BRIGHT_GREEN.index2), try {
new HSSFColor.BRIGHT_GREEN()); f = color.getClass().getDeclaredField("index2");
hash.put(new Integer(HSSFColor.TURQUOISE.index), new HSSFColor.TURQUOISE()); } catch (NoSuchFieldException e) {
hash.put(new Integer(HSSFColor.TURQUOISE.index2), new HSSFColor.TURQUOISE()); // can happen because not all colors have a second index
hash.put(new Integer(HSSFColor.DARK_RED.index), new HSSFColor.DARK_RED()); return null;
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()); Short s;
hash.put(new Integer(HSSFColor.PLUM.index2), new HSSFColor.PLUM()); try {
hash.put(new Integer(HSSFColor.GREY_25_PERCENT.index), s = (Short) f.get(color);
new HSSFColor.GREY_25_PERCENT()); } catch (IllegalArgumentException e) {
hash.put(new Integer(HSSFColor.ROSE.index), new HSSFColor.ROSE()); throw new RuntimeException(e);
hash.put(new Integer(HSSFColor.LIGHT_YELLOW.index), } catch (IllegalAccessException e) {
new HSSFColor.LIGHT_YELLOW()); throw new RuntimeException(e);
hash.put(new Integer(HSSFColor.LIGHT_GREEN.index), }
new HSSFColor.LIGHT_GREEN()); return new Integer(s.intValue());
hash.put(new Integer(HSSFColor.LIGHT_TURQUOISE.index), }
new HSSFColor.LIGHT_TURQUOISE());
hash.put(new Integer(HSSFColor.LIGHT_TURQUOISE.index2), private static HSSFColor[] getAllColors() {
new HSSFColor.LIGHT_TURQUOISE());
hash.put(new Integer(HSSFColor.PALE_BLUE.index), new HSSFColor.PALE_BLUE()); return new HSSFColor[] {
hash.put(new Integer(HSSFColor.LAVENDER.index), new HSSFColor.LAVENDER()); new BLACK(), new BROWN(), new OLIVE_GREEN(), new DARK_GREEN(),
hash.put(new Integer(HSSFColor.WHITE.index), new HSSFColor.WHITE()); new DARK_TEAL(), new DARK_BLUE(), new INDIGO(), new GREY_80_PERCENT(),
hash.put(new Integer(HSSFColor.CORNFLOWER_BLUE.index), new ORANGE(), new DARK_YELLOW(), new GREEN(), new TEAL(), new BLUE(),
new HSSFColor.CORNFLOWER_BLUE()); new BLUE_GREY(), new GREY_50_PERCENT(), new RED(), new LIGHT_ORANGE(), new LIME(),
hash.put(new Integer(HSSFColor.LEMON_CHIFFON.index), new SEA_GREEN(), new AQUA(), new LIGHT_BLUE(), new VIOLET(), new GREY_40_PERCENT(),
new HSSFColor.LEMON_CHIFFON()); new PINK(), new GOLD(), new YELLOW(), new BRIGHT_GREEN(), new TURQUOISE(),
hash.put(new Integer(HSSFColor.MAROON.index), new HSSFColor.MAROON()); new DARK_RED(), new SKY_BLUE(), new PLUM(), new GREY_25_PERCENT(), new ROSE(),
hash.put(new Integer(HSSFColor.ORCHID.index), new HSSFColor.ORCHID()); new LIGHT_YELLOW(), new LIGHT_GREEN(), new LIGHT_TURQUOISE(), new PALE_BLUE(),
hash.put(new Integer(HSSFColor.CORAL.index), new HSSFColor.CORAL()); new LAVENDER(), new WHITE(), new CORNFLOWER_BLUE(), new LEMON_CHIFFON(),
hash.put(new Integer(HSSFColor.ROYAL_BLUE.index), new HSSFColor.ROYAL_BLUE()); new MAROON(), new ORCHID(), new CORAL(), new ROYAL_BLUE(),
hash.put(new Integer(HSSFColor.LIGHT_CORNFLOWER_BLUE.index), new LIGHT_CORNFLOWER_BLUE(), new TAN(),
new HSSFColor.LIGHT_CORNFLOWER_BLUE()); };
return hash;
} }
/** /**
@ -144,73 +139,28 @@ public class HSSFColor implements Color
* it takes to create it once per request but you will not hold onto it * it takes to create it once per request but you will not hold onto it
* if you have none of those requests. * if you have none of those requests.
* *
* @return a hashtable containing all colors mapped to their gnumeric-like * @return a hashtable containing all colors keyed by String gnumeric-like triplets
* triplet string
*/ */
public final static Hashtable getTripletHash() public final static Hashtable getTripletHash()
{ {
Hashtable hash = new Hashtable(DISTINCT_COLOR_COUNT); return createColorsByHexStringMap();
}
hash.put(HSSFColor.BLACK.hexString, new HSSFColor.BLACK()); private static Hashtable createColorsByHexStringMap() {
hash.put(HSSFColor.BROWN.hexString, new HSSFColor.BROWN()); HSSFColor[] colors = getAllColors();
hash.put(HSSFColor.OLIVE_GREEN.hexString, Hashtable result = new Hashtable(colors.length * 3 / 2);
new HSSFColor.OLIVE_GREEN());
hash.put(HSSFColor.DARK_GREEN.hexString, new HSSFColor.DARK_GREEN()); for (int i = 0; i < colors.length; i++) {
hash.put(HSSFColor.DARK_TEAL.hexString, new HSSFColor.DARK_TEAL()); HSSFColor color = colors[i];
hash.put(HSSFColor.DARK_BLUE.hexString, new HSSFColor.DARK_BLUE());
hash.put(HSSFColor.INDIGO.hexString, new HSSFColor.INDIGO()); String hexString = color.getHexString();
hash.put(HSSFColor.GREY_80_PERCENT.hexString, if (result.containsKey(hexString)) {
new HSSFColor.GREY_80_PERCENT()); throw new RuntimeException("Dup color hexString (" + hexString
hash.put(HSSFColor.ORANGE.hexString, new HSSFColor.ORANGE()); + ") for color (" + color.getClass().getName() + ")");
hash.put(HSSFColor.DARK_YELLOW.hexString, }
new HSSFColor.DARK_YELLOW()); result.put(hexString, color);
hash.put(HSSFColor.GREEN.hexString, new HSSFColor.GREEN()); }
hash.put(HSSFColor.TEAL.hexString, new HSSFColor.TEAL()); return result;
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;
} }
/** /**
@ -1492,7 +1442,7 @@ public class HSSFColor implements Color
return hexString; return hexString;
} }
} }
/** /**
* Class CORNFLOWER_BLUE * Class CORNFLOWER_BLUE
*/ */
@ -1521,8 +1471,8 @@ public class HSSFColor implements Color
return hexString; return hexString;
} }
} }
/** /**
* Class LEMON_CHIFFON * Class LEMON_CHIFFON
*/ */
@ -1551,7 +1501,7 @@ public class HSSFColor implements Color
return hexString; return hexString;
} }
} }
/** /**
* Class MAROON * Class MAROON
*/ */
@ -1580,7 +1530,7 @@ public class HSSFColor implements Color
return hexString; return hexString;
} }
} }
/** /**
* Class ORCHID * Class ORCHID
*/ */
@ -1609,7 +1559,7 @@ public class HSSFColor implements Color
return hexString; return hexString;
} }
} }
/** /**
* Class CORAL * Class CORAL
*/ */
@ -1638,7 +1588,7 @@ public class HSSFColor implements Color
return hexString; return hexString;
} }
} }
/** /**
* Class ROYAL_BLUE * Class ROYAL_BLUE
*/ */
@ -1667,7 +1617,7 @@ public class HSSFColor implements Color
return hexString; return hexString;
} }
} }
/** /**
* Class LIGHT_CORNFLOWER_BLUE * Class LIGHT_CORNFLOWER_BLUE
*/ */
@ -1696,19 +1646,19 @@ public class HSSFColor implements Color
return hexString; return hexString;
} }
} }
/** /**
* Special Default/Normal/Automatic color. * Special Default/Normal/Automatic color.
* <p><i>Note:</i> This class is NOT in the default HashTables returned by HSSFColor. * <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. * The index is a special case which is interpreted in the various setXXXColor calls.
* *
* @author Jason * @author Jason
* *
*/ */
public final static class AUTOMATIC extends HSSFColor 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 final static short index = 0x40;
public short getIndex() public short getIndex()
@ -1725,7 +1675,7 @@ public class HSSFColor implements Color
{ {
return BLACK.hexString; return BLACK.hexString;
} }
public static HSSFColor getInstance() { public static HSSFColor getInstance() {
return instance; return instance;
} }

View File

@ -226,7 +226,9 @@ public class DateUtil
// Otherwise, check it's only made up, in any case, of: // Otherwise, check it's only made up, in any case, of:
// y m d h s - / , . : // 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; return true;
} }

View File

@ -14,7 +14,7 @@
# limitations under the License. # limitations under the License.
# Created by (org.apache.poi.hssf.record.formula.function.ExcelFileFormatDocFunctionExtractor) # 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 ) #Columns: (index, name, minParams, maxParams, returnClass, paramClasses, isVolatile, hasFootnote )
@ -37,7 +37,7 @@
15 SIN 1 1 V V 15 SIN 1 1 V V
16 COS 1 1 V V 16 COS 1 1 V V
17 TAN 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 - 19 PI 0 0 V -
20 SQRT 1 1 V V 20 SQRT 1 1 V V
21 EXP 1 1 V V 21 EXP 1 1 V V
@ -141,8 +141,8 @@
169 COUNTA 0 30 V R 169 COUNTA 0 30 V R
183 PRODUCT 0 30 V R 183 PRODUCT 0 30 V R
184 FACT 1 1 V V 184 FACT 1 1 V V
191 DPRODUCT 3 3 V R R R 189 DPRODUCT 3 3 V R R R
192 ISNONTEXT 1 1 V V 190 ISNONTEXT 1 1 V V
193 STDEVP 1 30 V R 193 STDEVP 1 30 V R
194 VARP 1 30 V R 194 VARP 1 30 V R
195 DSTDEVP 3 3 V R R R 195 DSTDEVP 3 3 V R R R
@ -184,6 +184,8 @@
244 INFO 1 1 V V 244 INFO 1 1 V V
# New Built-In Sheet Functions in BIFF4 # New Built-In Sheet Functions in BIFF4
14 FIXED 2 3 V V V V x 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 216 RANK 2 3 V V R V
247 DB 4 5 V V V V V V 247 DB 4 5 V V V V V V
252 FREQUENCY 2 2 A R R 252 FREQUENCY 2 2 A R R

View File

@ -14,11 +14,9 @@
# limitations under the License. # limitations under the License.
# Created by (org.apache.poi.hssf.record.formula.function.ExcelFileFormatDocFunctionExtractor) # 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 ) #Columns: (index, name, minParams, maxParams, returnClass, paramClasses, isVolatile, hasFootnote )
#
# + some manual edits !
# Built-In Sheet Functions in BIFF2 # Built-In Sheet Functions in BIFF2
0 COUNT 0 30 V R 0 COUNT 0 30 V R
@ -186,7 +184,7 @@
244 INFO 1 1 V V 244 INFO 1 1 V V
# New Built-In Sheet Functions in BIFF4 # New Built-In Sheet Functions in BIFF4
14 FIXED 2 3 V V V V x 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 215 DBCS 1 1 V V x
216 RANK 2 3 V V R V 216 RANK 2 3 V V R V
247 DB 4 5 V V V V V V 247 DB 4 5 V V V V V V

View File

@ -18,6 +18,7 @@ package org.apache.poi.hdgf;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream;
import org.apache.poi.POIDocument; import org.apache.poi.POIDocument;
import org.apache.poi.hdgf.chunks.ChunkFactory; 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.Stream;
import org.apache.poi.hdgf.streams.StringsStream; import org.apache.poi.hdgf.streams.StringsStream;
import org.apache.poi.hdgf.streams.TrailerStream; 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.DocumentEntry;
import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.util.LittleEndian; import org.apache.poi.util.LittleEndian;
@ -53,14 +55,17 @@ public class HDGFDiagram extends POIDocument {
private PointerFactory ptrFactory; private PointerFactory ptrFactory;
public HDGFDiagram(POIFSFileSystem fs) throws IOException { 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 docProps =
(DocumentEntry)filesystem.getRoot().getEntry("VisioDocument"); (DocumentEntry)dir.getEntry("VisioDocument");
// Grab the document stream // Grab the document stream
_docstream = new byte[docProps.getSize()]; _docstream = new byte[docProps.getSize()];
filesystem.createDocumentInputStream("VisioDocument").read(_docstream); dir.createDocumentInputStream("VisioDocument").read(_docstream);
// Read in the common POI streams // Read in the common POI streams
readProperties(); 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 * For testing only
*/ */

View File

@ -21,17 +21,18 @@ import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* This class holds all the FSPA (File Shape Address) structures. * This class holds all the FSPA (File Shape Address) structures.
* *
* @author Squeeself * @author Squeeself
*/ */
public class FSPATable public final class FSPATable
{ {
protected ArrayList shapes = new ArrayList(); private final List _shapes = new ArrayList();
protected HashMap cps = new HashMap(); private final Map _shapeIndexesByPropertyStart = new HashMap();
protected List _text; private final List _text;
public FSPATable(byte[] tableStream, int fcPlcspa, int lcbPlcspa, List tpt) public FSPATable(byte[] tableStream, int fcPlcspa, int lcbPlcspa, List tpt)
{ {
@ -46,32 +47,35 @@ public class FSPATable
GenericPropertyNode property = plex.getProperty(i); GenericPropertyNode property = plex.getProperty(i);
FSPA fspa = new FSPA(property.getBytes(), 0); FSPA fspa = new FSPA(property.getBytes(), 0);
shapes.add(fspa); _shapes.add(fspa);
cps.put(Integer.valueOf(property.getStart()), Integer.valueOf(i)); _shapeIndexesByPropertyStart.put(new Integer(property.getStart()), new Integer(i));
} }
} }
public FSPA getFspaFromCp(int cp) public FSPA getFspaFromCp(int cp)
{ {
Integer idx = (Integer)cps.get(Integer.valueOf(cp)); Integer idx = (Integer)_shapeIndexesByPropertyStart.get(new Integer(cp));
if (idx == null) if (idx == null) {
return 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() public String toString()
{ {
StringBuffer buf = new StringBuffer(); StringBuffer buf = new StringBuffer();
buf.append("[FPSA PLC size=").append(shapes.size()).append("]\n"); buf.append("[FPSA PLC size=").append(_shapes.size()).append("]\n");
for (Iterator it = cps.keySet().iterator(); it.hasNext(); ) for (Iterator it = _shapeIndexesByPropertyStart.keySet().iterator(); it.hasNext(); )
{ {
Integer i = (Integer) it.next(); 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(" [FC: ").append(i.toString()).append("] ");
buf.append(fspa.toString()); buf.append(fspa.toString());
buf.append("\n"); buf.append("\n");

View File

@ -294,6 +294,16 @@ public class FileInformationBlock extends FIBAbstractType
_longHandler.setLong(FIBLongHandler.CBMAC, cbMac); _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() public void clearOffsetsSizes()
{ {
_fieldHandler.clearFields(); _fieldHandler.clearFields();

View File

@ -90,12 +90,20 @@ public class TextPiece extends PropertyNode implements Comparable
public void adjustForDelete(int start, int length) public void adjustForDelete(int start, int length)
{ {
if (usesUnicode()) {
start /= 2;
length /= 2;
}
int myStart = getStart(); int myStart = getStart();
int myEnd = getEnd(); int myEnd = getEnd();
int end = start + length; int end = start + length;
/* do we have to delete from this text piece? */ /* do we have to delete from this text piece? */
if (start <= myEnd && end >= myStart) { if (start <= myEnd && end >= myStart) {
/* find where the deleted area overlaps with this text piece */ /* find where the deleted area overlaps with this text piece */
int overlapStart = Math.max(myStart, start); int overlapStart = Math.max(myStart, start);
int overlapEnd = Math.min(myEnd, end); int overlapEnd = Math.min(myEnd, end);

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. * 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 // Since this is the first item in our list, it is safe to assume that
// _start >= tp.getStart() // _start >= tp.getStart()
int insertIndex = _start - tp.getStart(); int insertIndex = _start - tp.getStart();
if (tp.usesUnicode())
insertIndex /= 2;
sb.insert(insertIndex, text); sb.insert(insertIndex, text);
int adjustedLength = _doc.getTextTable().adjustForInsert(_textStart, text.length()); int adjustedLength = _doc.getTextTable().adjustForInsert(_textStart, text.length());
_doc.getCharacterTable().adjustForInsert(_charStart, adjustedLength); _doc.getCharacterTable().adjustForInsert(_charStart, adjustedLength);
_doc.getParagraphTable().adjustForInsert(_parStart, adjustedLength); _doc.getParagraphTable().adjustForInsert(_parStart, adjustedLength);
_doc.getSectionTable().adjustForInsert(_sectionStart, adjustedLength); _doc.getSectionTable().adjustForInsert(_sectionStart, adjustedLength);
adjustForInsert(text.length()); adjustForInsert(text.length());
// update the FIB.CCPText field
adjustFIB(text.length());
return getCharacterRun(0); return getCharacterRun(0);
} }
@ -489,6 +514,7 @@ public class Range
public void delete() public void delete()
{ {
initAll(); initAll();
int numSections = _sections.size(); int numSections = _sections.size();
@ -519,6 +545,12 @@ public class Range
TextPiece piece = (TextPiece)_text.get(x); TextPiece piece = (TextPiece)_text.get(x);
piece.adjustForDelete(_start, _end - _start); 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; _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. * adjust this range after an insert happens.
* @param length the length to adjust for * @param length the length to adjust for
@ -834,6 +879,7 @@ public class Range
private void adjustForInsert(int length) private void adjustForInsert(int length)
{ {
_end += length; _end += length;
reset(); reset();
Range parent = (Range)_parent.get(); Range parent = (Range)_parent.get();
if (parent != null) if (parent != null)
@ -842,4 +888,14 @@ public class Range
} }
} }
public int getStartOffset() {
return _start;
}
public int getEndOffset() {
return _end;
}
} }

File diff suppressed because it is too large Load Diff

View File

@ -17,6 +17,7 @@
package org.apache.poi.hssf.model; package org.apache.poi.hssf.model;
import junit.framework.AssertionFailedError;
import junit.framework.TestCase; import junit.framework.TestCase;
import org.apache.poi.hssf.record.*; import org.apache.poi.hssf.record.*;
import org.apache.poi.hssf.record.aggregates.ColumnInfoRecordsAggregate; import org.apache.poi.hssf.record.aggregates.ColumnInfoRecordsAggregate;
@ -351,5 +352,25 @@ public final class TestSheet extends TestCase {
xfindex = sheet.getXFIndexForColAt((short) 10); xfindex = sheet.getXFIndexForColAt((short) 10);
assertEquals(DEFAULT_IDX, xfindex); 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);
}
} }

View File

@ -26,9 +26,12 @@ import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.PrintStream; import java.io.PrintStream;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
import java.net.URLConnection; import java.net.URLConnection;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
@ -37,7 +40,6 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.Stack; import java.util.Stack;
import java.util.zip.CRC32;
import java.util.zip.ZipException; import java.util.zip.ZipException;
import java.util.zip.ZipFile; import java.util.zip.ZipFile;
@ -149,7 +151,6 @@ public final class ExcelFileFormatDocFunctionExtractor {
private static final class FunctionDataCollector { private static final class FunctionDataCollector {
private final Map _allFunctionsByIndex; private final Map _allFunctionsByIndex;
private final Map _allFunctionsByName; private final Map _allFunctionsByName;
private final Set _groupFunctionIndexes; private final Set _groupFunctionIndexes;
@ -184,25 +185,29 @@ public final class ExcelFileFormatDocFunctionExtractor {
_allFunctionsByName.put(funcName, fd); _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) { private void checkRedefinedFunction(boolean hasNote, String funcName, Integer funcIxKey) {
FunctionData fdPrev; FunctionData fdPrev;
// check by index
fdPrev = (FunctionData) _allFunctionsByIndex.get(funcIxKey); fdPrev = (FunctionData) _allFunctionsByIndex.get(funcIxKey);
if(fdPrev != null) { if(fdPrev != null) {
if(fdPrev.hasFootnote() && hasNote) { if(!fdPrev.hasFootnote() || !hasNote) {
// func def can change if both have a foot-note throw new RuntimeException("changing function ["
_allFunctionsByName.remove(fdPrev.getName()); + funcIxKey + "] definition without foot-note");
} else {
throw new RuntimeException("changing function definition without foot-note");
} }
_allFunctionsByName.remove(fdPrev.getName());
} }
// check by name
fdPrev = (FunctionData) _allFunctionsByName.get(funcName); fdPrev = (FunctionData) _allFunctionsByName.get(funcName);
if(fdPrev != null) { if(fdPrev != null) {
if(fdPrev.hasFootnote() && hasNote) { if(!fdPrev.hasFootnote() || !hasNote) {
// func def can change if both have a foot-note throw new RuntimeException("changing function '"
_allFunctionsByIndex.remove(new Integer(fdPrev.getIndex())); + funcName + "' definition without foot-note");
} else {
throw new RuntimeException("changing function 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 = { private static final String[] TABLE_CELL_RELPATH_NAMES = {
"table:table-row", "table:table-cell", "text:p", "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", "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; private final Stack _elemNameStack;
@ -368,6 +377,8 @@ public final class ExcelFileFormatDocFunctionExtractor {
} else if(matchesRelPath(TABLE_CELL_RELPATH_NAMES)) { } else if(matchesRelPath(TABLE_CELL_RELPATH_NAMES)) {
_textNodeBuffer.setLength(0); _textNodeBuffer.setLength(0);
_cellHasNote = false; _cellHasNote = false;
} else if(matchesRelPath(NOTE_REF_RELPATH_NAMES_OLD)) {
_cellHasNote = true;
} else if(matchesRelPath(NOTE_REF_RELPATH_NAMES)) { } else if(matchesRelPath(NOTE_REF_RELPATH_NAMES)) {
_cellHasNote = true; _cellHasNote = true;
} }
@ -456,6 +467,9 @@ public final class ExcelFileFormatDocFunctionExtractor {
} }
private static void processFile(File effDocFile, File outFile) { private static void processFile(File effDocFile, File outFile) {
if(!effDocFile.exists()) {
throw new RuntimeException("file '" + effDocFile.getAbsolutePath() + "' does not exist");
}
OutputStream os; OutputStream os;
try { try {
os = new FileOutputStream(outFile); os = new FileOutputStream(outFile);
@ -475,7 +489,7 @@ public final class ExcelFileFormatDocFunctionExtractor {
ps.println("# Created by (" + genClass.getName() + ")"); ps.println("# Created by (" + genClass.getName() + ")");
// identify the source file // identify the source file
ps.print("# from source file '" + SOURCE_DOC_FILE_NAME + "'"); 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("#");
ps.println("#Columns: (index, name, minParams, maxParams, returnClass, paramClasses, isVolatile, hasFootnote )"); ps.println("#Columns: (index, name, minParams, maxParams, returnClass, paramClasses, isVolatile, hasFootnote )");
ps.println(""); ps.println("");
@ -490,6 +504,14 @@ public final class ExcelFileFormatDocFunctionExtractor {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
ps.close(); 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) { private static void outputLicenseHeader(PrintStream ps) {
@ -519,8 +541,14 @@ public final class ExcelFileFormatDocFunctionExtractor {
/** /**
* Helps identify the source file * Helps identify the source file
*/ */
private static String getFileCRC(File f) { private static String getFileMD5(File f) {
CRC32 crc = new CRC32(); MessageDigest m;
try {
m = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
byte[]buf = new byte[2048]; byte[]buf = new byte[2048];
try { try {
InputStream is = new FileInputStream(f); InputStream is = new FileInputStream(f);
@ -529,21 +557,17 @@ public final class ExcelFileFormatDocFunctionExtractor {
if(bytesRead<1) { if(bytesRead<1) {
break; break;
} }
crc.update(buf, 0, bytesRead); m.update(buf, 0, bytesRead);
} }
is.close(); is.close();
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException(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() { private static File downloadSourceFile() {
if (false) {
File dir = new File("c:/temp");
File effDocFile = new File(dir, SOURCE_DOC_FILE_NAME);
return effDocFile;
}
URL url; URL url;
try { try {
url = new URL("http://sc.openoffice.org/" + SOURCE_DOC_FILE_NAME); url = new URL("http://sc.openoffice.org/" + SOURCE_DOC_FILE_NAME);
@ -557,7 +581,7 @@ public final class ExcelFileFormatDocFunctionExtractor {
URLConnection conn = url.openConnection(); URLConnection conn = url.openConnection();
InputStream is = conn.getInputStream(); InputStream is = conn.getInputStream();
System.out.println("downloading " + url.toExternalForm()); System.out.println("downloading " + url.toExternalForm());
result = File.createTempFile("excelfileformat", "odt"); result = File.createTempFile("excelfileformat", ".odt");
OutputStream os = new FileOutputStream(result); OutputStream os = new FileOutputStream(result);
while(true) { while(true) {
int bytesRead = is.read(buf); int bytesRead = is.read(buf);
@ -577,12 +601,17 @@ public final class ExcelFileFormatDocFunctionExtractor {
public static void main(String[] args) { 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"); 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();
} }
} }

View File

@ -21,7 +21,6 @@ import junit.framework.AssertionFailedError;
import junit.framework.TestCase; import junit.framework.TestCase;
import org.apache.poi.hssf.model.FormulaParser; 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.AbstractFunctionPtg;
import org.apache.poi.hssf.record.formula.FuncPtg; import org.apache.poi.hssf.record.formula.FuncPtg;
import org.apache.poi.hssf.record.formula.FuncVarPtg; 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; import org.apache.poi.hssf.usermodel.HSSFWorkbook;
/** /**
* Tests parsing of some built-in functions that were not properly * 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 * @author Josh Micich
*/ */
@ -76,7 +75,7 @@ public final class TestParseMissingBuiltInFuncs extends TestCase {
} }
public void testUsdollar() { public void testUsdollar() {
confirmFunc("USDOLLAR(1)", 2, false, 204); confirmFunc("USDOLLAR(1)", 2, true, 204);
} }
public void testDBCS() { public void testDBCS() {

View File

@ -17,22 +17,18 @@
package org.apache.poi.hssf.record.formula.function; 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 java.lang.reflect.InvocationTargetException;
import junit.framework.AssertionFailedError;
import junit.framework.TestCase;
import org.apache.poi.hssf.HSSFTestDataSamples; import org.apache.poi.hssf.HSSFTestDataSamples;
import org.apache.poi.hssf.record.RecordFormatException; import org.apache.poi.hssf.record.RecordFormatException;
import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook; 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 * 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 * @author Josh Micich
*/ */

View File

@ -28,7 +28,7 @@ import junit.framework.TestSuite;
public class AllUserModelTests { public class AllUserModelTests {
public static Test suite() { 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(TestBugs.class);
result.addTestSuite(TestCellStyle.class); result.addTestSuite(TestCellStyle.class);
@ -58,6 +58,7 @@ public class AllUserModelTests {
result.addTestSuite(TestHSSFSheetSetOrder.class); result.addTestSuite(TestHSSFSheetSetOrder.class);
result.addTestSuite(TestHSSFTextbox.class); result.addTestSuite(TestHSSFTextbox.class);
result.addTestSuite(TestHSSFWorkbook.class); result.addTestSuite(TestHSSFWorkbook.class);
result.addTestSuite(TestLinkTable.class);
result.addTestSuite(TestNamedRange.class); result.addTestSuite(TestNamedRange.class);
result.addTestSuite(TestOLE2Embeding.class); result.addTestSuite(TestOLE2Embeding.class);
result.addTestSuite(TestPOIFSProperties.class); result.addTestSuite(TestPOIFSProperties.class);

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. * test that Boolean and Error types (BoolErrRecord) are supported properly.
*/ */

View File

@ -266,6 +266,8 @@ public class TestHSSFDateUtil extends TestCase {
formats = new String[] { formats = new String[] {
"yyyy-mm-dd hh:mm:ss", "yyyy/mm/dd HH:MM:SS", "yyyy-mm-dd hh:mm:ss", "yyyy/mm/dd HH:MM:SS",
"mm/dd HH:MM", "yy/mmm/dd 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++) { for(int i=0; i<formats.length; i++) {
assertTrue( HSSFDateUtil.isADateFormat(formatId, formats[i]) ); assertTrue( HSSFDateUtil.isADateFormat(formatId, formats[i]) );

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.WSBoolRecord;
import org.apache.poi.hssf.record.WindowTwoRecord; import org.apache.poi.hssf.record.WindowTwoRecord;
import org.apache.poi.ss.util.Region; import org.apache.poi.ss.util.Region;
import org.apache.poi.util.TempFile;
/** /**
* Tests HSSFSheet. This test case is very incomplete at the moment. * 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. * Test the gridset field gets set as expected.
*/ */
public void testBackupRecord() {
public void testBackupRecord()
throws Exception
{
HSSFWorkbook wb = new HSSFWorkbook(); HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet s = wb.createSheet(); HSSFSheet s = wb.createSheet();
Sheet sheet = s.getSheet(); Sheet sheet = s.getSheet();
@ -70,10 +66,7 @@ public final class TestHSSFSheet extends TestCase {
/** /**
* Test vertically centered output. * Test vertically centered output.
*/ */
public void testVerticallyCenter() {
public void testVerticallyCenter()
throws Exception
{
HSSFWorkbook wb = new HSSFWorkbook(); HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet s = wb.createSheet(); HSSFSheet s = wb.createSheet();
Sheet sheet = s.getSheet(); Sheet sheet = s.getSheet();
@ -90,10 +83,7 @@ public final class TestHSSFSheet extends TestCase {
/** /**
* Test horizontally centered output. * Test horizontally centered output.
*/ */
public void testHorizontallyCenter() {
public void testHorizontallyCenter()
throws Exception
{
HSSFWorkbook wb = new HSSFWorkbook(); HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet s = wb.createSheet(); HSSFSheet s = wb.createSheet();
Sheet sheet = s.getSheet(); Sheet sheet = s.getSheet();
@ -103,16 +93,13 @@ public final class TestHSSFSheet extends TestCase {
assertEquals(false, record.getHCenter()); assertEquals(false, record.getHCenter());
s.setHorizontallyCenter(true); s.setHorizontallyCenter(true);
assertEquals(true, record.getHCenter()); assertEquals(true, record.getHCenter());
} }
/** /**
* Test WSBboolRecord fields get set in the user model. * Test WSBboolRecord fields get set in the user model.
*/ */
public void testWSBool() {
public void testWSBool()
{
HSSFWorkbook wb = new HSSFWorkbook(); HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet s = wb.createSheet(); HSSFSheet s = wb.createSheet();
Sheet sheet = s.getSheet(); Sheet sheet = s.getSheet();
@ -158,9 +145,7 @@ public final class TestHSSFSheet extends TestCase {
assertEquals(true, s.getRowSumsRight()); assertEquals(true, s.getRowSumsRight());
} }
public void testReadBooleans() public void testReadBooleans() {
throws Exception
{
HSSFWorkbook workbook = new HSSFWorkbook(); HSSFWorkbook workbook = new HSSFWorkbook();
HSSFSheet sheet = workbook.createSheet("Test boolean"); HSSFSheet sheet = workbook.createSheet("Test boolean");
HSSFRow row = sheet.createRow((short) 2); HSSFRow row = sheet.createRow((short) 2);
@ -168,23 +153,16 @@ public final class TestHSSFSheet extends TestCase {
cell.setCellValue(true); cell.setCellValue(true);
cell = row.createCell((short) 11); cell = row.createCell((short) 11);
cell.setCellValue(true); cell.setCellValue(true);
File tempFile = TempFile.createTempFile("bool", "test.xls");
FileOutputStream stream = new FileOutputStream(tempFile); workbook = HSSFTestDataSamples.writeOutAndReadBack(workbook);
workbook.write(stream);
stream.close();
FileInputStream readStream = new FileInputStream(tempFile);
workbook = new HSSFWorkbook(readStream);
sheet = workbook.getSheetAt(0); sheet = workbook.getSheetAt(0);
row = sheet.getRow(2); row = sheet.getRow(2);
stream.close();
tempFile.delete();
assertNotNull(row); assertNotNull(row);
assertEquals(2, row.getPhysicalNumberOfCells()); assertEquals(2, row.getPhysicalNumberOfCells());
} }
public void testRemoveRow() public void testRemoveRow() {
{
HSSFWorkbook workbook = new HSSFWorkbook(); HSSFWorkbook workbook = new HSSFWorkbook();
HSSFSheet sheet = workbook.createSheet("Test boolean"); HSSFSheet sheet = workbook.createSheet("Test boolean");
HSSFRow row = sheet.createRow((short) 2); HSSFRow row = sheet.createRow((short) 2);
@ -197,8 +175,8 @@ public final class TestHSSFSheet extends TestCase {
HSSFRow row = sheet.createRow(0); HSSFRow row = sheet.createRow(0);
HSSFCell cell = row.createCell((short) 0); HSSFCell cell = row.createCell((short) 0);
HSSFCell cell2 = row.createCell((short) 1); HSSFCell cell2 = row.createCell((short) 1);
cell.setCellValue(new HSSFRichTextString("clone_test")); cell.setCellValue(new HSSFRichTextString("clone_test"));
cell2.setCellFormula("sin(1)"); cell2.setCellFormula("sin(1)");
HSSFSheet clonedSheet = workbook.cloneSheet(0); HSSFSheet clonedSheet = workbook.cloneSheet(0);
HSSFRow clonedRow = clonedSheet.getRow(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"));
assertNotNull(workbook.getSheet("Test Clone(1)")); 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 * Setting landscape and portrait stuff on existing sheets
*/ */
public void testPrintSetupLandscapeExisting() throws Exception { public void testPrintSetupLandscapeExisting() {
HSSFWorkbook workbook = openSample("SimpleWithPageBreaks.xls"); HSSFWorkbook workbook = openSample("SimpleWithPageBreaks.xls");
assertEquals(3, workbook.getNumberOfSheets()); assertEquals(3, workbook.getNumberOfSheets());
@ -306,9 +284,7 @@ public final class TestHSSFSheet extends TestCase {
assertEquals(1, sheetLS.getPrintSetup().getCopies()); assertEquals(1, sheetLS.getPrintSetup().getCopies());
// Save and re-load, and check still there // Save and re-load, and check still there
ByteArrayOutputStream baos = new ByteArrayOutputStream(); workbook = HSSFTestDataSamples.writeOutAndReadBack(workbook);
workbook.write(baos);
workbook = new HSSFWorkbook(new ByteArrayInputStream(baos.toByteArray()));
assertTrue(sheetL.getPrintSetup().getLandscape()); assertTrue(sheetL.getPrintSetup().getLandscape());
assertFalse(sheetPM.getPrintSetup().getLandscape()); assertFalse(sheetPM.getPrintSetup().getLandscape());
@ -318,7 +294,7 @@ public final class TestHSSFSheet extends TestCase {
assertEquals(1, sheetLS.getPrintSetup().getCopies()); assertEquals(1, sheetLS.getPrintSetup().getCopies());
} }
public void testGroupRows() throws Exception { public void testGroupRows() {
HSSFWorkbook workbook = new HSSFWorkbook(); HSSFWorkbook workbook = new HSSFWorkbook();
HSSFSheet s = workbook.createSheet(); HSSFSheet s = workbook.createSheet();
HSSFRow r1 = s.createRow(0); HSSFRow r1 = s.createRow(0);
@ -342,11 +318,7 @@ public final class TestHSSFSheet extends TestCase {
assertEquals(0, r5.getOutlineLevel()); assertEquals(0, r5.getOutlineLevel());
// Save and re-open // Save and re-open
ByteArrayOutputStream baos = new ByteArrayOutputStream(); workbook = HSSFTestDataSamples.writeOutAndReadBack(workbook);
workbook.write(baos);
workbook = new HSSFWorkbook(
new ByteArrayInputStream(baos.toByteArray())
);
s = workbook.getSheetAt(0); s = workbook.getSheetAt(0);
r1 = s.getRow(0); r1 = s.getRow(0);
@ -362,7 +334,7 @@ public final class TestHSSFSheet extends TestCase {
assertEquals(0, r5.getOutlineLevel()); assertEquals(0, r5.getOutlineLevel());
} }
public void testGroupRowsExisting() throws Exception { public void testGroupRowsExisting() {
HSSFWorkbook workbook = openSample("NoGutsRecords.xls"); HSSFWorkbook workbook = openSample("NoGutsRecords.xls");
HSSFSheet s = workbook.getSheetAt(0); HSSFSheet s = workbook.getSheetAt(0);
@ -391,11 +363,11 @@ public final class TestHSSFSheet extends TestCase {
assertEquals(0, r6.getOutlineLevel()); assertEquals(0, r6.getOutlineLevel());
// Save and re-open // Save and re-open
ByteArrayOutputStream baos = new ByteArrayOutputStream(); try {
workbook.write(baos); workbook = HSSFTestDataSamples.writeOutAndReadBack(workbook);
workbook = new HSSFWorkbook( } catch (OutOfMemoryError e) {
new ByteArrayInputStream(baos.toByteArray()) throw new AssertionFailedError("Identified bug 39903");
); }
s = workbook.getSheetAt(0); s = workbook.getSheetAt(0);
r1 = s.getRow(0); r1 = s.getRow(0);
@ -413,7 +385,7 @@ public final class TestHSSFSheet extends TestCase {
assertEquals(0, r6.getOutlineLevel()); assertEquals(0, r6.getOutlineLevel());
} }
public void testGetDrawings() throws Exception { public void testGetDrawings() {
HSSFWorkbook wb1c = openSample("WithChart.xls"); HSSFWorkbook wb1c = openSample("WithChart.xls");
HSSFWorkbook wb2c = openSample("WithTwoCharts.xls"); HSSFWorkbook wb2c = openSample("WithTwoCharts.xls");
@ -440,7 +412,7 @@ public final class TestHSSFSheet extends TestCase {
HSSFSheet hssfSheet = workbook.createSheet(); HSSFSheet hssfSheet = workbook.createSheet();
Sheet sheet = hssfSheet.getSheet(); Sheet sheet = hssfSheet.getSheet();
ProtectRecord protect = sheet.getProtect(); ProtectRecord protect = sheet.getProtect();
assertFalse(protect.getProtect()); assertFalse(protect.getProtect());
// This will tell us that cloneSheet, and by extension, // This will tell us that cloneSheet, and by extension,
@ -454,12 +426,12 @@ public final class TestHSSFSheet extends TestCase {
public void testProtectSheet() { public void testProtectSheet() {
short expected = (short)0xfef1; short expected = (short)0xfef1;
HSSFWorkbook wb = new HSSFWorkbook(); HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet s = wb.createSheet(); HSSFSheet s = wb.createSheet();
s.protectSheet("abcdefghij"); s.protectSheet("abcdefghij");
Sheet sheet = s.getSheet(); Sheet sheet = s.getSheet();
ProtectRecord protect = sheet.getProtect(); ProtectRecord protect = sheet.getProtect();
PasswordRecord pass = sheet.getPassword(); PasswordRecord pass = sheet.getPassword();
assertTrue("protection should be on",protect.getProtect()); assertTrue("protection should be on",protect.getProtect());
assertTrue("object protection should be on",sheet.isProtected()[1]); assertTrue("object protection should be on",sheet.isProtected()[1]);
assertTrue("scenario protection should be on",sheet.isProtected()[2]); assertTrue("scenario protection should be on",sheet.isProtected()[2]);
@ -467,9 +439,7 @@ public final class TestHSSFSheet extends TestCase {
} }
public void testZoom() public void testZoom() {
throws Exception
{
HSSFWorkbook wb = new HSSFWorkbook(); HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet sheet = wb.createSheet(); HSSFSheet sheet = wb.createSheet();
assertEquals(-1, sheet.getSheet().findFirstRecordLocBySid(SCLRecord.sid)); 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 sclLoc = sheet.getSheet().findFirstRecordLocBySid(SCLRecord.sid);
int window2Loc = sheet.getSheet().findFirstRecordLocBySid(WindowTwoRecord.sid); int window2Loc = sheet.getSheet().findFirstRecordLocBySid(WindowTwoRecord.sid);
assertTrue(sclLoc == window2Loc + 1); assertTrue(sclLoc == window2Loc + 1);
} }
@ -493,7 +462,7 @@ public final class TestHSSFSheet extends TestCase {
public void testRemoveMerged() { public void testRemoveMerged() {
HSSFWorkbook wb = new HSSFWorkbook(); HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet sheet = wb.createSheet(); 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); sheet.addMergedRegion(region);
region = new Region(1, (short)0, 2, (short)1); region = new Region(1, (short)0, 2, (short)1);
sheet.addMergedRegion(region); 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()); assertTrue("there isn't more than one merged region in there", 1 <= sheet.getNumMergedRegions());
region = sheet.getMergedRegionAt(0); region = sheet.getMergedRegionAt(0);
assertEquals("the merged row to doesnt match the one we put in ", 4, region.getRowTo()); assertEquals("the merged row to doesnt match the one we put in ", 4, region.getRowTo());
} }
public void testShiftMerged() { public void testShiftMerged() {
@ -536,33 +504,25 @@ public final class TestHSSFSheet extends TestCase {
cell = row.createCell((short)1); cell = row.createCell((short)1);
cell.setCellValue(new HSSFRichTextString("second row, second cell")); 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.addMergedRegion(region);
sheet.shiftRows(1, 1, 1); sheet.shiftRows(1, 1, 1);
region = sheet.getMergedRegionAt(0); region = sheet.getMergedRegionAt(0);
assertEquals("Merged region not moved over to row 2", 2, region.getRowFrom()); assertEquals("Merged region not moved over to row 2", 2, region.getRowFrom());
} }
/** /**
* Tests the display of gridlines, formulas, and rowcolheadings. * Tests the display of gridlines, formulas, and rowcolheadings.
* @author Shawn Laubach (slaubach at apache dot org) * @author Shawn Laubach (slaubach at apache dot org)
*/ */
public void testDisplayOptions() throws Exception { public void testDisplayOptions() {
HSSFWorkbook wb = new HSSFWorkbook(); HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet sheet = wb.createSheet(); HSSFSheet sheet = wb.createSheet();
File tempFile = TempFile.createTempFile("display", "test.xls"); wb = HSSFTestDataSamples.writeOutAndReadBack(wb);
FileOutputStream stream = new FileOutputStream(tempFile);
wb.write(stream);
stream.close();
FileInputStream readStream = new FileInputStream(tempFile);
wb = new HSSFWorkbook(readStream);
sheet = wb.getSheetAt(0); sheet = wb.getSheetAt(0);
readStream.close();
assertEquals(sheet.isDisplayGridlines(), true); assertEquals(sheet.isDisplayGridlines(), true);
assertEquals(sheet.isDisplayRowColHeadings(), true); assertEquals(sheet.isDisplayRowColHeadings(), true);
@ -572,16 +532,8 @@ public final class TestHSSFSheet extends TestCase {
sheet.setDisplayRowColHeadings(false); sheet.setDisplayRowColHeadings(false);
sheet.setDisplayFormulas(true); sheet.setDisplayFormulas(true);
tempFile = TempFile.createTempFile("display", "test.xls"); wb = HSSFTestDataSamples.writeOutAndReadBack(wb);
stream = new FileOutputStream(tempFile);
wb.write(stream);
stream.close();
readStream = new FileInputStream(tempFile);
wb = new HSSFWorkbook(readStream);
sheet = wb.getSheetAt(0); sheet = wb.getSheetAt(0);
readStream.close();
assertEquals(sheet.isDisplayGridlines(), false); assertEquals(sheet.isDisplayGridlines(), false);
assertEquals(sheet.isDisplayRowColHeadings(), false); assertEquals(sheet.isDisplayRowColHeadings(), false);
@ -593,7 +545,7 @@ public final class TestHSSFSheet extends TestCase {
* Make sure the excel file loads work * Make sure the excel file loads work
* *
*/ */
public void testPageBreakFiles() throws Exception{ public void testPageBreakFiles() {
HSSFWorkbook wb = openSample("SimpleWithPageBreaks.xls"); HSSFWorkbook wb = openSample("SimpleWithPageBreaks.xls");
HSSFSheet sheet = wb.getSheetAt(0); HSSFSheet sheet = wb.getSheetAt(0);
@ -611,27 +563,19 @@ public final class TestHSSFSheet extends TestCase {
assertEquals("row breaks number", 2, sheet.getRowBreaks().length); assertEquals("row breaks number", 2, sheet.getRowBreaks().length);
assertEquals("column breaks number", 2, sheet.getColumnBreaks().length); assertEquals("column breaks number", 2, sheet.getColumnBreaks().length);
File tempFile = TempFile.createTempFile("display", "testPagebreaks.xls"); wb = HSSFTestDataSamples.writeOutAndReadBack(wb);
FileOutputStream stream = new FileOutputStream(tempFile);
wb.write(stream);
stream.close();
wb = new HSSFWorkbook(new FileInputStream(tempFile));
sheet = wb.getSheetAt(0); sheet = wb.getSheetAt(0);
assertTrue("No row page break", sheet.isRowBroken(22)); assertTrue("No row page break", sheet.isRowBroken(22));
assertTrue("No column page break", sheet.isColumnBroken((short)4)); assertTrue("No column page break", sheet.isColumnBroken((short)4));
assertEquals("row breaks number", 2, sheet.getRowBreaks().length); assertEquals("row breaks number", 2, sheet.getRowBreaks().length);
assertEquals("column breaks number", 2, sheet.getColumnBreaks().length); assertEquals("column breaks number", 2, sheet.getColumnBreaks().length);
} }
public void testDBCSName () throws Exception { public void testDBCSName () {
HSSFWorkbook wb = openSample("DBCSSheetName.xls"); 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 2", wb.getSheetName(1),"\u090f\u0915" );
assertEquals("DBCS Sheet Name 1", wb.getSheetName(0),"\u091c\u093e"); 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 //try to add 5 empty rows to a new sheet
HSSFWorkbook workbook = new HSSFWorkbook(); HSSFWorkbook workbook = new HSSFWorkbook();
HSSFSheet sheet = workbook.createSheet(); HSSFSheet sheet = workbook.createSheet();
for (int i = 0; i < 5; i++) sheet.createRow(i); for (int i = 0; i < 5; i++) {
sheet.createRow(i);
}
ByteArrayOutputStream out = new ByteArrayOutputStream(); workbook = HSSFTestDataSamples.writeOutAndReadBack(workbook);
workbook.write(out);
out.close();
workbook = new HSSFWorkbook(new ByteArrayInputStream(out.toByteArray()));
//try adding empty rows in an existing worksheet //try adding empty rows in an existing worksheet
workbook = openSample("Simple.xls"); workbook = openSample("Simple.xls");
@ -702,14 +644,10 @@ public final class TestHSSFSheet extends TestCase {
sheet = workbook.getSheetAt(0); sheet = workbook.getSheetAt(0);
for (int i = 3; i < 10; i++) sheet.createRow(i); for (int i = 3; i < 10; i++) sheet.createRow(i);
out = new ByteArrayOutputStream(); workbook = HSSFTestDataSamples.writeOutAndReadBack(workbook);
workbook.write(out);
out.close();
workbook = new HSSFWorkbook(new ByteArrayInputStream(out.toByteArray()));
} }
public void testAutoSizeColumn() throws Exception { public void testAutoSizeColumn() {
HSSFWorkbook wb = openSample("43902.xls"); HSSFWorkbook wb = openSample("43902.xls");
String sheetName = "my sheet"; String sheetName = "my sheet";
HSSFSheet sheet = wb.getSheet(sheetName); HSSFSheet sheet = wb.getSheet(sheetName);
@ -719,7 +657,7 @@ public final class TestHSSFSheet extends TestCase {
// machines based on the fonts available. // machines based on the fonts available.
// So, we use ranges, which are pretty large, but // So, we use ranges, which are pretty large, but
// thankfully don't overlap! // thankfully don't overlap!
int minWithRow1And2 = 6400; int minWithRow1And2 = 6400;
int maxWithRow1And2 = 7800; int maxWithRow1And2 = 7800;
int minWithRow1Only = 2750; int minWithRow1Only = 2750;
int maxWithRow1Only = 3300; 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 //create a region over the 2nd row and auto size the first column
sheet.addMergedRegion(new Region(1,(short)0,1,(short)1)); sheet.addMergedRegion(new Region(1,(short)0,1,(short)1));
sheet.autoSizeColumn((short)0); sheet.autoSizeColumn((short)0);
ByteArrayOutputStream out = new ByteArrayOutputStream(); HSSFWorkbook wb2 = HSSFTestDataSamples.writeOutAndReadBack(wb);
wb.write(out);
out.close();
// 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) // because it is included in a merged region (Excel like behavior)
HSSFWorkbook wb2 = new HSSFWorkbook(new ByteArrayInputStream(out.toByteArray()));
HSSFSheet sheet2 = wb2.getSheet(sheetName); HSSFSheet sheet2 = wb2.getSheet(sheetName);
assertTrue(sheet2.getColumnWidth((short)0) >= minWithRow1Only); assertTrue(sheet2.getColumnWidth((short)0) >= minWithRow1Only);
assertTrue(sheet2.getColumnWidth((short)0) <= maxWithRow1Only); 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 // remove the 2nd row merged region and check that the 2nd row value is used to the autoSizeColumn width
sheet2.removeMergedRegion(1); sheet2.removeMergedRegion(1);
sheet2.autoSizeColumn((short)0); sheet2.autoSizeColumn((short)0);
out = new ByteArrayOutputStream(); HSSFWorkbook wb3 = HSSFTestDataSamples.writeOutAndReadBack(wb2);
wb2.write(out);
out.close();
HSSFWorkbook wb3 = new HSSFWorkbook(new ByteArrayInputStream(out.toByteArray()));
HSSFSheet sheet3 = wb3.getSheet(sheetName); HSSFSheet sheet3 = wb3.getSheet(sheetName);
assertTrue(sheet3.getColumnWidth((short)0) >= minWithRow1And2); assertTrue(sheet3.getColumnWidth((short)0) >= minWithRow1And2);
assertTrue(sheet3.getColumnWidth((short)0) <= maxWithRow1And2); assertTrue(sheet3.getColumnWidth((short)0) <= maxWithRow1And2);
@ -827,7 +759,7 @@ public final class TestHSSFSheet extends TestCase {
assertTrue(wb3.getSheetAt(3).getForceFormulaRecalculation()); assertTrue(wb3.getSheetAt(3).getForceFormulaRecalculation());
} }
public void testColumnWidth() throws Exception { public void testColumnWidth() {
//check we can correctly read column widths from a reference workbook //check we can correctly read column widths from a reference workbook
HSSFWorkbook wb = openSample("colwidth.xls"); HSSFWorkbook wb = openSample("colwidth.xls");
@ -867,11 +799,8 @@ public final class TestHSSFSheet extends TestCase {
} }
//serialize and read again //serialize and read again
ByteArrayOutputStream out = new ByteArrayOutputStream(); wb = HSSFTestDataSamples.writeOutAndReadBack(wb);
wb.write(out);
out.close();
wb = new HSSFWorkbook(new ByteArrayInputStream(out.toByteArray()));
sh = wb.getSheetAt(0); sh = wb.getSheetAt(0);
assertEquals(10, sh.getDefaultColumnWidth()); assertEquals(10, sh.getDefaultColumnWidth());
//columns A-C have default width //columns A-C have default width

View File

@ -20,12 +20,16 @@ package org.apache.poi.hssf.usermodel;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.List;
import junit.framework.AssertionFailedError; import junit.framework.AssertionFailedError;
import junit.framework.TestCase; import junit.framework.TestCase;
import org.apache.poi.hssf.HSSFTestDataSamples; 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.NameRecord;
import org.apache.poi.hssf.record.Record;
import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.util.TempFile; import org.apache.poi.util.TempFile;
/** /**
* *
@ -376,4 +380,49 @@ public final class TestHSSFWorkbook extends TestCase {
assertEquals("active", expectedActive, sheet.isActive()); assertEquals("active", expectedActive, sheet.isActive());
assertEquals("selected", expectedSelected, sheet.isSelected()); 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;
}
}
}

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

View File

@ -45,8 +45,8 @@ public final class TestSheetHiding extends TestCase {
*/ */
public void testTextSheets() throws Exception { public void testTextSheets() throws Exception {
// Both should have two sheets // Both should have two sheets
assertEquals(2, wbH.sheets.size()); assertEquals(2, wbH.getNumberOfSheets());
assertEquals(2, wbU.sheets.size()); assertEquals(2, wbU.getNumberOfSheets());
// All sheets should have one row // All sheets should have one row
assertEquals(0, wbH.getSheetAt(0).getLastRowNum()); assertEquals(0, wbH.getSheetAt(0).getLastRowNum());