merged with trunk r670185

git-svn-id: https://svn.apache.org/repos/asf/poi/tags/REL_3_1_FINAL@670186 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Yegor Kozlov 2008-06-21 12:03:44 +00:00
parent 6a0a80a25d
commit 2b835e6c19
175 changed files with 6871 additions and 5818 deletions

View File

@ -135,7 +135,7 @@ under the License.
<property name="mavendist.poi.dir" location="build/maven-dist/poi"/>
<property name="mavendist.oap.dir" location="build/maven-dist/org.apache.poi"/>
<property name="jar.name" value="poi"/>
<property name="version.id" value="3.1-beta2"/>
<property name="version.id" value="3.1-beta3"/>
<property name="halt.on.test.failure" value="true"/>
<property name="jdk.version.source" value="1.3"
description="JDK version of source code"/>
@ -170,6 +170,7 @@ under the License.
<path id="examples.classpath">
<path refid="main.classpath"/>
<pathelement location="${main.output.dir}"/>
<pathelement location="${scratchpad.output.dir}"/>
</path>

View File

@ -10,14 +10,6 @@ Common Public License Version 1.0:
http://www.opensource.org/licenses/cpl.php
See http://www.junit.org/
A single data file of the POI component HDGF is based on VSDump,
and is under the GNU General Public Licence version 3 (GPL v3):
http://gplv3.fsf.org/
Since this is a data file, and has no compiled version (the original
file is distributed in both source and binary versions), there should
be little difference in licencing requirements compared to the ASL.
See http://www.gnome.ru/projects/vsdump_en.html
The Office Open XML experimental support had additional dependencies,
with their own licensing:

View File

@ -36,6 +36,34 @@
</devs>
<!-- Don't forget to update status.xml too! -->
<release version="3.1-final" date="2008-06-??">
<action dev="POI-DEVELOPERS" type="fix">30978 - Fixed re-serialization of tRefErr3d and tAreaErr3d</action>
<action dev="POI-DEVELOPERS" type="fix">45234 - Removed incorrect shared formula conversion in CFRuleRecord</action>
<action dev="POI-DEVELOPERS" type="fix">45001 - Improved HWPF Range.replaceText()</action>
<action dev="POI-DEVELOPERS" type="fix">44692 - Fixed HSSFPicture.resize() to properly resize pictures if the underlying columns/rows have modified size</action>
<action dev="POI-DEVELOPERS" type="add">Support custom image renderers in HSLF</action>
<action dev="POI-DEVELOPERS" type="fix">Correctly increment the reference count of a blip when a picture is inserted</action>
<action dev="POI-DEVELOPERS" type="fix">45110 - Fixed TextShape.resizeToFitText() to properly resize TextShape</action>
<action dev="POI-DEVELOPERS" type="fix">45091 - Fixed serialization of RefN~ tokens. Simplified Ptg class hierarchy</action>
<action dev="POI-DEVELOPERS" type="fix">45133 - Fixed OBJ Record (5Dh) to pad the sub-record data to a 4-byte boundary</action>
<action dev="POI-DEVELOPERS" type="fix">45145 - Fixed Sheet to always enforce RowRecordsAggregate before ValueRecordsAggregate</action>
<action dev="POI-DEVELOPERS" type="fix">45123 - Fixed SharedFormulaRecord.convertSharedFormulas() to propagate token operand classes</action>
<action dev="POI-DEVELOPERS" type="fix">45087 - Correctly detect date formats like [Black]YYYY as being date based</action>
<action dev="POI-DEVELOPERS" type="add">45060 - Improved token class transformation during formula parsing</action>
<action dev="POI-DEVELOPERS" type="add">44840 - Improved handling of HSSFObjectData, especially for entries with data held not in POIFS</action>
<action dev="POI-DEVELOPERS" type="add">45043 - Support for getting excel cell comments when extracting text</action>
<action dev="POI-DEVELOPERS" type="add">Extend the support for specifying a policy to HSSF on missing / blank cells when fetching, to be able to specify the policy at the HSSFWorkbook level</action>
<action dev="POI-DEVELOPERS" type="fix">45025 - improved FormulaParser parse error messages</action>
<action dev="POI-DEVELOPERS" type="fix">45046 - allowed EXTERNALBOOK(0x01AE) to be optional in the LinkTable</action>
<action dev="POI-DEVELOPERS" type="fix">45066 - fixed sheet encoding size mismatch problems</action>
<action dev="POI-DEVELOPERS" type="add">45003 - Support embeded HDGF visio documents</action>
<action dev="POI-DEVELOPERS" type="fix">45001 - Partial fix for HWPF Range.insertBefore() and Range.delete() with unicode characters</action>
<action dev="POI-DEVELOPERS" type="fix">44977 - Support for AM/PM in excel date formats</action>
<action dev="POI-DEVELOPERS" type="add">Support for specifying a policy to HSSF on missing / blank cells when fetching</action>
<action dev="POI-DEVELOPERS" type="add">44937 - Partial support for extracting Escher images from HWPF files</action>
<action dev="POI-DEVELOPERS" type="fix">44824 - Avoid an infinite loop when reading some HWPF pictures</action>
<action dev="POI-DEVELOPERS" type="fix">44898 - Correctly handle short last blocks in POIFS</action>
</release>
<release version="3.1-beta2" date="2008-05-26">
<action dev="POI-DEVELOPERS" type="fix">44306 - fixed reading/writing of AttrPtg(type=choose) and method toFormulaString() for CHOOSE formulas</action>
<action dev="POI-DEVELOPERS" type="fix">24207 - added HSSFName.isDeleted() to check if the name points to cell that no longer exists</action>

View File

@ -31,9 +31,9 @@
</header>
<body>
<section><title>POI 3.1-BETA1 Released (2008-04028)</title>
<section><title>POI 3.1-BETA2 Released (2008-05-28)</title>
<p>
The POI team is pleased to announce the release of 3.1 BETA1 which is one of the final steps before 3.1 FINAL.
The POI team is pleased to announce the release of 3.1 BETA2 which is one of the final steps before 3.1 FINAL.
The status of this release is a beta, meaning that we encourage users to try it out.
If you find any bugs, please report them to the POI <link href="https://issues.apache.org/bugzilla/buglist.cgi?product=POI">bug database</link> or to
the <link href="./mailinglists.html">POI Developer List</link>.
@ -45,7 +45,7 @@
</p>
<p>
The release is also available from the central Maven repository
under Group ID "org.apache.poi" and Version "3.1-beta1".
under Group ID "org.apache.poi" and Version "3.1-beta2".
</p>
</section>
<section><title>POI 3.0.2 Released</title>

View File

@ -33,6 +33,34 @@
<!-- Don't forget to update changes.xml too! -->
<changes>
<release version="3.1-final" date="2008-06-??">
<action dev="POI-DEVELOPERS" type="fix">30978 - Fixed re-serialization of tRefErr3d and tAreaErr3d</action>
<action dev="POI-DEVELOPERS" type="fix">45234 - Removed incorrect shared formula conversion in CFRuleRecord</action>
<action dev="POI-DEVELOPERS" type="fix">45001 - Improved HWPF Range.replaceText()</action>
<action dev="POI-DEVELOPERS" type="fix">44692 - Fixed HSSFPicture.resize() to properly resize pictures if the underlying columns/rows have modified size</action>
<action dev="POI-DEVELOPERS" type="add">Support custom image renderers in HSLF</action>
<action dev="POI-DEVELOPERS" type="fix">Correctly increment the reference count of a blip when a picture is inserted</action>
<action dev="POI-DEVELOPERS" type="fix">45110 - Fixed TextShape.resizeToFitText() to properly resize TextShape</action>
<action dev="POI-DEVELOPERS" type="fix">45091 - Fixed serialization of RefN~ tokens. Simplified Ptg class hierarchy</action>
<action dev="POI-DEVELOPERS" type="fix">45133 - Fixed OBJ Record (5Dh) to pad the sub-record data to a 4-byte boundary</action>
<action dev="POI-DEVELOPERS" type="fix">45145 - Fixed Sheet to always enforce RowRecordsAggregate before ValueRecordsAggregate</action>
<action dev="POI-DEVELOPERS" type="fix">45123 - Fixed SharedFormulaRecord.convertSharedFormulas() to propagate token operand classes</action>
<action dev="POI-DEVELOPERS" type="fix">45087 - Correctly detect date formats like [Black]YYYY as being date based</action>
<action dev="POI-DEVELOPERS" type="add">45060 - Improved token class transformation during formula parsing</action>
<action dev="POI-DEVELOPERS" type="add">44840 - Improved handling of HSSFObjectData, especially for entries with data held not in POIFS</action>
<action dev="POI-DEVELOPERS" type="add">45043 - Support for getting excel cell comments when extracting text</action>
<action dev="POI-DEVELOPERS" type="add">Extend the support for specifying a policy to HSSF on missing / blank cells when fetching, to be able to specify the policy at the HSSFWorkbook level</action>
<action dev="POI-DEVELOPERS" type="fix">45025 - improved FormulaParser parse error messages</action>
<action dev="POI-DEVELOPERS" type="fix">45046 - allowed EXTERNALBOOK(0x01AE) to be optional in the LinkTable</action>
<action dev="POI-DEVELOPERS" type="fix">45066 - fixed sheet encoding size mismatch problems</action>
<action dev="POI-DEVELOPERS" type="add">45003 - Support embeded HDGF visio documents</action>
<action dev="POI-DEVELOPERS" type="fix">45001 - Partial fix for HWPF Range.insertBefore() and Range.delete() with unicode characters</action>
<action dev="POI-DEVELOPERS" type="fix">44977 - Support for AM/PM in excel date formats</action>
<action dev="POI-DEVELOPERS" type="add">Support for specifying a policy to HSSF on missing / blank cells when fetching</action>
<action dev="POI-DEVELOPERS" type="add">44937 - Partial support for extracting Escher images from HWPF files</action>
<action dev="POI-DEVELOPERS" type="fix">44824 - Avoid an infinite loop when reading some HWPF pictures</action>
<action dev="POI-DEVELOPERS" type="fix">44898 - Correctly handle short last blocks in POIFS</action>
</release>
<release version="3.1-beta2" date="2008-05-26">
<action dev="POI-DEVELOPERS" type="fix">44306 - fixed reading/writing of AttrPtg(type=choose) and method toFormulaString() for CHOOSE formulas</action>
<action dev="POI-DEVELOPERS" type="fix">24207 - added HSSFName.isDeleted() to check if the name points to cell that no longer exists</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.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Iterator;
import java.util.List;
@ -191,6 +192,11 @@ public abstract class POIDocument {
System.err.println("Couldn't write property set with name " + name + " as not supported by HPSF yet");
}
}
/**
* Writes the document out to the specified output stream
*/
public abstract void write(OutputStream out) throws IOException;
/**
* Copies nodes from one POIFS to the other minus the excepts

View File

@ -65,20 +65,27 @@ public class EscherClientAnchorRecord
int size = 0;
// Always find 4 two byte entries. Sometimes find 9
field_1_flag = LittleEndian.getShort( data, pos + size ); size += 2;
field_2_col1 = LittleEndian.getShort( data, pos + size ); size += 2;
field_3_dx1 = LittleEndian.getShort( data, pos + size ); size += 2;
field_4_row1 = LittleEndian.getShort( data, pos + size ); size += 2;
if(bytesRemaining >= 18) {
field_5_dy1 = LittleEndian.getShort( data, pos + size ); size += 2;
field_6_col2 = LittleEndian.getShort( data, pos + size ); size += 2;
field_7_dx2 = LittleEndian.getShort( data, pos + size ); size += 2;
field_8_row2 = LittleEndian.getShort( data, pos + size ); size += 2;
field_9_dy2 = LittleEndian.getShort( data, pos + size ); size += 2;
shortRecord = false;
} else {
shortRecord = true;
}
if (bytesRemaining == 4) // Word format only 4 bytes
{
// Not sure exactly what the format is quite yet, likely a reference to a PLC
}
else
{
field_1_flag = LittleEndian.getShort( data, pos + size ); size += 2;
field_2_col1 = LittleEndian.getShort( data, pos + size ); size += 2;
field_3_dx1 = LittleEndian.getShort( data, pos + size ); size += 2;
field_4_row1 = LittleEndian.getShort( data, pos + size ); size += 2;
if(bytesRemaining >= 18) {
field_5_dy1 = LittleEndian.getShort( data, pos + size ); size += 2;
field_6_col2 = LittleEndian.getShort( data, pos + size ); size += 2;
field_7_dx2 = LittleEndian.getShort( data, pos + size ); size += 2;
field_8_row2 = LittleEndian.getShort( data, pos + size ); size += 2;
field_9_dy2 = LittleEndian.getShort( data, pos + size ); size += 2;
shortRecord = false;
} else {
shortRecord = true;
}
}
bytesRemaining -= size;
remainingData = new byte[bytesRemaining];
System.arraycopy( data, pos + size, remainingData, 0, bytesRemaining );

View File

@ -238,6 +238,10 @@ public class EscherDggRecord
return maxDgId;
}
public void setMaxDrawingGroupId(int id){
maxDgId = id;
}
public FileIdCluster[] getFileIdClusters()
{
return field_5_fileIdClusters;

View File

@ -87,7 +87,8 @@ public final class BiffViewer {
records.add(record);
if (activeRecord != null)
activeRecord.dump(ps);
activeRecord = new RecordDetails(recStream.getSid(), recStream.getLength(), (int)recStream.getPos(), record);
int startPos = (int)(recStream.getPos()-recStream.getLength() - 4);
activeRecord = new RecordDetails(recStream.getSid(), recStream.getLength(), startPos, record);
}
if (dump) {
recStream.dumpBytes(ps);

View File

@ -20,6 +20,7 @@ import java.io.IOException;
import org.apache.poi.POIOLE2TextExtractor;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFComment;
import org.apache.poi.hssf.usermodel.HSSFRichTextString;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
@ -39,6 +40,7 @@ public class ExcelExtractor extends POIOLE2TextExtractor {
private HSSFWorkbook wb;
private boolean includeSheetNames = true;
private boolean formulasNotResults = false;
private boolean includeCellComments = false;
public ExcelExtractor(HSSFWorkbook wb) {
super(wb);
@ -62,6 +64,12 @@ public class ExcelExtractor extends POIOLE2TextExtractor {
public void setFormulasNotResults(boolean formulasNotResults) {
this.formulasNotResults = formulasNotResults;
}
/**
* Should cell comments be included? Default is true
*/
public void setIncludeCellComments(boolean includeCellComments) {
this.includeCellComments = includeCellComments;
}
/**
* Retreives the text contents of the file
@ -128,6 +136,15 @@ public class ExcelExtractor extends POIOLE2TextExtractor {
break;
}
// Output the comment, if requested and exists
HSSFComment comment = cell.getCellComment();
if(includeCellComments && comment != null) {
// Replace any newlines with spaces, otherwise it
// breaks the output
String commentText = comment.getString().getString().replace('\n', ' ');
text.append(" Comment by "+comment.getAuthor()+": "+commentText);
}
// Output a tab if we're not on the last cell
if(outputContents && k < (lastCell-1)) {
text.append("\t");

View File

@ -18,7 +18,6 @@
package org.apache.poi.hssf.model;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Stack;
import java.util.regex.Pattern;
@ -55,23 +54,23 @@ public final class FormulaParser {
*/
static final class FormulaParseException extends RuntimeException {
// This class was given package scope until it would become clear that it is useful to
// general client code.
// general client code.
public FormulaParseException(String msg) {
super(msg);
}
}
public static int FORMULA_TYPE_CELL = 0;
public static int FORMULA_TYPE_SHARED = 1;
public static int FORMULA_TYPE_ARRAY =2;
public static int FORMULA_TYPE_CONDFOMRAT = 3;
public static int FORMULA_TYPE_NAMEDRANGE = 4;
public static final int FORMULA_TYPE_CELL = 0;
public static final int FORMULA_TYPE_SHARED = 1;
public static final int FORMULA_TYPE_ARRAY =2;
public static final int FORMULA_TYPE_CONDFOMRAT = 3;
public static final int FORMULA_TYPE_NAMEDRANGE = 4;
private final String formulaString;
private final int formulaLength;
private int pointer;
private final List tokens = new Stack();
private ParseNode _rootNode;
/**
* Used for spotting if we have a cell reference,
@ -127,39 +126,34 @@ public final class FormulaParser {
// Just return if so and reset 'look' to something to keep
// SkipWhitespace from spinning
look = (char)0;
}
}
pointer++;
//System.out.println("Got char: "+ look);
}
/** Report What Was Expected */
private RuntimeException expected(String s) {
return new FormulaParseException(s + " Expected");
String msg = "Parse error near char " + (pointer-1) + " '" + look + "'"
+ " in specified formula '" + formulaString + "'. Expected "
+ s;
return new FormulaParseException(msg);
}
/** Recognize an Alpha Character */
private boolean IsAlpha(char c) {
return Character.isLetter(c) || c == '$' || c=='_';
}
/** Recognize a Decimal Digit */
private boolean IsDigit(char c) {
//System.out.println("Checking digit for"+c);
return Character.isDigit(c);
}
/** Recognize an Alphanumeric */
private boolean IsAlNum(char c) {
return (IsAlpha(c) || IsDigit(c));
}
/** Recognize White Space */
private boolean IsWhite( char c) {
return (c ==' ' || c== TAB);
@ -175,7 +169,7 @@ public final class FormulaParser {
/**
* Consumes the next input character if it is equal to the one specified otherwise throws an
* unchecked exception. This method does <b>not</b> consume whitespace (before or after the
* matched character).
* matched character).
*/
private void Match(char x) {
if (look != x) {
@ -215,7 +209,6 @@ public final class FormulaParser {
return Token.toString();
}
/** Get a Number */
private String GetNum() {
StringBuffer value = new StringBuffer();
@ -227,14 +220,15 @@ public final class FormulaParser {
return value.length() == 0 ? null : value.toString();
}
/** Parse and Translate a String Identifier */
private Ptg parseIdent() {
String name;
name = GetName();
private ParseNode parseFunctionOrIdentifier() {
String name = GetName();
if (look == '('){
//This is a function
return function(name);
}
return new ParseNode(parseIdentifier(name));
}
private Ptg parseIdentifier(String name) {
if (look == ':' || look == '.') { // this is a AreaReference
GetChar();
@ -278,88 +272,45 @@ public final class FormulaParser {
// This can be either a cell ref or a named range
// Try to spot which it is
boolean cellRef = CELL_REFERENCE_PATTERN.matcher(name).matches();
if (cellRef) {
return new ReferencePtg(name);
return new RefPtg(name);
}
for(int i = 0; i < book.getNumberOfNames(); i++) {
// named range name matching is case insensitive
if(book.getNameAt(i).getNameName().equalsIgnoreCase(name)) {
if(book.getNameAt(i).getNameName().equalsIgnoreCase(name)) {
return new NamePtg(name, book);
}
}
throw new FormulaParseException("Found reference to named range \""
throw new FormulaParseException("Found reference to named range \""
+ name + "\", but that named range wasn't defined!");
}
/**
* Adds a pointer to the last token to the latest function argument list.
* @param obj
*/
private void addArgumentPointer(List argumentPointers) {
argumentPointers.add(tokens.get(tokens.size()-1));
}
/**
* Note - Excel function names are 'case aware but not case sensitive'. This method may end
* up creating a defined name record in the workbook if the specified name is not an internal
* Excel function, and has not been encountered before.
*
* @param name case preserved function name (as it was entered/appeared in the formula).
* Excel function, and has not been encountered before.
*
* @param name case preserved function name (as it was entered/appeared in the formula).
*/
private Ptg function(String name) {
int numArgs =0 ;
// Note regarding parameter -
private ParseNode function(String name) {
NamePtg nameToken = null;
// Note regarding parameter -
if(!AbstractFunctionPtg.isInternalFunctionName(name)) {
// external functions get a Name token which points to a defined name record
NamePtg nameToken = new NamePtg(name, this.book);
nameToken = new NamePtg(name, this.book);
// in the token tree, the name is more or less the first argument
numArgs++;
tokens.add(nameToken);
}
//average 2 args per function
List argumentPointers = new ArrayList(2);
Match('(');
numArgs += Arguments(argumentPointers);
ParseNode[] args = Arguments();
Match(')');
return getFunction(name, numArgs, argumentPointers);
return getFunction(name, nameToken, args);
}
/**
* Adds the size of all the ptgs after the provided index (inclusive).
* <p>
* Initially used to count a goto
* @param index
* @return int
*/
private int getPtgSize(int index) {
int count = 0;
Iterator ptgIterator = tokens.listIterator(index);
while (ptgIterator.hasNext()) {
Ptg ptg = (Ptg)ptgIterator.next();
count+=ptg.getSize();
}
return count;
}
private int getPtgSize(int start, int end) {
int count = 0;
int index = start;
Iterator ptgIterator = tokens.listIterator(index);
while (ptgIterator.hasNext() && index <= end) {
Ptg ptg = (Ptg)ptgIterator.next();
count+=ptg.getSize();
index++;
}
return count;
}
/**
* Generates the variable function ptg for the formula.
* <p>
@ -368,84 +319,35 @@ public final class FormulaParser {
* @param numArgs
* @return Ptg a null is returned if we're in an IF formula, it needs extreme manipulation and is handled in this function
*/
private AbstractFunctionPtg getFunction(String name, int numArgs, List argumentPointers) {
private ParseNode getFunction(String name, NamePtg namePtg, ParseNode[] args) {
boolean isVarArgs;
int funcIx;
FunctionMetadata fm = FunctionMetadataRegistry.getFunctionByName(name.toUpperCase());
int numArgs = args.length;
if(fm == null) {
if (namePtg == null) {
throw new IllegalStateException("NamePtg must be supplied for external functions");
}
// must be external function
isVarArgs = true;
funcIx = FunctionMetadataRegistry.FUNCTION_INDEX_EXTERNAL;
} else {
isVarArgs = !fm.hasFixedArgsLength();
funcIx = fm.getIndex();
validateNumArgs(numArgs, fm);
ParseNode[] allArgs = new ParseNode[numArgs+1];
allArgs[0] = new ParseNode(namePtg);
System.arraycopy(args, 0, allArgs, 1, numArgs);
return new ParseNode(new FuncVarPtg(name, (byte)(numArgs+1)), allArgs);
}
if (namePtg != null) {
throw new IllegalStateException("NamePtg no applicable to internal functions");
}
boolean isVarArgs = !fm.hasFixedArgsLength();
int funcIx = fm.getIndex();
validateNumArgs(args.length, fm);
AbstractFunctionPtg retval;
if(isVarArgs) {
retval = new FuncVarPtg(name, (byte)numArgs);
} else {
retval = new FuncPtg(funcIx);
}
if (!name.equals(AbstractFunctionPtg.FUNCTION_NAME_IF)) {
// early return for everything else besides IF()
return retval;
}
AttrPtg ifPtg = new AttrPtg();
ifPtg.setData((short)7); //mirroring excel output
ifPtg.setOptimizedIf(true);
if (argumentPointers.size() != 2 && argumentPointers.size() != 3) {
throw new IllegalArgumentException("["+argumentPointers.size()+"] Arguments Found - An IF formula requires 2 or 3 arguments. IF(CONDITION, TRUE_VALUE, FALSE_VALUE [OPTIONAL]");
}
//Biffview of an IF formula record indicates the attr ptg goes after the condition ptgs and are
//tracked in the argument pointers
//The beginning first argument pointer is the last ptg of the condition
int ifIndex = tokens.indexOf(argumentPointers.get(0))+1;
tokens.add(ifIndex, ifPtg);
//we now need a goto ptgAttr to skip to the end of the formula after a true condition
//the true condition is should be inserted after the last ptg in the first argument
int gotoIndex = tokens.indexOf(argumentPointers.get(1))+1;
AttrPtg goto1Ptg = new AttrPtg();
goto1Ptg.setGoto(true);
tokens.add(gotoIndex, goto1Ptg);
if (numArgs > 2) { //only add false jump if there is a false condition
//second goto to skip past the function ptg
AttrPtg goto2Ptg = new AttrPtg();
goto2Ptg.setGoto(true);
goto2Ptg.setData((short)(retval.getSize()-1));
//Page 472 of the Microsoft Excel Developer's kit states that:
//The b(or w) field specifies the number byes (or words to skip, minus 1
tokens.add(goto2Ptg); //this goes after all the arguments are defined
}
//data portion of the if ptg points to the false subexpression (Page 472 of MS Excel Developer's kit)
//count the number of bytes after the ifPtg to the False Subexpression
//doesn't specify -1 in the documentation
ifPtg.setData((short)(getPtgSize(ifIndex+1, gotoIndex)));
//count all the additional (goto) ptgs but dont count itself
int ptgCount = this.getPtgSize(gotoIndex)-goto1Ptg.getSize()+retval.getSize();
if (ptgCount > Short.MAX_VALUE) {
throw new RuntimeException("Ptg Size exceeds short when being specified for a goto ptg in an if");
}
goto1Ptg.setData((short)(ptgCount-1));
return retval;
return new ParseNode(retval, args);
}
private void validateNumArgs(int numArgs, FunctionMetadata fm) {
@ -474,99 +376,99 @@ public final class FormulaParser {
private static boolean isArgumentDelimiter(char ch) {
return ch == ',' || ch == ')';
}
/** get arguments to a function */
private int Arguments(List argumentPointers) {
private ParseNode[] Arguments() {
//average 2 args per function
List temp = new ArrayList(2);
SkipWhite();
if(look == ')') {
return 0;
return ParseNode.EMPTY_ARRAY;
}
boolean missedPrevArg = true;
int numArgs = 0;
while(true) {
while (true) {
SkipWhite();
if(isArgumentDelimiter(look)) {
if(missedPrevArg) {
tokens.add(new MissingArgPtg());
addArgumentPointer(argumentPointers);
if (isArgumentDelimiter(look)) {
if (missedPrevArg) {
temp.add(new ParseNode(MissingArgPtg.instance));
numArgs++;
}
if(look == ')') {
if (look == ')') {
break;
}
Match(',');
missedPrevArg = true;
continue;
}
comparisonExpression();
addArgumentPointer(argumentPointers);
temp.add(comparisonExpression());
numArgs++;
missedPrevArg = false;
SkipWhite();
if (!isArgumentDelimiter(look)) {
throw expected("',' or ')'");
}
}
return numArgs;
ParseNode[] result = new ParseNode[temp.size()];
temp.toArray(result);
return result;
}
/** Parse and Translate a Math Factor */
private void powerFactor() {
percentFactor();
private ParseNode powerFactor() {
ParseNode result = percentFactor();
while(true) {
SkipWhite();
if(look != '^') {
return;
return result;
}
Match('^');
percentFactor();
tokens.add(new PowerPtg());
ParseNode other = percentFactor();
result = new ParseNode(PowerPtg.instance, result, other);
}
}
private void percentFactor() {
tokens.add(parseSimpleFactor());
private ParseNode percentFactor() {
ParseNode result = parseSimpleFactor();
while(true) {
SkipWhite();
if(look != '%') {
return;
return result;
}
Match('%');
tokens.add(new PercentPtg());
result = new ParseNode(PercentPtg.instance, result);
}
}
/**
* factors (without ^ or % )
*/
private Ptg parseSimpleFactor() {
private ParseNode parseSimpleFactor() {
SkipWhite();
switch(look) {
case '#':
return parseErrorLiteral();
return new ParseNode(parseErrorLiteral());
case '-':
Match('-');
powerFactor();
return new UnaryMinusPtg();
return new ParseNode(UnaryMinusPtg.instance, powerFactor());
case '+':
Match('+');
powerFactor();
return new UnaryPlusPtg();
return new ParseNode(UnaryPlusPtg.instance, powerFactor());
case '(':
Match('(');
comparisonExpression();
ParseNode inside = comparisonExpression();
Match(')');
return new ParenthesisPtg();
return new ParseNode(ParenthesisPtg.instance, inside);
case '"':
return parseStringLiteral();
case ',':
case ')':
return new MissingArgPtg(); // TODO - not quite the right place to recognise a missing arg
return new ParseNode(parseStringLiteral());
}
if (IsAlpha(look) || look == '\''){
return parseIdent();
return parseFunctionOrIdentifier();
}
// else - assume number
return parseNumber();
return new ParseNode(parseNumber());
}
@ -704,10 +606,9 @@ public final class FormulaParser {
}
private StringPtg parseStringLiteral()
{
private StringPtg parseStringLiteral() {
Match('"');
StringBuffer token = new StringBuffer();
while (true) {
if (look == '"') {
@ -723,28 +624,30 @@ public final class FormulaParser {
}
/** Parse and Translate a Math Term */
private void Term() {
powerFactor();
private ParseNode Term() {
ParseNode result = powerFactor();
while(true) {
SkipWhite();
Ptg operator;
switch(look) {
case '*':
Match('*');
powerFactor();
tokens.add(new MultiplyPtg());
continue;
operator = MultiplyPtg.instance;
break;
case '/':
Match('/');
powerFactor();
tokens.add(new DividePtg());
continue;
operator = DividePtg.instance;
break;
default:
return result; // finished with Term
}
return; // finished with Term
ParseNode other = powerFactor();
result = new ParseNode(operator, result, other);
}
}
private void comparisonExpression() {
concatExpression();
private ParseNode comparisonExpression() {
ParseNode result = concatExpression();
while (true) {
SkipWhite();
switch(look) {
@ -752,72 +655,75 @@ public final class FormulaParser {
case '>':
case '<':
Ptg comparisonToken = getComparisonToken();
concatExpression();
tokens.add(comparisonToken);
ParseNode other = concatExpression();
result = new ParseNode(comparisonToken, result, other);
continue;
}
return; // finished with predicate expression
return result; // finished with predicate expression
}
}
private Ptg getComparisonToken() {
if(look == '=') {
Match(look);
return new EqualPtg();
return EqualPtg.instance;
}
boolean isGreater = look == '>';
Match(look);
if(isGreater) {
if(look == '=') {
Match('=');
return new GreaterEqualPtg();
return GreaterEqualPtg.instance;
}
return new GreaterThanPtg();
return GreaterThanPtg.instance;
}
switch(look) {
case '=':
Match('=');
return new LessEqualPtg();
return LessEqualPtg.instance;
case '>':
Match('>');
return new NotEqualPtg();
return NotEqualPtg.instance;
}
return new LessThanPtg();
return LessThanPtg.instance;
}
private void concatExpression() {
additiveExpression();
private ParseNode concatExpression() {
ParseNode result = additiveExpression();
while (true) {
SkipWhite();
if(look != '&') {
break; // finished with concat expression
}
Match('&');
additiveExpression();
tokens.add(new ConcatPtg());
ParseNode other = additiveExpression();
result = new ParseNode(ConcatPtg.instance, result, other);
}
return result;
}
/** Parse and Translate an Expression */
private void additiveExpression() {
Term();
private ParseNode additiveExpression() {
ParseNode result = Term();
while (true) {
SkipWhite();
Ptg operator;
switch(look) {
case '+':
Match('+');
Term();
tokens.add(new AddPtg());
continue;
operator = AddPtg.instance;
break;
case '-':
Match('-');
Term();
tokens.add(new SubtractPtg());
continue;
operator = SubtractPtg.instance;
break;
default:
return result; // finished with additive expression
}
return; // finished with additive expression
ParseNode other = Term();
result = new ParseNode(operator, result, other);
}
}
@ -835,17 +741,18 @@ end;
**/
/** API call to execute the parsing of the formula
*
/**
* API call to execute the parsing of the formula
* @deprecated use Ptg[] FormulaParser.parse(String, HSSFWorkbook) directly
*/
public void parse() {
pointer=0;
GetChar();
comparisonExpression();
_rootNode = comparisonExpression();
if(pointer <= formulaLength) {
String msg = "Unused input [" + formulaString.substring(pointer-1)
+ "] after attempting to parse the formula [" + formulaString + "]";
String msg = "Unused input [" + formulaString.substring(pointer-1)
+ "] after attempting to parse the formula [" + formulaString + "]";
throw new FormulaParseException(msg);
}
}
@ -860,92 +767,18 @@ end;
* a result of the parsing
*/
public Ptg[] getRPNPtg() {
return getRPNPtg(FORMULA_TYPE_CELL);
return getRPNPtg(FORMULA_TYPE_CELL);
}
public Ptg[] getRPNPtg(int formulaType) {
Node node = createTree();
setRootLevelRVA(node, formulaType);
setParameterRVA(node,formulaType);
return (Ptg[]) tokens.toArray(new Ptg[0]);
OperandClassTransformer oct = new OperandClassTransformer(formulaType);
// RVA is for 'operand class': 'reference', 'value', 'array'
oct.transformFormula(_rootNode);
return ParseNode.toTokenArray(_rootNode);
}
private void setRootLevelRVA(Node n, int formulaType) {
//Pg 16, excelfileformat.pdf @ openoffice.org
Ptg p = n.getValue();
if (formulaType == FormulaParser.FORMULA_TYPE_NAMEDRANGE) {
if (p.getDefaultOperandClass() == Ptg.CLASS_REF) {
setClass(n,Ptg.CLASS_REF);
} else {
setClass(n,Ptg.CLASS_ARRAY);
}
} else {
setClass(n,Ptg.CLASS_VALUE);
}
}
private void setParameterRVA(Node n, int formulaType) {
Ptg p = n.getValue();
int numOperands = n.getNumChildren();
if (p instanceof AbstractFunctionPtg) {
for (int i =0;i<numOperands;i++) {
setParameterRVA(n.getChild(i),((AbstractFunctionPtg)p).getParameterClass(i),formulaType);
// if (n.getChild(i).getValue() instanceof AbstractFunctionPtg) {
// setParameterRVA(n.getChild(i),formulaType);
// }
setParameterRVA(n.getChild(i),formulaType);
}
} else {
for (int i =0;i<numOperands;i++) {
setParameterRVA(n.getChild(i),formulaType);
}
}
}
private void setParameterRVA(Node n, int expectedClass,int formulaType) {
Ptg p = n.getValue();
if (expectedClass == Ptg.CLASS_REF) { //pg 15, table 1
if (p.getDefaultOperandClass() == Ptg.CLASS_REF ) {
setClass(n, Ptg.CLASS_REF);
}
if (p.getDefaultOperandClass() == Ptg.CLASS_VALUE) {
if (formulaType==FORMULA_TYPE_CELL || formulaType == FORMULA_TYPE_SHARED) {
setClass(n,Ptg.CLASS_VALUE);
} else {
setClass(n,Ptg.CLASS_ARRAY);
}
}
if (p.getDefaultOperandClass() == Ptg.CLASS_ARRAY ) {
setClass(n, Ptg.CLASS_ARRAY);
}
} else if (expectedClass == Ptg.CLASS_VALUE) { //pg 15, table 2
if (formulaType == FORMULA_TYPE_NAMEDRANGE) {
setClass(n,Ptg.CLASS_ARRAY) ;
} else {
setClass(n,Ptg.CLASS_VALUE);
}
} else { //Array class, pg 16.
if (p.getDefaultOperandClass() == Ptg.CLASS_VALUE &&
(formulaType==FORMULA_TYPE_CELL || formulaType == FORMULA_TYPE_SHARED)) {
setClass(n,Ptg.CLASS_VALUE);
} else {
setClass(n,Ptg.CLASS_ARRAY);
}
}
}
private void setClass(Node n, byte theClass) {
Ptg p = n.getValue();
if (p instanceof AbstractFunctionPtg || !(p instanceof OperationPtg)) {
p.setClass(theClass);
} else {
for (int i =0;i<n.getNumChildren();i++) {
setClass(n.getChild(i),theClass);
}
}
}
/**
* Convience method which takes in a list then passes it to the
* Convenience method which takes in a list then passes it to the
* other toFormulaString signature.
* @param book workbook for 3D and named references
* @param lptgs list of Ptg, can be null or empty
@ -960,7 +793,7 @@ end;
return retval;
}
/**
* Convience method which takes in a list then passes it to the
* Convenience method which takes in a list then passes it to the
* other toFormulaString signature. Works on the current
* workbook for 3D and named references
* @param lptgs list of Ptg, can be null or empty
@ -993,11 +826,11 @@ end;
// TODO - put comment and throw exception in toFormulaString() of these classes
continue;
}
if (! (ptg instanceof OperationPtg)) {
stack.push(ptg.toFormulaString(book));
if (ptg instanceof ParenthesisPtg) {
String contents = (String)stack.pop();
stack.push ("(" + contents + ")");
continue;
}
if (ptg instanceof AttrPtg) {
AttrPtg attrPtg = ((AttrPtg) ptg);
if (attrPtg.isOptimizedIf() || attrPtg.isOptimizedChoose() || attrPtg.isGoto()) {
@ -1008,34 +841,31 @@ end;
continue;
// but if it ever did, care must be taken:
// tAttrSpace comes *before* the operand it applies to, which may be consistent
// with how the formula text appears but is against the RPN ordering assumed here
// with how the formula text appears but is against the RPN ordering assumed here
}
if (attrPtg.isSemiVolatile()) {
// similar to tAttrSpace - RPN is violated
continue;
}
if (!attrPtg.isSum()) {
throw new RuntimeException("Unexpected tAttr: " + attrPtg.toString());
if (attrPtg.isSum()) {
String[] operands = getOperands(stack, attrPtg.getNumberOfOperands());
stack.push(attrPtg.toFormulaString(operands));
continue;
}
throw new RuntimeException("Unexpected tAttr: " + attrPtg.toString());
}
final OperationPtg o = (OperationPtg) ptg;
int nOperands = o.getNumberOfOperands();
final String[] operands = new String[nOperands];
for (int j = nOperands-1; j >= 0; j--) { // reverse iteration because args were pushed in-order
if(stack.isEmpty()) {
String msg = "Too few arguments suppled to operation token ("
+ o.getClass().getName() + "). Expected (" + nOperands
+ ") operands but got (" + (nOperands - j - 1) + ")";
throw new IllegalStateException(msg);
}
operands[j] = (String) stack.pop();
if (! (ptg instanceof OperationPtg)) {
stack.push(ptg.toFormulaString(book));
continue;
}
OperationPtg o = (OperationPtg) ptg;
String[] operands = getOperands(stack, o.getNumberOfOperands());
stack.push(o.toFormulaString(operands));
}
if(stack.isEmpty()) {
// inspection of the code above reveals that every stack.pop() is followed by a
// inspection of the code above reveals that every stack.pop() is followed by a
// stack.push(). So this is either an internal error or impossible.
throw new IllegalStateException("Stack underflow");
}
@ -1047,6 +877,20 @@ end;
}
return result;
}
private static String[] getOperands(Stack stack, int nOperands) {
String[] operands = new String[nOperands];
for (int j = nOperands-1; j >= 0; j--) { // reverse iteration because args were pushed in-order
if(stack.isEmpty()) {
String msg = "Too few arguments supplied to operation. Expected (" + nOperands
+ ") operands but got (" + (nOperands - j - 1) + ")";
throw new IllegalStateException(msg);
}
operands[j] = (String) stack.pop();
}
return operands;
}
/**
* Static method to convert an array of Ptgs in RPN order
* to a human readable string format in infix mode. Works
@ -1057,59 +901,4 @@ end;
public String toFormulaString(Ptg[] ptgs) {
return toFormulaString(book, ptgs);
}
/** Create a tree representation of the RPN token array
*used to run the class(RVA) change algo
*/
private Node createTree() {
Stack stack = new Stack();
int numPtgs = tokens.size();
OperationPtg o;
int numOperands;
Node[] operands;
for (int i=0;i<numPtgs;i++) {
if (tokens.get(i) instanceof OperationPtg) {
o = (OperationPtg) tokens.get(i);
numOperands = o.getNumberOfOperands();
operands = new Node[numOperands];
for (int j=0;j<numOperands;j++) {
operands[numOperands-j-1] = (Node) stack.pop();
}
Node result = new Node(o);
result.setChildren(operands);
stack.push(result);
} else {
stack.push(new Node((Ptg)tokens.get(i)));
}
}
return (Node) stack.pop();
}
/** toString on the parser instance returns the RPN ordered list of tokens
* Useful for testing
*/
public String toString() {
StringBuffer buf = new StringBuffer();
for (int i=0;i<tokens.size();i++) {
buf.append( ( (Ptg)tokens.get(i)).toFormulaString(book));
buf.append(' ');
}
return buf.toString();
}
/** Private helper class, used to create a tree representation of the formula*/
private static final class Node {
private Ptg value=null;
private Node[] children=new Node[0];
private int numChild=0;
public Node(Ptg val) {
value = val;
}
public void setChildren(Node[] child) {children = child;numChild=child.length;}
public int getNumChildren() {return numChild;}
public Node getChild(int number) {return children[number];}
public Ptg getValue() {return value;}
}
}

View File

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

View File

@ -0,0 +1,206 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hssf.model;
import org.apache.poi.hssf.record.formula.AbstractFunctionPtg;
import org.apache.poi.hssf.record.formula.ControlPtg;
import org.apache.poi.hssf.record.formula.ValueOperatorPtg;
import org.apache.poi.hssf.record.formula.Ptg;
/**
* This class performs 'operand class' transformation. Non-base tokens are classified into three
* operand classes:
* <ul>
* <li>reference</li>
* <li>value</li>
* <li>array</li>
* </ul>
* <p/>
*
* The final operand class chosen for each token depends on the formula type and the token's place
* in the formula. If POI gets the operand class wrong, Excel <em>may</em> interpret the formula
* incorrectly. This condition is typically manifested as a formula cell that displays as '#VALUE!',
* but resolves correctly when the user presses F2, enter.<p/>
*
* The logic implemented here was partially inspired by the description in
* "OpenOffice.org's Documentation of the Microsoft Excel File Format". The model presented there
* seems to be inconsistent with observed Excel behaviour (These differences have not been fully
* investigated). The implementation in this class has been heavily modified in order to satisfy
* concrete examples of how Excel performs the same logic (see TestRVA).<p/>
*
* Hopefully, as additional important test cases are identified and added to the test suite,
* patterns might become more obvious in this code and allow for simplification.
*
* @author Josh Micich
*/
final class OperandClassTransformer {
private final int _formulaType;
public OperandClassTransformer(int formulaType) {
_formulaType = formulaType;
}
/**
* Traverses the supplied formula parse tree, calling <tt>Ptg.setClass()</tt> for each non-base
* token to set its operand class.
*/
public void transformFormula(ParseNode rootNode) {
byte rootNodeOperandClass;
switch (_formulaType) {
case FormulaParser.FORMULA_TYPE_CELL:
rootNodeOperandClass = Ptg.CLASS_VALUE;
break;
default:
throw new RuntimeException("Incomplete code - formula type ("
+ _formulaType + ") not supported yet");
}
transformNode(rootNode, rootNodeOperandClass, false);
}
private void transformNode(ParseNode node, byte desiredOperandClass,
boolean callerForceArrayFlag) {
Ptg token = node.getToken();
ParseNode[] children = node.getChildren();
if (token instanceof ValueOperatorPtg || token instanceof ControlPtg) {
// Value Operator Ptgs and Control are base tokens, so token will be unchanged
// but any child nodes are processed according to desiredOperandClass and callerForceArrayFlag
for (int i = 0; i < children.length; i++) {
ParseNode child = children[i];
transformNode(child, desiredOperandClass, callerForceArrayFlag);
}
return;
}
if (token instanceof AbstractFunctionPtg) {
transformFunctionNode((AbstractFunctionPtg) token, children, desiredOperandClass,
callerForceArrayFlag);
return;
}
if (children.length > 0) {
throw new IllegalStateException("Node should not have any children");
}
if (token.isBaseToken()) {
// nothing to do
return;
}
if (callerForceArrayFlag) {
switch (desiredOperandClass) {
case Ptg.CLASS_VALUE:
case Ptg.CLASS_ARRAY:
token.setClass(Ptg.CLASS_ARRAY);
break;
case Ptg.CLASS_REF:
token.setClass(Ptg.CLASS_REF);
break;
default:
throw new IllegalStateException("Unexpected operand class ("
+ desiredOperandClass + ")");
}
} else {
token.setClass(desiredOperandClass);
}
}
private void transformFunctionNode(AbstractFunctionPtg afp, ParseNode[] children,
byte desiredOperandClass, boolean callerForceArrayFlag) {
boolean localForceArrayFlag;
byte defaultReturnOperandClass = afp.getDefaultOperandClass();
if (callerForceArrayFlag) {
switch (defaultReturnOperandClass) {
case Ptg.CLASS_REF:
if (desiredOperandClass == Ptg.CLASS_REF) {
afp.setClass(Ptg.CLASS_REF);
} else {
afp.setClass(Ptg.CLASS_ARRAY);
}
localForceArrayFlag = false;
break;
case Ptg.CLASS_ARRAY:
afp.setClass(Ptg.CLASS_ARRAY);
localForceArrayFlag = false;
break;
case Ptg.CLASS_VALUE:
afp.setClass(Ptg.CLASS_ARRAY);
localForceArrayFlag = true;
break;
default:
throw new IllegalStateException("Unexpected operand class ("
+ defaultReturnOperandClass + ")");
}
} else {
if (defaultReturnOperandClass == desiredOperandClass) {
localForceArrayFlag = false;
// an alternative would have been to for non-base Ptgs to set their operand class
// from their default, but this would require the call in many subclasses because
// the default OC is not known until the end of the constructor
afp.setClass(defaultReturnOperandClass);
} else {
switch (desiredOperandClass) {
case Ptg.CLASS_VALUE:
// always OK to set functions to return 'value'
afp.setClass(Ptg.CLASS_VALUE);
localForceArrayFlag = false;
break;
case Ptg.CLASS_ARRAY:
switch (defaultReturnOperandClass) {
case Ptg.CLASS_REF:
afp.setClass(Ptg.CLASS_REF);
break;
case Ptg.CLASS_VALUE:
afp.setClass(Ptg.CLASS_ARRAY);
break;
default:
throw new IllegalStateException("Unexpected operand class ("
+ defaultReturnOperandClass + ")");
}
localForceArrayFlag = (defaultReturnOperandClass == Ptg.CLASS_VALUE);
break;
case Ptg.CLASS_REF:
switch (defaultReturnOperandClass) {
case Ptg.CLASS_ARRAY:
afp.setClass(Ptg.CLASS_ARRAY);
break;
case Ptg.CLASS_VALUE:
afp.setClass(Ptg.CLASS_VALUE);
break;
default:
throw new IllegalStateException("Unexpected operand class ("
+ defaultReturnOperandClass + ")");
}
localForceArrayFlag = false;
break;
default:
throw new IllegalStateException("Unexpected operand class ("
+ desiredOperandClass + ")");
}
}
}
for (int i = 0; i < children.length; i++) {
ParseNode child = children[i];
byte paramOperandClass = afp.getParameterClass(i);
transformNode(child, paramOperandClass, localForceArrayFlag);
}
}
}

View File

@ -0,0 +1,201 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hssf.model;
import org.apache.poi.hssf.record.formula.AttrPtg;
import org.apache.poi.hssf.record.formula.FuncVarPtg;
import org.apache.poi.hssf.record.formula.Ptg;
import org.apache.poi.hssf.record.formula.function.FunctionMetadataRegistry;
/**
* Represents a syntactic element from a formula by encapsulating the corresponding <tt>Ptg</tt>
* token. Each <tt>ParseNode</tt> may have child <tt>ParseNode</tt>s in the case when the wrapped
* <tt>Ptg</tt> is non-atomic.
*
* @author Josh Micich
*/
final class ParseNode {
public static final ParseNode[] EMPTY_ARRAY = { };
private final Ptg _token;
private final ParseNode[] _children;
private boolean _isIf;
private final int _tokenCount;
public ParseNode(Ptg token, ParseNode[] children) {
_token = token;
_children = children;
_isIf = isIf(token);
int tokenCount = 1;
for (int i = 0; i < children.length; i++) {
tokenCount += children[i].getTokenCount();
}
if (_isIf) {
// there will be 2 or 3 extra tAttr tokens according to whether the false param is present
tokenCount += children.length;
}
_tokenCount = tokenCount;
}
public ParseNode(Ptg token) {
this(token, EMPTY_ARRAY);
}
public ParseNode(Ptg token, ParseNode child0) {
this(token, new ParseNode[] { child0, });
}
public ParseNode(Ptg token, ParseNode child0, ParseNode child1) {
this(token, new ParseNode[] { child0, child1, });
}
private int getTokenCount() {
return _tokenCount;
}
/**
* Collects the array of <tt>Ptg</tt> tokens for the specified tree.
*/
public static Ptg[] toTokenArray(ParseNode rootNode) {
TokenCollector temp = new TokenCollector(rootNode.getTokenCount());
rootNode.collectPtgs(temp);
return temp.getResult();
}
private void collectPtgs(TokenCollector temp) {
if (isIf(getToken())) {
collectIfPtgs(temp);
return;
}
for (int i=0; i< getChildren().length; i++) {
getChildren()[i].collectPtgs(temp);
}
temp.add(getToken());
}
/**
* The IF() function gets marked up with two or three tAttr tokens.
* Similar logic will be required for CHOOSE() when it is supported
*
* See excelfileformat.pdf sec 3.10.5 "tAttr (19H)
*/
private void collectIfPtgs(TokenCollector temp) {
// condition goes first
getChildren()[0].collectPtgs(temp);
// placeholder for tAttrIf
int ifAttrIndex = temp.createPlaceholder();
// true parameter
getChildren()[1].collectPtgs(temp);
// placeholder for first skip attr
int skipAfterTrueParamIndex = temp.createPlaceholder();
int trueParamSize = temp.sumTokenSizes(ifAttrIndex+1, skipAfterTrueParamIndex);
AttrPtg attrIf = new AttrPtg();
attrIf.setOptimizedIf(true);
AttrPtg attrSkipAfterTrue = new AttrPtg();
attrSkipAfterTrue.setGoto(true);
if (getChildren().length > 2) {
// false param present
// false parameter
getChildren()[2].collectPtgs(temp);
int skipAfterFalseParamIndex = temp.createPlaceholder();
AttrPtg attrSkipAfterFalse = new AttrPtg();
attrSkipAfterFalse.setGoto(true);
int falseParamSize = temp.sumTokenSizes(skipAfterTrueParamIndex+1, skipAfterFalseParamIndex);
attrIf.setData((short)(trueParamSize + 4)); // distance to start of false parameter. +4 for skip after true
attrSkipAfterTrue.setData((short)(falseParamSize + 4 + 4 - 1)); // 1 less than distance to end of if FuncVar(size=4). +4 for attr skip before
attrSkipAfterFalse.setData((short)(4 - 1)); // 1 less than distance to end of if FuncVar(size=4).
temp.setPlaceholder(ifAttrIndex, attrIf);
temp.setPlaceholder(skipAfterTrueParamIndex, attrSkipAfterTrue);
temp.setPlaceholder(skipAfterFalseParamIndex, attrSkipAfterFalse);
} else {
// false parameter not present
attrIf.setData((short)(trueParamSize + 4)); // distance to start of FuncVar. +4 for skip after true
attrSkipAfterTrue.setData((short)(4 - 1)); // 1 less than distance to end of if FuncVar(size=4).
temp.setPlaceholder(ifAttrIndex, attrIf);
temp.setPlaceholder(skipAfterTrueParamIndex, attrSkipAfterTrue);
}
temp.add(getToken());
}
private static boolean isIf(Ptg token) {
if (token instanceof FuncVarPtg) {
FuncVarPtg func = (FuncVarPtg) token;
if (FunctionMetadataRegistry.FUNCTION_NAME_IF.equals(func.getName())) {
return true;
}
}
return false;
}
public Ptg getToken() {
return _token;
}
public ParseNode[] getChildren() {
return _children;
}
private static final class TokenCollector {
private final Ptg[] _ptgs;
private int _offset;
public TokenCollector(int tokenCount) {
_ptgs = new Ptg[tokenCount];
_offset = 0;
}
public int sumTokenSizes(int fromIx, int toIx) {
int result = 0;
for (int i=fromIx; i<toIx; i++) {
result += _ptgs[i].getSize();
}
return result;
}
public int createPlaceholder() {
return _offset++;
}
public void add(Ptg token) {
if (token == null) {
throw new IllegalArgumentException("token must not be null");
}
_ptgs[_offset] = token;
_offset++;
}
public void setPlaceholder(int index, Ptg token) {
if (_ptgs[index] != null) {
throw new IllegalStateException("Invalid placeholder index (" + index + ")");
}
_ptgs[index] = token;
}
public Ptg[] getResult() {
return _ptgs;
}
}
}

View File

@ -66,7 +66,7 @@ public final class Sheet implements Model {
protected ArrayList records = null;
int preoffset = 0; // offset of the sheet in a new file
int loc = 0;
protected int dimsloc = 0;
protected int dimsloc = -1; // TODO - is it legal for dims record to be missing?
protected DimensionsRecord dims;
protected DefaultColWidthRecord defaultcolwidth = null;
protected DefaultRowHeightRecord defaultrowheight = null;
@ -96,8 +96,8 @@ public final class Sheet implements Model {
protected List condFormatting = new ArrayList();
/** Add an UncalcedRecord if not true indicating formulas have not been calculated */
protected boolean uncalced = false;
protected boolean _isUncalced = false;
public static final byte PANE_LOWER_RIGHT = (byte)0;
public static final byte PANE_UPPER_RIGHT = (byte)1;
public static final byte PANE_LOWER_LEFT = (byte)2;
@ -162,7 +162,7 @@ public final class Sheet implements Model {
}
}
else if (rec.getSid() == UncalcedRecord.sid) {
retval.uncalced = true;
retval._isUncalced = true;
}
else if (rec.getSid() == DimensionsRecord.sid)
{
@ -295,6 +295,8 @@ public final class Sheet implements Model {
}
else if ( rec.getSid() == IndexRecord.sid )
{
// ignore INDEX record because it is only needed by Excel,
// and POI always re-calculates its contents
rec = null;
}
@ -329,16 +331,8 @@ public final class Sheet implements Model {
}
}
retval.records = records;
// if (retval.rows == null)
// {
// retval.rows = new RowRecordsAggregate();
// }
retval.checkCells();
retval.checkRows();
// if (retval.cells == null)
// {
// retval.cells = new ValueRecordsAggregate();
// }
retval.checkCells();
if (log.check( POILogger.DEBUG ))
log.log(POILogger.DEBUG, "sheet createSheet (existing file) exited");
return retval;
@ -494,7 +488,15 @@ public final class Sheet implements Model {
if (cells == null)
{
cells = new ValueRecordsAggregate();
records.add(getDimsLoc() + 1, cells);
// In the worksheet stream, the row records always occur before the cell (value)
// records. Therefore POI's aggregates (RowRecordsAggregate, ValueRecordsAggregate)
// should follow suit. Some methods in this class tolerate either order, while
// others have been found to fail (see bug 45145).
int rraIndex = getDimsLoc() + 1;
if (records.get(rraIndex).getClass() != RowRecordsAggregate.class) {
throw new IllegalStateException("Cannot create value records before row records exist");
}
records.add(rraIndex+1, cells);
}
}
@ -816,17 +818,17 @@ public final class Sheet implements Model {
// Once the rows have been found in the list of records, start
// writing out the blocked row information. This includes the DBCell references
if (record instanceof RowRecordsAggregate) {
pos += ((RowRecordsAggregate)record).serialize(pos, data, cells); // rec.length;
pos += ((RowRecordsAggregate)record).serialize(pos, data, cells);
} else if (record instanceof ValueRecordsAggregate) {
//Do nothing here. The records were serialized during the RowRecordAggregate block serialization
} else {
pos += record.serialize(pos, data ); // rec.length;
pos += record.serialize(pos, data );
}
// If the BOF record was just serialized then add the IndexRecord
if (record.getSid() == BOFRecord.sid) {
// Add an optional UncalcedRecord
if (uncalced) {
if (_isUncalced) {
UncalcedRecord rec = new UncalcedRecord();
pos += rec.serialize(pos, data);
}
@ -837,67 +839,68 @@ public final class Sheet implements Model {
pos += serializeIndexRecord(k, pos, data);
}
}
//// uncomment to test record sizes ////
// System.out.println( record.getClass().getName() );
// byte[] data2 = new byte[record.getRecordSize()];
// record.serialize(0, data2 ); // rec.length;
// if (LittleEndian.getUShort(data2, 2) != record.getRecordSize() - 4
// && record instanceof RowRecordsAggregate == false
// && record instanceof ValueRecordsAggregate == false
// && record instanceof EscherAggregate == false)
// {
// throw new RuntimeException("Blah!!! Size off by " + ( LittleEndian.getUShort(data2, 2) - record.getRecordSize() - 4) + " records.");
// }
//asd: int len = record.serialize(pos + offset, data );
///// DEBUG BEGIN /////
//asd: if (len != record.getRecordSize())
//asd: throw new IllegalStateException("Record size does not match serialized bytes. Serialized size = " + len + " but getRecordSize() returns " + record.getRecordSize() + ". Record object is " + record.getClass());
///// DEBUG END /////
//asd: pos += len; // rec.length;
}
if (log.check( POILogger.DEBUG ))
if (log.check( POILogger.DEBUG )) {
log.log(POILogger.DEBUG, "Sheet.serialize returning ");
}
return pos-offset;
}
private int serializeIndexRecord(final int BOFRecordIndex, final int offset, byte[] data) {
IndexRecord index = new IndexRecord();
index.setFirstRow(rows.getFirstRowNum());
index.setLastRowAdd1(rows.getLastRowNum()+1);
//Calculate the size of the records from the end of the BOF
//and up to the RowRecordsAggregate...
int sheetRecSize = 0;
for (int j = BOFRecordIndex+1; j < records.size(); j++)
{
Record tmpRec = (( Record ) records.get(j));
if (tmpRec instanceof RowRecordsAggregate)
break;
sheetRecSize+= tmpRec.getRecordSize();
}
//Add the references to the DBCells in the IndexRecord (one for each block)
int blockCount = rows.getRowBlockCount();
//Calculate the size of this IndexRecord
int indexRecSize = IndexRecord.getRecordSizeForBlockCount(blockCount);
/**
* @param indexRecordOffset also happens to be the end of the BOF record
* @return the size of the serialized INDEX record
*/
private int serializeIndexRecord(final int bofRecordIndex, final int indexRecordOffset,
byte[] data) {
IndexRecord index = new IndexRecord();
index.setFirstRow(rows.getFirstRowNum());
index.setLastRowAdd1(rows.getLastRowNum() + 1);
// Calculate the size of the records from the end of the BOF
// and up to the RowRecordsAggregate...
int rowBlockOffset = 0;
int cellBlockOffset = 0;
int dbCellOffset = 0;
for (int block=0;block<blockCount;block++) {
rowBlockOffset += rows.getRowBlockSize(block);
cellBlockOffset += null == cells ? 0 : cells.getRowCellBlockSize(rows.getStartRowNumberForBlock(block),
rows.getEndRowNumberForBlock(block));
//Note: The offsets are relative to the Workbook BOF. Assume that this is
//0 for now.....
index.addDbcell(offset + indexRecSize + sheetRecSize + dbCellOffset + rowBlockOffset + cellBlockOffset);
//Add space required to write the dbcell record(s) (whose references were just added).
dbCellOffset += (8 + (rows.getRowCountForBlock(block) * 2));
}
return index.serialize(offset, data);
// 'initial sheet records' are between INDEX and first ROW record.
int sizeOfInitialSheetRecords = 0;
// start just after BOF record (INDEX is not present in this list)
for (int j = bofRecordIndex + 1; j < records.size(); j++) {
Record tmpRec = ((Record) records.get(j));
if (tmpRec instanceof UncalcedRecord) {
continue;
}
if (tmpRec instanceof RowRecordsAggregate) {
break;
}
sizeOfInitialSheetRecords += tmpRec.getRecordSize();
}
if (_isUncalced) {
sizeOfInitialSheetRecords += UncalcedRecord.getStaticRecordSize();
}
// Add the references to the DBCells in the IndexRecord (one for each block)
// Note: The offsets are relative to the Workbook BOF. Assume that this is
// 0 for now.....
int blockCount = rows.getRowBlockCount();
// Calculate the size of this IndexRecord
int indexRecSize = IndexRecord.getRecordSizeForBlockCount(blockCount);
int currentOffset = indexRecordOffset + indexRecSize + sizeOfInitialSheetRecords;
for (int block = 0; block < blockCount; block++) {
// each row-block has a DBCELL record.
// The offset of each DBCELL record needs to be updated in the INDEX record
// account for row records in this row-block
currentOffset += rows.getRowBlockSize(block);
// account for cell value records after those
currentOffset += null == cells ? 0 : cells.getRowCellBlockSize(rows
.getStartRowNumberForBlock(block), rows.getEndRowNumberForBlock(block));
// currentOffset is now the location of the DBCELL record for this row-block
index.addDbcell(currentOffset);
// Add space required to write the DBCELL record (whose reference was just added).
currentOffset += (8 + (rows.getRowCountForBlock(block) * 2));
}
return index.serialize(indexRecordOffset, data);
}
@ -2017,31 +2020,33 @@ public final class Sheet implements Model {
{
int retval = 0;
for ( int k = 0; k < records.size(); k++ )
{
retval += ( (Record) records.get( k ) ).getRecordSize();
}
//Add space for the IndexRecord
if (rows != null) {
final int blocks = rows.getRowBlockCount();
retval += IndexRecord.getRecordSizeForBlockCount(blocks);
//Add space for the DBCell records
//Once DBCell per block.
//8 bytes per DBCell (non variable section)
//2 bytes per row reference
retval += (8 * blocks);
for (Iterator itr = rows.getIterator(); itr.hasNext();) {
RowRecord row = (RowRecord)itr.next();
if (cells != null && cells.rowHasCells(row.getRowNumber()))
retval += 2;
for ( int k = 0; k < records.size(); k++) {
Record record = (Record) records.get(k);
if (record instanceof UncalcedRecord) {
// skip the UncalcedRecord if present, it's only encoded if the isUncalced flag is set
continue;
}
retval += record.getRecordSize();
}
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
if (uncalced) {
if (_isUncalced) {
retval += UncalcedRecord.getStaticRecordSize();
}
return retval;
}
@ -2518,13 +2523,13 @@ public final class Sheet implements Model {
* @return whether an uncalced record must be inserted or not at generation
*/
public boolean getUncalced() {
return uncalced;
return _isUncalced;
}
/**
* @param uncalced whether an uncalced record must be inserted or not at generation
*/
public void setUncalced(boolean uncalced) {
this.uncalced = uncalced;
this._isUncalced = uncalced;
}
/**

View File

@ -191,12 +191,11 @@ public class Workbook implements Model
case ExternSheetRecord.sid :
throw new RuntimeException("Extern sheet is part of LinkTable");
case NameRecord.sid :
throw new RuntimeException("DEFINEDNAME is part of LinkTable");
case SupBookRecord.sid :
// LinkTable can start with either of these
if (log.check( POILogger.DEBUG ))
log.log(DEBUG, "found SupBook record at " + k);
retval.linkTable = new LinkTable(recs, k, retval.records);
// retval.records.supbookpos = k;
k+=retval.linkTable.getRecordCount() - 1;
continue;
case FormatRecord.sid :
@ -604,6 +603,29 @@ public class Workbook implements Model
boundsheets.remove(sheetnum);
fixTabIdRecord();
}
// Within NameRecords, it's ok to have the formula
// part point at deleted sheets. It's also ok to
// have the ExternSheetNumber point at deleted
// sheets.
// However, the sheet index must be adjusted, or
// excel will break. (Sheet index is either 0 for
// global, or 1 based index to sheet)
int sheetNum1Based = sheetnum + 1;
for(int i=0; i<getNumNames(); i++) {
NameRecord nr = getNameRecord(i);
if(nr.getIndexToSheet() == sheetNum1Based) {
// Excel re-writes these to point to no sheet
nr.setEqualsToIndexToSheet((short)0);
} else if(nr.getIndexToSheet() > sheetNum1Based) {
// Bump down by one, so still points
// at the same sheet
nr.setEqualsToIndexToSheet((short)(
nr.getEqualsToIndexToSheet()-1
));
}
}
}
/**

View File

@ -14,14 +14,10 @@
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hssf.record;
import java.util.Stack;
import org.apache.poi.hssf.model.FormulaParser;
import org.apache.poi.hssf.model.Workbook;
import org.apache.poi.hssf.record.cf.BorderFormatting;
import org.apache.poi.hssf.record.cf.FontFormatting;
import org.apache.poi.hssf.record.cf.PatternFormatting;
@ -30,7 +26,6 @@ import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.util.BitField;
import org.apache.poi.util.BitFieldFactory;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.StringUtil;
/**
* Conditional Formatting Rule Record.
@ -59,9 +54,6 @@ public final class CFRuleRecord extends Record
private byte field_2_comparison_operator;
private short field_3_formula1_len;
private short field_4_formula2_len;
private int field_5_options;
private static final BitField modificationBits = bf(0x003FFFFF); // Bits: font,align,bord,patt,prot
@ -121,8 +113,6 @@ public final class CFRuleRecord extends Record
{
field_1_condition_type=conditionType;
field_2_comparison_operator=comparisonOperation;
field_3_formula1_len = (short)0;
field_4_formula2_len = (short)0;
// Set modification flags to 1: by default options are not modified
field_5_options = modificationBits.setValue(field_5_options, -1);
@ -147,8 +137,8 @@ public final class CFRuleRecord extends Record
this(conditionType, comparisonOperation);
field_1_condition_type = CONDITION_TYPE_CELL_VALUE_IS;
field_2_comparison_operator = comparisonOperation;
setParsedExpression1(formula1);
setParsedExpression2(formula2);
field_17_formula1 = formula1;
field_18_formula2 = formula2;
}
/**
@ -167,63 +157,38 @@ public final class CFRuleRecord extends Record
Ptg[] formula1 = parseFormula(formulaText1, workbook);
Ptg[] formula2 = parseFormula(formulaText2, workbook);
return new CFRuleRecord(CONDITION_TYPE_CELL_VALUE_IS, comparisonOperation, formula1, formula2);
}
/**
* Constructs a Formula record and sets its fields appropriately.
* Note - id must be 0x06 (NOT 0x406 see MSKB #Q184647 for an
* "explanation of this bug in the documentation) or an exception
* will be throw upon validation
*
* @param in the RecordInputstream to read the record from
*/
public CFRuleRecord(RecordInputStream in)
{
public CFRuleRecord(RecordInputStream in) {
super(in);
}
protected void fillFields(RecordInputStream in) {
try {
field_1_condition_type = in.readByte();
field_2_comparison_operator = in.readByte();
field_3_formula1_len = in.readShort();
field_4_formula2_len = in.readShort();
field_5_options = in.readInt();
field_6_not_used = in.readShort();
field_1_condition_type = in.readByte();
field_2_comparison_operator = in.readByte();
int field_3_formula1_len = in.readUShort();
int field_4_formula2_len = in.readUShort();
field_5_options = in.readInt();
field_6_not_used = in.readShort();
if (containsFontFormattingBlock()) {
fontFormatting = new FontFormatting(in);
}
if (containsBorderFormattingBlock()) {
borderFormatting = new BorderFormatting(in);
}
if (containsPatternFormattingBlock()) {
patternFormatting = new PatternFormatting(in);
}
if (field_3_formula1_len > 0) {
Stack ptgs = Ptg.createParsedExpressionTokens(field_3_formula1_len, in);
// Now convert any fields as required
ptgs = SharedFormulaRecord.convertSharedFormulas(ptgs, 0, 0);
field_17_formula1 = toArray(ptgs);
}
if (field_4_formula2_len > 0) {
Stack ptgs = Ptg.createParsedExpressionTokens(field_4_formula2_len, in);
// Now convert any fields as required
ptgs = SharedFormulaRecord.convertSharedFormulas(ptgs, 0, 0);
field_18_formula2 = toArray(ptgs);
}
} catch (java.lang.UnsupportedOperationException uoe) {
throw new RecordFormatException(uoe);
if (containsFontFormattingBlock()) {
fontFormatting = new FontFormatting(in);
}
if (containsBorderFormattingBlock()) {
borderFormatting = new BorderFormatting(in);
}
if (containsPatternFormattingBlock()) {
patternFormatting = new PatternFormatting(in);
}
if (field_3_formula1_len > 0) {
field_17_formula1 = Ptg.readTokens(field_3_formula1_len, in);
}
if (field_4_formula2_len > 0) {
field_18_formula2 = Ptg.readTokens(field_4_formula2_len, in);
}
}
public byte getConditionType()
@ -323,24 +288,6 @@ public final class CFRuleRecord extends Record
}
/**
* get the length (in number of tokens) of the expression 1
* @return expression length
*/
private short getExpression1Length()
{
return field_3_formula1_len;
}
/**
* get the length (in number of tokens) of the expression 2
* @return expression length
*/
private short getExpression2Length()
{
return field_4_formula2_len;
}
/**
* get the option flags
*
@ -489,16 +436,6 @@ public final class CFRuleRecord extends Record
return field_18_formula2;
}
private void setParsedExpression1(Ptg[] ptgs) {
short len = getTotalPtgSize(field_17_formula1 = ptgs);
field_3_formula1_len = len;
}
private void setParsedExpression2(Ptg[] ptgs) {
short len = getTotalPtgSize(field_18_formula2 = ptgs);
field_4_formula2_len = len;
}
/**
* called by constructor, should throw runtime exception in the event of a
* record passed with a differing ID.
@ -519,6 +456,17 @@ public final class CFRuleRecord extends Record
return sid;
}
/**
* @param ptgs may be <code>null</code>
* @return encoded size of the formula
*/
private static int getFormulaSize(Ptg[] ptgs) {
if (ptgs == null) {
return 0;
}
return Ptg.getEncodedSize(ptgs);
}
/**
* called by the class that is responsible for writing this sucker.
* Subclasses should implement this so that their data is passed back in a
@ -528,18 +476,20 @@ public final class CFRuleRecord extends Record
* @param data byte array containing instance data
* @return number of bytes written
*/
public int serialize(int pOffset, byte [] data)
{
int formula1Len=getFormulaSize(field_17_formula1);
int formula2Len=getFormulaSize(field_18_formula2);
int offset = pOffset;
int recordsize = getRecordSize();
LittleEndian.putShort(data, 0 + offset, sid);
LittleEndian.putShort(data, 2 + offset, (short)(recordsize-4));
data[4 + offset] = field_1_condition_type;
data[5 + offset] = field_2_comparison_operator;
LittleEndian.putShort(data, 6 + offset, field_3_formula1_len);
LittleEndian.putShort(data, 8 + offset, field_4_formula2_len);
LittleEndian.putUShort(data, 6 + offset, formula1Len);
LittleEndian.putUShort(data, 8 + offset, formula2Len);
LittleEndian.putInt(data, 10 + offset, field_5_options);
LittleEndian.putShort(data,14 + offset, field_6_not_used);
@ -562,16 +512,12 @@ public final class CFRuleRecord extends Record
offset += patternFormatting.serialize(offset, data);
}
if (getExpression1Length()>0)
{
Ptg.serializePtgStack(convertToTokenStack(field_17_formula1), data, offset);
offset += getExpression1Length();
if (field_17_formula1 != null) {
offset += Ptg.serializePtgs(field_17_formula1, data, offset);
}
if (getExpression2Length()>0)
{
Ptg.serializePtgStack(convertToTokenStack(field_18_formula2), data, offset);
offset += getExpression2Length();
if (field_18_formula2 != null) {
offset += Ptg.serializePtgs(field_18_formula2, data, offset);
}
if(offset - pOffset != recordsize) {
throw new IllegalStateException("write mismatch (" + (offset - pOffset) + "!=" + recordsize + ")");
@ -586,24 +532,12 @@ public final class CFRuleRecord extends Record
(containsFontFormattingBlock()?fontFormatting.getRawRecord().length:0)+
(containsBorderFormattingBlock()?8:0)+
(containsPatternFormattingBlock()?4:0)+
getExpression1Length()+
getExpression2Length()
getFormulaSize(field_17_formula1)+
getFormulaSize(field_18_formula2)
;
return retval;
}
private short getTotalPtgSize(Ptg[] ptgs)
{
if( ptgs == null) {
return 0;
}
short retval = 0;
for (int i = 0; i < ptgs.length; i++)
{
retval += ptgs[i].getSize();
}
return retval;
}
public String toString()
{
@ -629,8 +563,6 @@ public final class CFRuleRecord extends Record
public Object clone() {
CFRuleRecord rec = new CFRuleRecord(field_1_condition_type, field_2_comparison_operator);
rec.field_3_formula1_len = field_3_formula1_len;
rec.field_4_formula2_len = field_4_formula2_len;
rec.field_5_options = field_5_options;
rec.field_6_not_used = field_6_not_used;
if (containsFontFormattingBlock()) {
@ -642,10 +574,10 @@ public final class CFRuleRecord extends Record
if (containsPatternFormattingBlock()) {
rec.patternFormatting = (PatternFormatting) patternFormatting.clone();
}
if (field_3_formula1_len > 0) {
if (field_17_formula1 != null) {
rec.field_17_formula1 = (Ptg[]) field_17_formula1.clone();
}
if (field_4_formula2_len > 0) {
if (field_18_formula2 != null) {
rec.field_18_formula2 = (Ptg[]) field_18_formula2.clone();
}
@ -653,30 +585,17 @@ public final class CFRuleRecord extends Record
}
/**
* TODO - parse conditional format formulas properly i.e. produce tRefN and tAreaN instead of tRef and tArea
* this call will produce the wrong results if the formula contains any cell references
* One approach might be to apply the inverse of SharedFormulaRecord.convertSharedFormulas(Stack, int, int)
* Note - two extra parameters (rowIx & colIx) will be required. They probably come from one of the Region objects.
*
* @return <code>null</code> if <tt>formula</tt> was null.
*/
private static Ptg[] parseFormula(String formula, HSSFWorkbook workbook)
{
private static Ptg[] parseFormula(String formula, HSSFWorkbook workbook) {
if(formula == null) {
return null;
}
return FormulaParser.parse(formula, workbook);
}
// TODO - treat formulas as token arrays instead of Stacks throughout the rest of POI
private static Stack convertToTokenStack(Ptg[] ptgs)
{
Stack parsedExpression = new Stack();
// fill the Ptg Stack with Ptgs of new formula
for (int k = 0; k < ptgs.length; k++)
{
parsedExpression.push(ptgs[ k ]);
}
return parsedExpression;
}
private static Ptg[] toArray(Stack ptgs) {
Ptg[] result = new Ptg[ptgs.size()];
ptgs.toArray(result);
return result;
}
}

View File

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

View File

@ -108,7 +108,10 @@ public class EmbeddedObjectRefSubRecord
in.readByte(); // discard
}
field_6_stream_id = in.readInt();
// Fetch the stream ID
field_6_stream_id = in.readInt();
// Store what's left
remainingBytes = in.readRemainder();
}

View File

@ -557,7 +557,7 @@ public final class FormulaRecord
if (field_8_parsed_expr != null)
size = field_8_parsed_expr.size();
for (int i=0; i< size; i++) {
Ptg ptg = (Ptg)((Ptg)field_8_parsed_expr.get(i)).clone();
Ptg ptg = ((Ptg)field_8_parsed_expr.get(i)).copy();
rec.field_8_parsed_expr.add(i, ptg);
}
rec.value_data = value_data;

View File

@ -14,7 +14,6 @@
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hssf.record;
@ -22,9 +21,8 @@ import java.util.Iterator;
import java.util.List;
import java.util.Stack;
import org.apache.poi.hssf.model.FormulaParser;
import org.apache.poi.hssf.record.formula.Area3DPtg;
import org.apache.poi.hssf.record.formula.DeletedArea3DPtg;
import org.apache.poi.hssf.record.formula.DeletedRef3DPtg;
import org.apache.poi.hssf.record.formula.Ptg;
import org.apache.poi.hssf.record.formula.Ref3DPtg;
import org.apache.poi.hssf.record.formula.UnionPtg;
@ -44,8 +42,7 @@ import org.apache.poi.util.StringUtil;
* @author Glen Stampoultzis (glens at apache.org)
* @version 1.0-pre
*/
public class NameRecord extends Record {
public final class NameRecord extends Record {
/**
*/
public final static short sid = 0x18; //Docs says that it is 0x218
@ -650,50 +647,9 @@ public class NameRecord extends Record {
/** gets the reference , the area only (range)
* @return area reference
*/
public String getAreaReference(HSSFWorkbook book){
if (field_13_name_definition == null || field_13_name_definition.isEmpty()) return "Error";
Ptg ptg = (Ptg) field_13_name_definition.peek();
String result = "";
// If it's a union, descend in and process
if (ptg.getClass() == UnionPtg.class) {
Iterator it =field_13_name_definition.iterator();
while( it.hasNext() ) {
Ptg p = (Ptg)it.next();
String thisRes = getAreaRefString(p, book);
if(thisRes.length() > 0) {
// Add a comma to the end if needed
if(result.length() > 0 && !result.endsWith(",")) {
result += ",";
}
// And add the string it corresponds to
result += thisRes;
}
}
} else {
// Otherwise just get the string
result = getAreaRefString(ptg, book);
}
return result;
}
/**
* Turn the given ptg into a string, or
* return an empty string if nothing is possible
* for it.
*/
private String getAreaRefString(Ptg ptg,HSSFWorkbook book) {
if (ptg.getClass() == Area3DPtg.class){
return ptg.toFormulaString(book);
} else if (ptg.getClass() == Ref3DPtg.class){
return ptg.toFormulaString(book);
} else if (ptg.getClass() == DeletedArea3DPtg.class || ptg.getClass() == DeletedRef3DPtg.class) {
return "#REF!";
}
return "";
}
public String getAreaReference(HSSFWorkbook book){
return FormulaParser.toFormulaString(book, field_13_name_definition);
}
/** sets the reference , the area only (range)
* @param ref area reference
@ -737,7 +693,7 @@ public class NameRecord extends Record {
}
// And then a union if we had more than one area
if(refs.length > 1) {
ptg = new UnionPtg();
ptg = UnionPtg.instance;
field_13_name_definition.push(ptg);
this.setDefinitionTextLength( (short)(getDefinitionLength() + ptg.getSize()) );
}

View File

@ -1,4 +1,3 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
@ -16,27 +15,21 @@
limitations under the License.
==================================================================== */
package org.apache.poi.hssf.record;
import org.apache.poi.util.*;
import java.io.ByteArrayInputStream;
import java.util.List;
import java.util.Iterator;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.apache.poi.util.LittleEndian;
/**
* The obj record is used to hold various graphic objects and controls.
*
* @author Glen Stampoultzis (glens at apache.org)
*/
public class ObjRecord
extends Record
{
public final class ObjRecord extends Record {
public final static short sid = 0x5D;
private List subrecords;
@ -47,6 +40,7 @@ public class ObjRecord
public ObjRecord()
{
subrecords = new ArrayList(2);
// TODO - ensure 2 sub-records (ftCmo 15h, and ftEnd 00h) are always created
}
/**
@ -80,6 +74,7 @@ public class ObjRecord
//following wont work properly
int subSize = 0;
byte[] subRecordData = in.readRemainder();
RecordInputStream subRecStream = new RecordInputStream(new ByteArrayInputStream(subRecordData));
while(subRecStream.hasNextRecord()) {
subRecStream.nextRecord();
@ -89,28 +84,19 @@ public class ObjRecord
}
/**
* Check if the RecordInputStream skipped EndSubRecord,
* if it did then append it explicitly.
* See Bug 41242 for details.
* Add the EndSubRecord explicitly.
*
* TODO - the reason the EndSubRecord is always skipped is because its 'sid' is zero and
* that causes subRecStream.hasNextRecord() to return false.
* There may be more than the size of EndSubRecord left-over, if there is any padding
* after that record. The content of the EndSubRecord and the padding is all zeros.
* So there's not much to look at past the last substantial record.
*
* See Bugs 41242/45133 for details.
*/
if (subRecordData.length - subSize == 4){
if (subRecordData.length - subSize >= 4) {
subrecords.add(new EndSubRecord());
}
/* JMH the size present/not present in the code below
needs to be considered in the RecordInputStream??
int pos = offset;
while (pos - offset <= size-2) // atleast one "short" must be present
{
short subRecordSid = LittleEndian.getShort(data, pos);
short subRecordSize = -1; // set default to "< 0"
if (pos-offset <= size-4) { // see if size info is present, else default to -1
subRecordSize = LittleEndian.getShort(data, pos + 2);
}
Record subRecord = SubRecord.createSubRecord(subRecordSid, subRecordSize, data, pos + 4);
subrecords.add(subRecord);
pos += subRecord.getRecordSize();
}*/
}
public String toString()
@ -140,6 +126,8 @@ public class ObjRecord
Record record = (Record) iterator.next();
pos += record.serialize(pos, data);
}
// assume padding (if present) does not need to be written.
// it is probably zero already, and it probably doesn't matter anyway
return getRecordSize();
}
@ -155,7 +143,9 @@ public class ObjRecord
Record record = (Record) iterator.next();
size += record.getRecordSize();
}
return 4 + size;
int oddBytes = size & 0x03;
int padding = oddBytes == 0 ? 0 : 4 - oddBytes;
return 4 + size + padding;
}
public short getSid()
@ -192,9 +182,4 @@ public class ObjRecord
return rec;
}
} // END OF CLASS
}

View File

@ -201,24 +201,16 @@ public final class SharedFormulaRecord extends Record {
if (ptgs != null)
for (int k = 0; k < ptgs.size(); k++) {
Ptg ptg = (Ptg) ptgs.get(k);
byte originalOperandClass = -1;
if (!ptg.isBaseToken()) {
originalOperandClass = ptg.getPtgClass();
}
if (ptg instanceof RefNPtg) {
RefNPtg refNPtg = (RefNPtg)ptg;
ptg = new ReferencePtg(fixupRelativeRow(formulaRow,refNPtg.getRow(),refNPtg.isRowRelative()),
ptg = new RefPtg(fixupRelativeRow(formulaRow,refNPtg.getRow(),refNPtg.isRowRelative()),
fixupRelativeColumn(formulaColumn,refNPtg.getColumn(),refNPtg.isColRelative()),
refNPtg.isRowRelative(),
refNPtg.isColRelative());
} else if (ptg instanceof RefNVPtg) {
RefNVPtg refNVPtg = (RefNVPtg)ptg;
ptg = new RefVPtg(fixupRelativeRow(formulaRow,refNVPtg.getRow(),refNVPtg.isRowRelative()),
fixupRelativeColumn(formulaColumn,refNVPtg.getColumn(),refNVPtg.isColRelative()),
refNVPtg.isRowRelative(),
refNVPtg.isColRelative());
} else if (ptg instanceof RefNAPtg) {
RefNAPtg refNAPtg = (RefNAPtg)ptg;
ptg = new RefAPtg( fixupRelativeRow(formulaRow,refNAPtg.getRow(),refNAPtg.isRowRelative()),
fixupRelativeColumn(formulaColumn,refNAPtg.getColumn(),refNAPtg.isColRelative()),
refNAPtg.isRowRelative(),
refNAPtg.isColRelative());
} else if (ptg instanceof AreaNPtg) {
AreaNPtg areaNPtg = (AreaNPtg)ptg;
ptg = new AreaPtg(fixupRelativeRow(formulaRow,areaNPtg.getFirstRow(),areaNPtg.isFirstRowRelative()),
@ -229,27 +221,11 @@ public final class SharedFormulaRecord extends Record {
areaNPtg.isLastRowRelative(),
areaNPtg.isFirstColRelative(),
areaNPtg.isLastColRelative());
} else if (ptg instanceof AreaNVPtg) {
AreaNVPtg areaNVPtg = (AreaNVPtg)ptg;
ptg = new AreaVPtg(fixupRelativeRow(formulaRow,areaNVPtg.getFirstRow(),areaNVPtg.isFirstRowRelative()),
fixupRelativeRow(formulaRow,areaNVPtg.getLastRow(),areaNVPtg.isLastRowRelative()),
fixupRelativeColumn(formulaColumn,areaNVPtg.getFirstColumn(),areaNVPtg.isFirstColRelative()),
fixupRelativeColumn(formulaColumn,areaNVPtg.getLastColumn(),areaNVPtg.isLastColRelative()),
areaNVPtg.isFirstRowRelative(),
areaNVPtg.isLastRowRelative(),
areaNVPtg.isFirstColRelative(),
areaNVPtg.isLastColRelative());
} else if (ptg instanceof AreaNAPtg) {
AreaNAPtg areaNAPtg = (AreaNAPtg)ptg;
ptg = new AreaAPtg(fixupRelativeRow(formulaRow,areaNAPtg.getFirstRow(),areaNAPtg.isFirstRowRelative()),
fixupRelativeRow(formulaRow,areaNAPtg.getLastRow(),areaNAPtg.isLastRowRelative()),
fixupRelativeColumn(formulaColumn,areaNAPtg.getFirstColumn(),areaNAPtg.isFirstColRelative()),
fixupRelativeColumn(formulaColumn,areaNAPtg.getLastColumn(),areaNAPtg.isLastColRelative()),
areaNAPtg.isFirstRowRelative(),
areaNAPtg.isLastRowRelative(),
areaNAPtg.isFirstColRelative(),
areaNAPtg.isLastColRelative());
}
}
if (!ptg.isBaseToken()) {
ptg.setClass(originalOperandClass);
}
newPtgStack.add(ptg);
}
return newPtgStack;

View File

@ -37,7 +37,7 @@ import java.util.List;
public final class ValueRecordsAggregate
extends Record
{
public final static short sid = -1000;
public final static short sid = -1001; // 1000 clashes with RowRecordsAggregate
int firstcell = -1;
int lastcell = -1;
CellValueRecordInterface[][] records;

View File

@ -44,6 +44,10 @@ public abstract class AbstractFunctionPtg extends OperationPtg {
protected byte field_1_num_args;
protected short field_2_fnc_index;
public final boolean isBaseToken() {
return false;
}
public String toString() {
StringBuffer sb = new StringBuffer(64);
sb.append(getClass().getName()).append(" [");
@ -52,12 +56,6 @@ public abstract class AbstractFunctionPtg extends OperationPtg {
return sb.toString();
}
public int getType() {
return -1;
}
public short getFunctionIndex() {
return field_2_fnc_index;
}

View File

@ -1,4 +1,3 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
@ -16,69 +15,32 @@
limitations under the License.
==================================================================== */
/*
* AddPtg.java
*
* Created on October 29, 2001, 7:48 PM
*/
package org.apache.poi.hssf.record.formula;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.record.RecordInputStream;
/**
* Addition operator PTG the "+" binomial operator. If you need more
* explanation than that then well...We really can't help you here.
* @author Andrew C. Oliver (acoliver@apache.org)
* @author Jason Height (jheight at chariot dot net dot au)
*/
public class AddPtg
extends OperationPtg
{
public final static int SIZE = 1;
public final class AddPtg extends ValueOperatorPtg {
public final static byte sid = 0x03;
private final static String ADD = "+";
/** Creates new AddPtg */
public static final ValueOperatorPtg instance = new AddPtg();
public AddPtg()
{
}
public AddPtg(RecordInputStream in)
{
// doesn't need anything
private AddPtg() {
// enforce singleton
}
public void writeBytes(byte [] array, int offset)
{
array[ offset + 0 ] = sid;
protected byte getSid() {
return sid;
}
public int getSize()
{
return SIZE;
}
public int getType()
{
return TYPE_BINARY;
}
public int getNumberOfOperands()
{
public int getNumberOfOperands() {
return 2;
}
/** Implementation of method from Ptg */
public String toFormulaString(HSSFWorkbook book)
{
return "+";
}
/** implementation of method from OperationsPtg*/
public String toFormulaString(String[] operands) {
@ -89,11 +51,4 @@ public class AddPtg
buffer.append(operands[ 1 ]);
return buffer.toString();
}
public byte getDefaultOperandClass() {return Ptg.CLASS_VALUE;}
public Object clone() {
return new AddPtg();
}
}

View File

@ -27,7 +27,7 @@ import org.apache.poi.util.LittleEndian;
/**
* Title: Area 3D Ptg - 3D referecnce (Sheet + Area)<P>
* Title: Area 3D Ptg - 3D reference (Sheet + Area)<P>
* Description: Defined a area in Extern Sheet. <P>
* REFERENCE: <P>
* @author Libin Roman (Vista Portal LDT. Developer)
@ -35,9 +35,7 @@ import org.apache.poi.util.LittleEndian;
* @author Jason Height (jheight at chariot dot net dot au)
* @version 1.0-pre
*/
public class Area3DPtg extends Ptg implements AreaI
{
public final class Area3DPtg extends OperandPtg implements AreaI {
public final static byte sid = 0x3b;
private final static int SIZE = 11; // 10 + 1 for Ptg
private short field_1_index_extern_sheet;
@ -84,28 +82,20 @@ public class Area3DPtg extends Ptg implements AreaI
setExternSheetIndex(externalSheetIndex);
}
public String toString()
{
StringBuffer buffer = new StringBuffer();
buffer.append( "AreaPtg\n" );
buffer.append( "Index to Extern Sheet = " + getExternSheetIndex() ).append( "\n" );
buffer.append( "firstRow = " + getFirstRow() ).append( "\n" );
buffer.append( "lastRow = " + getLastRow() ).append( "\n" );
buffer.append( "firstCol = " + getFirstColumn() ).append( "\n" );
buffer.append( "lastCol = " + getLastColumn() ).append( "\n" );
buffer.append( "firstColRel= "
+ isFirstRowRelative() ).append( "\n" );
buffer.append( "lastColRowRel = "
+ isLastRowRelative() ).append( "\n" );
buffer.append( "firstColRel = " + isFirstColRelative() ).append( "\n" );
buffer.append( "lastColRel = " + isLastColRelative() ).append( "\n" );
return buffer.toString();
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append(getClass().getName());
sb.append(" [");
sb.append("sheetIx=").append(getExternSheetIndex());
sb.append(" ! ");
sb.append(AreaReference.formatAsString(this));
sb.append("]");
return sb.toString();
}
public void writeBytes( byte[] array, int offset )
{
array[0 + offset] = (byte) ( sid + ptgClass );
array[0 + offset] = (byte) ( sid + getPtgClass() );
LittleEndian.putShort( array, 1 + offset, getExternSheetIndex() );
LittleEndian.putShort( array, 3 + offset, (short)getFirstRow() );
LittleEndian.putShort( array, 5 + offset, (short)getLastRow() );
@ -279,35 +269,28 @@ public class Area3DPtg extends Ptg implements AreaI
StringBuffer retval = new StringBuffer();
String sheetName = Ref3DPtg.getSheetName(book, field_1_index_extern_sheet);
if(sheetName != null) {
SheetNameFormatter.appendFormat(retval, sheetName);
if(sheetName.length() == 0) {
// What excel does if sheet has been deleted
sheetName = "#REF";
retval.append(sheetName);
} else {
// Normal
SheetNameFormatter.appendFormat(retval, sheetName);
}
retval.append( '!' );
}
// Now the normal area bit
retval.append( AreaPtg.toFormulaString(this, book) );
retval.append(AreaReference.formatAsString(this));
// All done
return retval.toString();
}
public byte getDefaultOperandClass()
{
public byte getDefaultOperandClass() {
return Ptg.CLASS_REF;
}
public Object clone()
{
Area3DPtg ptg = new Area3DPtg();
ptg.field_1_index_extern_sheet = field_1_index_extern_sheet;
ptg.field_2_first_row = field_2_first_row;
ptg.field_3_last_row = field_3_last_row;
ptg.field_4_first_column = field_4_first_column;
ptg.field_5_last_column = field_5_last_column;
ptg.setClass(ptgClass);
return ptg;
}
// TODO - one junit relies on this. remove
public boolean equals( Object o )
{
if ( this == o ) return true;
@ -323,17 +306,4 @@ public class Area3DPtg extends Ptg implements AreaI
return true;
}
public int hashCode()
{
int result;
result = (int) field_1_index_extern_sheet;
result = 29 * result + (int) field_2_first_row;
result = 29 * result + (int) field_3_last_row;
result = 29 * result + (int) field_4_first_column;
result = 29 * result + (int) field_5_last_column;
return result;
}
}

View File

@ -1,68 +0,0 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
/*
* AreaPtg.java
*
* Created on November 17, 2001, 9:30 PM
*/
package org.apache.poi.hssf.record.formula;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.BitField;
import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.hssf.util.AreaReference;
import org.apache.poi.hssf.util.CellReference;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
/**
* Specifies a rectangular area of cells A1:A4 for instance.
* @author Jason Height (jheight at chariot dot net dot au)
*/
public final class AreaAPtg extends AreaPtg {
public final static short sid = 0x65;
protected AreaAPtg() {
//Required for clone methods
}
public AreaAPtg(int firstRow, int lastRow, int firstColumn, int lastColumn, boolean firstRowRelative, boolean lastRowRelative, boolean firstColRelative, boolean lastColRelative) {
super(firstRow, lastRow, firstColumn, lastColumn, firstRowRelative, lastRowRelative, firstColRelative, lastColRelative);
}
public AreaAPtg(RecordInputStream in)
{
super(in);
}
public String getAreaPtgName() {
return "AreaAPtg";
}
public Object clone() {
AreaAPtg ptg = new AreaAPtg();
ptg.setFirstRow(getFirstRow());
ptg.setLastRow(getLastRow());
ptg.setFirstColumnRaw(getFirstColumnRaw());
ptg.setLastColumnRaw(getLastColumnRaw());
ptg.setClass(ptgClass);
return ptg;
}
}

View File

@ -17,73 +17,40 @@
package org.apache.poi.hssf.record.formula;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.BitField;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.util.LittleEndian;
/**
* AreaErr - handles deleted cell area references.
*
* @author Daniel Noll (daniel at nuix dot com dot au)
*/
public class AreaErrPtg extends AreaPtg
{
public final class AreaErrPtg extends OperandPtg {
public final static byte sid = 0x2b;
private AreaErrPtg()
{
//Required for clone methods
super();
}
public AreaErrPtg(RecordInputStream in)
{
super(in);
}
public String toString()
{
StringBuffer buffer = new StringBuffer();
buffer.append("AreaErrPtg\n");
buffer.append("firstRow = " + getFirstRow()).append("\n");
buffer.append("lastRow = " + getLastRow()).append("\n");
buffer.append("firstCol = " + getFirstColumn()).append("\n");
buffer.append("lastCol = " + getLastColumn()).append("\n");
buffer.append("firstColRowRel= "
+ isFirstRowRelative()).append("\n");
buffer.append("lastColRowRel = "
+ isLastRowRelative()).append("\n");
buffer.append("firstColRel = " + isFirstColRelative()).append("\n");
buffer.append("lastColRel = " + isLastColRelative()).append("\n");
return buffer.toString();
public AreaErrPtg(RecordInputStream in) {
// 8 bytes unused:
in.readInt();
in.readInt();
}
public void writeBytes(byte [] array, int offset) {
super.writeBytes(array, offset);
array[offset] = (byte) (sid + ptgClass);
array[offset] = (byte) (sid + getPtgClass());
LittleEndian.putInt(array, offset+1, 0);
LittleEndian.putInt(array, offset+5, 0);
}
public String toFormulaString(HSSFWorkbook book)
{
public String toFormulaString(HSSFWorkbook book) {
return "#REF!";
}
public Object clone()
{
AreaErrPtg ptg = new AreaErrPtg();
ptg.setFirstRow(getFirstRow());
ptg.setFirstColumn(getFirstColumn());
ptg.setLastRow(getLastRow());
ptg.setLastColumn(getLastColumn());
ptg.setFirstColRelative(isFirstColRelative());
ptg.setLastColRelative(isLastColRelative());
ptg.setFirstRowRelative(isFirstRowRelative());
ptg.setLastRowRelative(isLastRowRelative());
ptg.setClass(ptgClass);
return ptg;
}
public byte getDefaultOperandClass() {
return Ptg.CLASS_REF;
}
public int getSize() {
return 9;
}
}

View File

@ -1,4 +1,3 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
@ -16,49 +15,22 @@
limitations under the License.
==================================================================== */
/*
* AreaPtg.java
*
* Created on November 17, 2001, 9:30 PM
*/
package org.apache.poi.hssf.record.formula;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.BitField;
import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.hssf.util.AreaReference;
import org.apache.poi.hssf.util.CellReference;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
/**
* Specifies a rectangular area of cells A1:A4 for instance.
* @author Jason Height (jheight at chariot dot net dot au)
*/
public final class AreaNPtg extends AreaPtgBase {
public final static short sid = 0x2D;
public final class AreaNPtg extends AreaPtg
{
public final static short sid = 0x2D;
public AreaNPtg(RecordInputStream in) {
super(in);
}
protected AreaNPtg() {
//Required for clone methods
}
public AreaNPtg(RecordInputStream in)
{
super(in);
}
public String getAreaPtgName() {
return "AreaNPtg";
}
public String toFormulaString(HSSFWorkbook book)
{
throw notImplemented();
}
public Object clone() {
throw notImplemented();
}
protected byte getSid() {
return sid;
}
}

320
src/java/org/apache/poi/hssf/record/formula/AreaPtg.java Normal file → Executable file
View File

@ -17,323 +17,25 @@
package org.apache.poi.hssf.record.formula;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.BitField;
import org.apache.poi.util.BitFieldFactory;
import org.apache.poi.hssf.util.AreaReference;
import org.apache.poi.hssf.util.CellReference;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.record.RecordInputStream;
/**
* Specifies a rectangular area of cells A1:A4 for instance.
* @author andy
* @author Jason Height (jheight at chariot dot net dot au)
*/
public class AreaPtg extends Ptg implements AreaI {
/**
* TODO - (May-2008) fix subclasses of AreaPtg 'AreaN~' which are used in shared formulas.
* see similar comment in ReferencePtg
*/
protected final RuntimeException notImplemented() {
return new RuntimeException("Coding Error: This method should never be called. This ptg should be converted");
}
public final class AreaPtg extends AreaPtgBase {
public final static short sid = 0x25;
private final static int SIZE = 9;
/** zero based, unsigned 16 bit */
private int field_1_first_row;
/** zero based, unsigned 16 bit */
private int field_2_last_row;
/** zero based, unsigned 8 bit */
private int field_3_first_column;
/** zero based, unsigned 8 bit */
private int field_4_last_column;
private final static BitField rowRelative = BitFieldFactory.getInstance(0x8000);
private final static BitField colRelative = BitFieldFactory.getInstance(0x4000);
private final static BitField columnMask = BitFieldFactory.getInstance(0x3FFF);
protected AreaPtg() {
//Required for clone methods
public AreaPtg(int firstRow, int lastRow, int firstColumn, int lastColumn, boolean firstRowRelative, boolean lastRowRelative, boolean firstColRelative, boolean lastColRelative) {
super(firstRow, lastRow, firstColumn, lastColumn, firstRowRelative, lastRowRelative, firstColRelative, lastColRelative);
}
public AreaPtg(RecordInputStream in) {
super(in);
}
public AreaPtg(String arearef) {
AreaReference ar = new AreaReference(arearef);
CellReference firstCell = ar.getFirstCell();
CellReference lastCell = ar.getLastCell();
setFirstRow(firstCell.getRow());
setFirstColumn(firstCell.getCol());
setLastRow(lastCell.getRow());
setLastColumn(lastCell.getCol());
setFirstColRelative(!firstCell.isColAbsolute());
setLastColRelative(!lastCell.isColAbsolute());
setFirstRowRelative(!firstCell.isRowAbsolute());
setLastRowRelative(!lastCell.isRowAbsolute());
}
public AreaPtg(int firstRow, int lastRow, int firstColumn, int lastColumn,
boolean firstRowRelative, boolean lastRowRelative, boolean firstColRelative, boolean lastColRelative) {
checkColumnBounds(firstColumn);
checkColumnBounds(lastColumn);
checkRowBounds(firstRow);
checkRowBounds(lastRow);
setFirstRow(firstRow);
setLastRow(lastRow);
setFirstColumn(firstColumn);
setLastColumn(lastColumn);
setFirstRowRelative(firstRowRelative);
setLastRowRelative(lastRowRelative);
setFirstColRelative(firstColRelative);
setLastColRelative(lastColRelative);
}
private static void checkColumnBounds(int colIx) {
if((colIx & 0x0FF) != colIx) {
throw new IllegalArgumentException("colIx (" + colIx + ") is out of range");
}
}
private static void checkRowBounds(int rowIx) {
if((rowIx & 0x0FFFF) != rowIx) {
throw new IllegalArgumentException("rowIx (" + rowIx + ") is out of range");
}
}
public AreaPtg(RecordInputStream in)
{
field_1_first_row = in.readUShort();
field_2_last_row = in.readUShort();
field_3_first_column = in.readUShort();
field_4_last_column = in.readUShort();
//System.out.println(toString());
}
public String getAreaPtgName() {
return "AreaPtg";
}
public String toString()
{
StringBuffer buffer = new StringBuffer();
buffer.append(getAreaPtgName());
buffer.append("\n");
buffer.append("firstRow = " + getFirstRow()).append("\n");
buffer.append("lastRow = " + getLastRow()).append("\n");
buffer.append("firstCol = " + getFirstColumn()).append("\n");
buffer.append("lastCol = " + getLastColumn()).append("\n");
buffer.append("firstColRowRel= "
+ isFirstRowRelative()).append("\n");
buffer.append("lastColRowRel = "
+ isLastRowRelative()).append("\n");
buffer.append("firstColRel = " + isFirstColRelative()).append("\n");
buffer.append("lastColRel = " + isLastColRelative()).append("\n");
return buffer.toString();
}
public void writeBytes(byte [] array, int offset) {
array[offset] = (byte) (sid + ptgClass);
LittleEndian.putShort(array,offset+1,(short)field_1_first_row);
LittleEndian.putShort(array,offset+3,(short)field_2_last_row);
LittleEndian.putShort(array,offset+5,(short)field_3_first_column);
LittleEndian.putShort(array,offset+7,(short)field_4_last_column);
}
public int getSize()
{
return SIZE;
}
/**
* @return the first row in the area
*/
public int getFirstRow()
{
return field_1_first_row;
}
/**
* sets the first row
* @param rowIx number (0-based)
*/
public void setFirstRow(int rowIx) {
checkRowBounds(rowIx);
field_1_first_row = rowIx;
}
/**
* @return last row in the range (x2 in x1,y1-x2,y2)
*/
public int getLastRow()
{
return field_2_last_row;
}
/**
* @param rowIx last row number in the area
*/
public void setLastRow(int rowIx) {
checkRowBounds(rowIx);
field_2_last_row = rowIx;
}
/**
* @return the first column number in the area.
*/
public int getFirstColumn()
{
return columnMask.getValue(field_3_first_column);
}
/**
* @return the first column number + the options bit settings unstripped
*/
public short getFirstColumnRaw()
{
return (short) field_3_first_column; // TODO
}
/**
* @return whether or not the first row is a relative reference or not.
*/
public boolean isFirstRowRelative()
{
return rowRelative.isSet(field_3_first_column);
}
/**
* sets the first row to relative or not
* @param rel is relative or not.
*/
public void setFirstRowRelative(boolean rel) {
field_3_first_column=rowRelative.setBoolean(field_3_first_column,rel);
}
/**
* @return isrelative first column to relative or not
*/
public boolean isFirstColRelative()
{
return colRelative.isSet(field_3_first_column);
}
/**
* set whether the first column is relative
*/
public void setFirstColRelative(boolean rel) {
field_3_first_column=colRelative.setBoolean(field_3_first_column,rel);
}
/**
* set the first column in the area
*/
public void setFirstColumn(int colIx) {
checkColumnBounds(colIx);
field_3_first_column=columnMask.setValue(field_3_first_column, colIx);
}
/**
* set the first column irespective of the bitmasks
*/
public void setFirstColumnRaw(int column)
{
field_3_first_column = column;
}
/**
* @return lastcolumn in the area
*/
public int getLastColumn()
{
return columnMask.getValue(field_4_last_column);
}
/**
* @return last column and bitmask (the raw field)
*/
public short getLastColumnRaw()
{
return (short) field_4_last_column;
}
/**
* @return last row relative or not
*/
public boolean isLastRowRelative()
{
return rowRelative.isSet(field_4_last_column);
}
/**
* set whether the last row is relative or not
* @param rel <code>true</code> if the last row relative, else
* <code>false</code>
*/
public void setLastRowRelative(boolean rel) {
field_4_last_column=rowRelative.setBoolean(field_4_last_column,rel);
}
/**
* @return lastcol relative or not
*/
public boolean isLastColRelative()
{
return colRelative.isSet(field_4_last_column);
}
/**
* set whether the last column should be relative or not
*/
public void setLastColRelative(boolean rel) {
field_4_last_column=colRelative.setBoolean(field_4_last_column,rel);
}
/**
* set the last column in the area
*/
public void setLastColumn(int colIx) {
checkColumnBounds(colIx);
field_4_last_column=columnMask.setValue(field_4_last_column, colIx);
}
/**
* set the last column irrespective of the bitmasks
*/
public void setLastColumnRaw(short column)
{
field_4_last_column = column;
}
public String toFormulaString(HSSFWorkbook book)
{
return toFormulaString(this, book);
}
protected static String toFormulaString(AreaI area, HSSFWorkbook 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() {
return Ptg.CLASS_REF;
}
public Object clone() {
AreaPtg ptg = new AreaPtg();
ptg.field_1_first_row = field_1_first_row;
ptg.field_2_last_row = field_2_last_row;
ptg.field_3_first_column = field_3_first_column;
ptg.field_4_last_column = field_4_last_column;
ptg.setClass(ptgClass);
return ptg;
}
super(arearef);
}
protected byte getSid() {
return sid;
}
}

View File

@ -0,0 +1,286 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hssf.record.formula;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.BitField;
import org.apache.poi.util.BitFieldFactory;
import org.apache.poi.hssf.util.AreaReference;
import org.apache.poi.hssf.util.CellReference;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.record.RecordInputStream;
/**
* Specifies a rectangular area of cells A1:A4 for instance.
* @author andy
* @author Jason Height (jheight at chariot dot net dot au)
*/
public abstract class AreaPtgBase extends OperandPtg implements AreaI {
/**
* TODO - (May-2008) fix subclasses of AreaPtg 'AreaN~' which are used in shared formulas.
* see similar comment in ReferencePtg
*/
protected final RuntimeException notImplemented() {
return new RuntimeException("Coding Error: This method should never be called. This ptg should be converted");
}
public final static short sid = 0x25;
private final static int SIZE = 9;
/** zero based, unsigned 16 bit */
private int field_1_first_row;
/** zero based, unsigned 16 bit */
private int field_2_last_row;
/** zero based, unsigned 8 bit */
private int field_3_first_column;
/** zero based, unsigned 8 bit */
private int field_4_last_column;
private final static BitField rowRelative = BitFieldFactory.getInstance(0x8000);
private final static BitField colRelative = BitFieldFactory.getInstance(0x4000);
private final static BitField columnMask = BitFieldFactory.getInstance(0x3FFF);
protected AreaPtgBase(String arearef) {
AreaReference ar = new AreaReference(arearef);
CellReference firstCell = ar.getFirstCell();
CellReference lastCell = ar.getLastCell();
setFirstRow(firstCell.getRow());
setFirstColumn(firstCell.getCol());
setLastRow(lastCell.getRow());
setLastColumn(lastCell.getCol());
setFirstColRelative(!firstCell.isColAbsolute());
setLastColRelative(!lastCell.isColAbsolute());
setFirstRowRelative(!firstCell.isRowAbsolute());
setLastRowRelative(!lastCell.isRowAbsolute());
}
protected AreaPtgBase(int firstRow, int lastRow, int firstColumn, int lastColumn,
boolean firstRowRelative, boolean lastRowRelative, boolean firstColRelative, boolean lastColRelative) {
checkColumnBounds(firstColumn);
checkColumnBounds(lastColumn);
checkRowBounds(firstRow);
checkRowBounds(lastRow);
setFirstRow(firstRow);
setLastRow(lastRow);
setFirstColumn(firstColumn);
setLastColumn(lastColumn);
setFirstRowRelative(firstRowRelative);
setLastRowRelative(lastRowRelative);
setFirstColRelative(firstColRelative);
setLastColRelative(lastColRelative);
}
private static void checkColumnBounds(int colIx) {
if((colIx & 0x0FF) != colIx) {
throw new IllegalArgumentException("colIx (" + colIx + ") is out of range");
}
}
private static void checkRowBounds(int rowIx) {
if((rowIx & 0x0FFFF) != rowIx) {
throw new IllegalArgumentException("rowIx (" + rowIx + ") is out of range");
}
}
protected AreaPtgBase(RecordInputStream in)
{
field_1_first_row = in.readUShort();
field_2_last_row = in.readUShort();
field_3_first_column = in.readUShort();
field_4_last_column = in.readUShort();
}
public final String toString() {
StringBuffer sb = new StringBuffer();
sb.append(getClass().getName());
sb.append(" [");
sb.append(AreaReference.formatAsString(this));
sb.append("]");
return sb.toString();
}
protected abstract byte getSid();
public final void writeBytes(byte [] array, int offset) {
array[offset] = (byte) (getSid() + getPtgClass());
LittleEndian.putShort(array,offset+1,(short)field_1_first_row);
LittleEndian.putShort(array,offset+3,(short)field_2_last_row);
LittleEndian.putShort(array,offset+5,(short)field_3_first_column);
LittleEndian.putShort(array,offset+7,(short)field_4_last_column);
}
public final int getSize() {
return SIZE;
}
/**
* @return the first row in the area
*/
public final int getFirstRow() {
return field_1_first_row;
}
/**
* sets the first row
* @param rowIx number (0-based)
*/
public final void setFirstRow(int rowIx) {
checkRowBounds(rowIx);
field_1_first_row = rowIx;
}
/**
* @return last row in the range (x2 in x1,y1-x2,y2)
*/
public final int getLastRow() {
return field_2_last_row;
}
/**
* @param rowIx last row number in the area
*/
public final void setLastRow(int rowIx) {
checkRowBounds(rowIx);
field_2_last_row = rowIx;
}
/**
* @return the first column number in the area.
*/
public final int getFirstColumn() {
return columnMask.getValue(field_3_first_column);
}
/**
* @return the first column number + the options bit settings unstripped
*/
public final short getFirstColumnRaw() {
return (short) field_3_first_column; // TODO
}
/**
* @return whether or not the first row is a relative reference or not.
*/
public final boolean isFirstRowRelative() {
return rowRelative.isSet(field_3_first_column);
}
/**
* sets the first row to relative or not
* @param rel is relative or not.
*/
public final void setFirstRowRelative(boolean rel) {
field_3_first_column=rowRelative.setBoolean(field_3_first_column,rel);
}
/**
* @return isrelative first column to relative or not
*/
public final boolean isFirstColRelative() {
return colRelative.isSet(field_3_first_column);
}
/**
* set whether the first column is relative
*/
public final void setFirstColRelative(boolean rel) {
field_3_first_column=colRelative.setBoolean(field_3_first_column,rel);
}
/**
* set the first column in the area
*/
public final void setFirstColumn(int colIx) {
checkColumnBounds(colIx);
field_3_first_column=columnMask.setValue(field_3_first_column, colIx);
}
/**
* set the first column irrespective of the bitmasks
*/
public final void setFirstColumnRaw(int column) {
field_3_first_column = column;
}
/**
* @return lastcolumn in the area
*/
public final int getLastColumn() {
return columnMask.getValue(field_4_last_column);
}
/**
* @return last column and bitmask (the raw field)
*/
public final short getLastColumnRaw() {
return (short) field_4_last_column;
}
/**
* @return last row relative or not
*/
public final boolean isLastRowRelative() {
return rowRelative.isSet(field_4_last_column);
}
/**
* set whether the last row is relative or not
* @param rel <code>true</code> if the last row relative, else
* <code>false</code>
*/
public final void setLastRowRelative(boolean rel) {
field_4_last_column=rowRelative.setBoolean(field_4_last_column,rel);
}
/**
* @return lastcol relative or not
*/
public final boolean isLastColRelative() {
return colRelative.isSet(field_4_last_column);
}
/**
* set whether the last column should be relative or not
*/
public final void setLastColRelative(boolean rel) {
field_4_last_column=colRelative.setBoolean(field_4_last_column,rel);
}
/**
* set the last column in the area
*/
public final void setLastColumn(int colIx) {
checkColumnBounds(colIx);
field_4_last_column=columnMask.setValue(field_4_last_column, colIx);
}
/**
* set the last column irrespective of the bitmasks
*/
public final void setLastColumnRaw(short column) {
field_4_last_column = column;
}
public String toFormulaString(HSSFWorkbook book) {
return AreaReference.formatAsString(this);
}
public byte getDefaultOperandClass() {
return Ptg.CLASS_REF;
}
}

View File

@ -1,71 +0,0 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
/*
* AreaPtg.java
*
* Created on November 17, 2001, 9:30 PM
*/
package org.apache.poi.hssf.record.formula;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.BitField;
import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.hssf.util.AreaReference;
import org.apache.poi.hssf.util.CellReference;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
/**
* Specifies a rectangular area of cells A1:A4 for instance.
* @author Jason Height (jheight at chariot dot net dot au)
*/
public final class AreaVPtg
extends AreaPtg
{
public final static short sid = 0x45;
protected AreaVPtg() {
//Required for clone methods
}
public AreaVPtg(int firstRow, int lastRow, int firstColumn, int lastColumn, boolean firstRowRelative, boolean lastRowRelative, boolean firstColRelative, boolean lastColRelative) {
super(firstRow, lastRow, firstColumn, lastColumn, firstRowRelative, lastRowRelative, firstColRelative, lastColRelative);
}
public AreaVPtg(RecordInputStream in)
{
super(in);
}
public String getAreaPtgName() {
return "AreaVPtg";
}
public Object clone() {
AreaVPtg ptg = new AreaVPtg();
ptg.setFirstRow(getFirstRow());
ptg.setLastRow(getLastRow());
ptg.setFirstColumnRaw(getFirstColumnRaw());
ptg.setLastColumnRaw(getLastColumnRaw());
ptg.setClass(ptgClass);
return ptg;
}
}

View File

@ -35,29 +35,32 @@ import org.apache.poi.util.LittleEndian;
*
* @author Jason Height (jheight at chariot dot net dot au)
*/
public class ArrayPtg extends Ptg {
public final class ArrayPtg extends Ptg {
public static final byte sid = 0x20;
private static final int RESERVED_FIELD_LEN = 7;
// TODO - fix up field visibility and subclasses
protected byte[] field_1_reserved;
private byte[] field_1_reserved;
// data from these fields comes after the Ptg data of all tokens in current formula
protected short token_1_columns;
protected short token_2_rows;
protected Object[] token_3_arrayValues;
private short token_1_columns;
private short token_2_rows;
private Object[] token_3_arrayValues;
protected ArrayPtg() {
//Required for clone methods
}
public ArrayPtg(RecordInputStream in)
{
public ArrayPtg(RecordInputStream in) {
field_1_reserved = new byte[RESERVED_FIELD_LEN];
// TODO - add readFully method to RecordInputStream
for(int i=0; i< RESERVED_FIELD_LEN; i++) {
field_1_reserved[i] = in.readByte();
}
}
public Object[] getTokenArrayValues() {
return (Object[]) token_3_arrayValues.clone();
}
public boolean isBaseToken() {
return false;
}
/**
* Read in the actual token (array) values. This occurs
@ -95,6 +98,10 @@ public class ArrayPtg extends Ptg {
return buffer.toString();
}
/**
* Note - (2D) array elements are stored column by column
* @return the index into the internal 1D array for the specified column and row
*/
/* package */ int getValueIndex(int colIx, int rowIx) {
if(colIx < 0 || colIx >= token_1_columns) {
throw new IllegalArgumentException("Specified colIx (" + colIx
@ -104,12 +111,12 @@ public class ArrayPtg extends Ptg {
throw new IllegalArgumentException("Specified rowIx (" + rowIx
+ ") is outside the allowed range (0.." + (token_2_rows-1) + ")");
}
return rowIx * token_1_columns + colIx;
return rowIx + token_2_rows * colIx;
}
public void writeBytes(byte[] data, int offset) {
LittleEndian.putByte(data, offset + 0, sid + ptgClass);
LittleEndian.putByte(data, offset + 0, sid + getPtgClass());
System.arraycopy(field_1_reserved, 0, data, offset+1, RESERVED_FIELD_LEN);
}
@ -182,13 +189,9 @@ public class ArrayPtg extends Ptg {
}
public Object clone() {
ArrayPtg ptg = new ArrayPtg();
ArrayPtg ptg = (ArrayPtg) super.clone();
ptg.field_1_reserved = (byte[]) field_1_reserved.clone();
ptg.token_1_columns = token_1_columns;
ptg.token_2_rows = token_2_rows;
ptg.token_3_arrayValues = (Object[]) token_3_arrayValues.clone();
ptg.setClass(ptgClass);
return ptg;
}
}

View File

@ -1,48 +0,0 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hssf.record.formula;
import org.apache.poi.hssf.record.RecordInputStream;
/**
* ArrayPtgA - handles arrays
*
* @author Jason Height (jheight at chariot dot net dot au)
*/
public final class ArrayPtgA extends ArrayPtg {
public final static byte sid = 0x60;
private ArrayPtgA() {
//Required for clone methods
}
public ArrayPtgA(RecordInputStream in) {
super(in);
}
public Object clone() {
ArrayPtgA ptg = new ArrayPtgA();
ptg.field_1_reserved = (byte[]) field_1_reserved.clone();
ptg.token_1_columns = token_1_columns;
ptg.token_2_rows = token_2_rows;
ptg.token_3_arrayValues = (Object[]) token_3_arrayValues.clone();
ptg.setClass(ptgClass);
return ptg;
}
}

View File

@ -1,54 +0,0 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hssf.record.formula;
import org.apache.poi.hssf.record.RecordInputStream;
/**
* ArrayPtg - handles arrays
*
* The ArrayPtg is a little weird, the size of the Ptg when parsing initially only
* includes the Ptg sid and the reserved bytes. The next Ptg in the expression then follows.
* It is only after the "size" of all the Ptgs is met, that the ArrayPtg data is actually
* held after this. So Ptg.createParsedExpression keeps track of the number of
* ArrayPtg elements and need to parse the data upto the FORMULA record size.
*
* @author Jason Height (jheight at chariot dot net dot au)
*/
public final class ArrayPtgV extends ArrayPtg {
public final static byte sid = 0x40;
private ArrayPtgV() {
//Required for clone methods
}
public ArrayPtgV(RecordInputStream in) {
super(in);
}
public Object clone() {
ArrayPtgV ptg = new ArrayPtgV();
ptg.field_1_reserved = (byte[]) field_1_reserved.clone();
ptg.token_1_columns = token_1_columns;
ptg.token_2_rows = token_2_rows;
ptg.token_3_arrayValues = (Object[]) token_3_arrayValues.clone();
ptg.setClass(ptgClass);
return ptg;
}
}

View File

@ -15,7 +15,6 @@
limitations under the License.
==================================================================== */
package org.apache.poi.hssf.record.formula;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
@ -32,8 +31,7 @@ import org.apache.poi.util.BitFieldFactory;
* @author andy
* @author Jason Height (jheight at chariot dot net dot au)
*/
public final class AttrPtg extends OperationPtg {
public final class AttrPtg extends ControlPtg {
public final static byte sid = 0x19;
private final static int SIZE = 4;
private byte field_1_options;
@ -289,12 +287,6 @@ public final class AttrPtg extends OperationPtg {
}
return "UNKNOWN ATTRIBUTE";
}
public byte getDefaultOperandClass() {
return Ptg.CLASS_VALUE;
}
public Object clone() {
int[] jt;

View File

@ -27,17 +27,10 @@ import org.apache.poi.hssf.record.RecordInputStream;
* @author Andrew C. Oliver (acoliver at apache dot org)
* @author Jason Height (jheight at chariot dot net dot au)
*/
public class BoolPtg
extends Ptg
{
public final class BoolPtg extends ScalarConstantPtg {
public final static int SIZE = 2;
public final static byte sid = 0x1d;
private boolean field_1_value;
private BoolPtg() {
//Required for clone methods
}
private final boolean field_1_value;
public BoolPtg(RecordInputStream in)
{
@ -49,11 +42,6 @@ public class BoolPtg
field_1_value = (formulaToken.equals("TRUE"));
}
public void setValue(boolean value)
{
field_1_value = value;
}
public boolean getValue()
{
return field_1_value;
@ -74,12 +62,4 @@ public class BoolPtg
{
return field_1_value ? "TRUE" : "FALSE";
}
public byte getDefaultOperandClass() {return Ptg.CLASS_VALUE;}
public Object clone() {
BoolPtg ptg = new BoolPtg();
ptg.field_1_value = field_1_value;
return ptg;
}
}

View File

@ -15,60 +15,31 @@
limitations under the License.
==================================================================== */
package org.apache.poi.hssf.record.formula;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.record.RecordInputStream;
/**
*
* @author andy
* @author Jason Height (jheight at chariot dot net dot au)
*/
public class ConcatPtg
extends OperationPtg
{
public final static int SIZE = 1;
public final class ConcatPtg extends ValueOperatorPtg {
public final static byte sid = 0x08;
private final static String CONCAT = "&";
public ConcatPtg(RecordInputStream in)
{
// No contents
public static final ValueOperatorPtg instance = new ConcatPtg();
private ConcatPtg() {
// enforce singleton
}
public ConcatPtg() {
protected byte getSid() {
return sid;
}
public void writeBytes(byte [] array, int offset)
{
array[ offset + 0 ] = sid;
}
public int getSize()
{
return SIZE;
}
public int getType()
{
return TYPE_BINARY;
}
public int getNumberOfOperands()
{
public int getNumberOfOperands() {
return 2;
}
public String toFormulaString(HSSFWorkbook book)
{
return CONCAT;
}
public String toFormulaString(String[] operands) {
StringBuffer buffer = new StringBuffer();
@ -78,9 +49,4 @@ public class ConcatPtg
buffer.append(operands[ 1 ]);
return buffer.toString();
}
public Object clone() {
return new ConcatPtg();
}
}

View File

@ -15,11 +15,24 @@
limitations under the License.
==================================================================== */
package org.apache.poi.hssf.record.formula;
public abstract class ControlPtg
extends Ptg
{
/**
* Common superclass for
* tExp
* tTbl
* tParen
* tNlr
* tAttr
* tSheet
* tEndSheet
*/
public abstract class ControlPtg extends Ptg {
public boolean isBaseToken() {
return true;
}
public final byte getDefaultOperandClass() {
throw new IllegalStateException("Control tokens are not classified");
}
}

View File

@ -18,6 +18,9 @@
package org.apache.poi.hssf.record.formula;
import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.hssf.usermodel.HSSFErrorConstants;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.util.LittleEndian;
/**
* Title: Deleted Area 3D Ptg - 3D referecnce (Sheet + Area)<P>
@ -26,19 +29,30 @@ import org.apache.poi.hssf.record.RecordInputStream;
* @author Patrick Luby
* @version 1.0-pre
*/
public class DeletedArea3DPtg extends Area3DPtg
{
public final class DeletedArea3DPtg extends OperandPtg {
public final static byte sid = 0x3d;
private final int field_1_index_extern_sheet;
private final int unused1;
private final int unused2;
/** Creates new DeletedArea3DPtg */
public DeletedArea3DPtg( String arearef, short externIdx )
{
super(arearef, externIdx);
}
public DeletedArea3DPtg( RecordInputStream in)
{
super(in);
}
public DeletedArea3DPtg( RecordInputStream in) {
field_1_index_extern_sheet = in.readUShort();
unused1 = in.readInt();
unused2 = in.readInt();
}
public String toFormulaString(HSSFWorkbook book) {
return HSSFErrorConstants.getText(HSSFErrorConstants.ERROR_REF);
}
public byte getDefaultOperandClass() {
return Ptg.CLASS_REF;
}
public int getSize() {
return 11;
}
public void writeBytes(byte[] data, int offset) {
LittleEndian.putByte(data, 0 + offset, sid + getPtgClass());
LittleEndian.putUShort(data, 1 + offset, field_1_index_extern_sheet);
LittleEndian.putInt(data, 3 + offset, unused1);
LittleEndian.putInt(data, 7 + offset, unused2);
}
}

View File

@ -15,11 +15,13 @@
limitations under the License.
==================================================================== */
package org.apache.poi.hssf.record.formula;
import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.hssf.usermodel.HSSFErrorConstants;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.util.LittleEndian;
/**
* Title: Deleted Reference 3D Ptg <P>
@ -28,16 +30,29 @@ import org.apache.poi.hssf.record.RecordInputStream;
* @author Patrick Luby
* @version 1.0-pre
*/
public final class DeletedRef3DPtg extends OperandPtg {
public final static byte sid = 0x3c;
private final int field_1_index_extern_sheet;
private final int unused1;
public class DeletedRef3DPtg extends Ref3DPtg {
public final static byte sid = 0x3c;
/** Creates new DeletedRef3DPtg */
public DeletedRef3DPtg(RecordInputStream in) {
field_1_index_extern_sheet = in.readUShort();
unused1 = in.readInt();
}
/** Creates new DeletedRef3DPtg */
public DeletedRef3DPtg(RecordInputStream in) {
super(in);
}
public DeletedRef3DPtg(String cellref, short externIdx ) {
super(cellref, externIdx);
}
public String toFormulaString(HSSFWorkbook book) {
return HSSFErrorConstants.getText(HSSFErrorConstants.ERROR_REF);
}
public byte getDefaultOperandClass() {
return Ptg.CLASS_REF;
}
public int getSize() {
return 7;
}
public void writeBytes(byte[] data, int offset) {
LittleEndian.putByte(data, 0 + offset, sid + getPtgClass());
LittleEndian.putUShort(data, 1 + offset, field_1_index_extern_sheet);
LittleEndian.putInt(data, 3 + offset, unused1);
}
}

View File

@ -15,72 +15,36 @@
limitations under the License.
==================================================================== */
package org.apache.poi.hssf.record.formula;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.record.RecordInputStream;
/**
* This PTG implements the standard binomial divide "/"
* @author Andrew C. Oliver acoliver at apache dot org
* @author Jason Height (jheight at chariot dot net dot au)
*/
public class DividePtg
extends OperationPtg
{
public final static int SIZE = 1;
public final class DividePtg extends ValueOperatorPtg {
public final static byte sid = 0x06;
/** Creates new AddPtg */
public static final ValueOperatorPtg instance = new DividePtg();
public DividePtg()
{
private DividePtg() {
// enforce singleton
}
protected byte getSid() {
return sid;
}
public DividePtg(RecordInputStream in)
{
// doesn't need anything
}
public void writeBytes(byte [] array, int offset)
{
array[ offset + 0 ] = sid;
}
public int getSize()
{
return SIZE;
}
public int getType()
{
return TYPE_BINARY;
}
public int getNumberOfOperands()
{
public int getNumberOfOperands() {
return 2;
}
public String toFormulaString(HSSFWorkbook book)
{
return "/";
}
public String toFormulaString(String[] operands) {
StringBuffer buffer = new StringBuffer();
buffer.append(operands[ 0 ]);
buffer.append(toFormulaString((HSSFWorkbook)null));
buffer.append("/");
buffer.append(operands[ 1 ]);
return buffer.toString();
}
public Object clone() {
DividePtg ptg = new DividePtg();
return ptg;
}
}

View File

@ -1,4 +1,3 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
@ -18,70 +17,34 @@
package org.apache.poi.hssf.record.formula;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.record.RecordInputStream;
/**
*
* @author andy
*/
public class EqualPtg
extends OperationPtg
{
public final static int SIZE = 1;
public final class EqualPtg extends ValueOperatorPtg {
public final static byte sid = 0x0b;
/** Creates new AddPtg */
public static final ValueOperatorPtg instance = new EqualPtg();
public EqualPtg()
{
private EqualPtg() {
// enforce singleton
}
protected byte getSid() {
return sid;
}
public EqualPtg(RecordInputStream in)
{
// doesn't need anything
}
public void writeBytes(byte [] array, int offset)
{
array[ offset + 0 ] = sid;
}
public int getSize()
{
return SIZE;
}
public int getType()
{
return TYPE_BINARY;
}
public int getNumberOfOperands()
{
public int getNumberOfOperands() {
return 2;
}
public String toFormulaString(HSSFWorkbook book)
{
return "=";
}
public String toFormulaString(String[] operands) {
StringBuffer buffer = new StringBuffer();
buffer.append(operands[ 0 ]);
buffer.append(toFormulaString((HSSFWorkbook)null));
buffer.append("=");
buffer.append(operands[ 1 ]);
return buffer.toString();
}
public Object clone() {
return new EqualPtg();
}
}

View File

@ -1,4 +1,3 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
@ -16,7 +15,6 @@
limitations under the License.
==================================================================== */
package org.apache.poi.hssf.record.formula;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
@ -26,7 +24,7 @@ import org.apache.poi.hssf.usermodel.HSSFErrorConstants;
/**
* @author Daniel Noll (daniel at nuix dot com dot au)
*/
public final class ErrPtg extends Ptg {
public final class ErrPtg extends ScalarConstantPtg {
// convenient access to namespace
private static final HSSFErrorConstants EC = null;
@ -49,7 +47,7 @@ public final class ErrPtg extends Ptg {
public static final short sid = 0x1c;
private static final int SIZE = 2;
private int field_1_error_code;
private final int field_1_error_code;
/** Creates new ErrPtg */
@ -66,7 +64,7 @@ public final class ErrPtg extends Ptg {
public void writeBytes(byte [] array, int offset)
{
array[offset] = (byte) (sid + ptgClass);
array[offset] = (byte) (sid + getPtgClass());
array[offset + 1] = (byte)field_1_error_code;
}
@ -78,14 +76,6 @@ public final class ErrPtg extends Ptg {
return SIZE;
}
public byte getDefaultOperandClass() {
return Ptg.CLASS_VALUE;
}
public Object clone() {
return new ErrPtg(field_1_error_code);
}
public int getErrorCode() {
return field_1_error_code;
}

View File

@ -1,4 +1,3 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
@ -30,29 +29,18 @@ import org.apache.poi.util.LittleEndian;
* @author Jason Height (jheight at chariot dot net dot au)
* @author dmui (save existing implementation)
*/
public class ExpPtg
extends Ptg
{
public final class ExpPtg extends ControlPtg {
private final static int SIZE = 5;
public final static short sid = 0x1;
private short field_1_first_row;
private short field_2_first_col;
/** Creates new ExpPtg */
public ExpPtg()
{
}
/** Creates new ExpPtg */
private final short field_1_first_row;
private final short field_2_first_col;
public ExpPtg(RecordInputStream in)
{
field_1_first_row = in.readShort();
field_2_first_col = in.readShort();
}
public void writeBytes(byte [] array, int offset)
{
array[offset+0]= (byte) (sid);
@ -85,14 +73,4 @@ public class ExpPtg
buffer.append("col = ").append(getColumn()).append("\n");
return buffer.toString();
}
public byte getDefaultOperandClass() {return Ptg.CLASS_VALUE;}
public Object clone() {
ExpPtg result = new ExpPtg();
result.field_1_first_row = field_1_first_row;
result.field_2_first_col = field_2_first_col;
return result;
}
}

View File

@ -44,6 +44,8 @@ public final class FuncPtg extends AbstractFunctionPtg {
throw new RuntimeException("Invalid built-in function index (" + field_2_fnc_index + ")");
}
numParams = fm.getMinParams();
returnClass = fm.getReturnClassCode();
paramClass = fm.getParameterClassCodes();
}
public FuncPtg(int functionIndex) {
field_2_fnc_index = (short) functionIndex;
@ -54,7 +56,7 @@ public final class FuncPtg extends AbstractFunctionPtg {
}
public void writeBytes(byte[] array, int offset) {
array[offset+0]= (byte) (sid + ptgClass);
array[offset+0]= (byte) (sid + getPtgClass());
LittleEndian.putShort(array,offset+1,field_2_fnc_index);
}
@ -62,12 +64,6 @@ public final class FuncPtg extends AbstractFunctionPtg {
return numParams;
}
public Object clone() {
FuncPtg ptg = new FuncPtg(field_2_fnc_index);
ptg.setClass(ptgClass);
return ptg;
}
public int getSize() {
return SIZE;
}

View File

@ -30,16 +30,21 @@ public final class FuncVarPtg extends AbstractFunctionPtg{
public final static byte sid = 0x22;
private final static int SIZE = 4;
private FuncVarPtg() {
//Required for clone methods
}
/**Creates new function pointer from a byte array
/**Creates new function pointer from a byte array
* usually called while reading an excel file.
*/
public FuncVarPtg(RecordInputStream in) {
field_1_num_args = in.readByte();
field_2_fnc_index = in.readShort();
FunctionMetadata fm = FunctionMetadataRegistry.getFunctionByIndex(field_2_fnc_index);
if(fm == null) {
// Happens only as a result of a call to FormulaParser.parse(), with a non-built-in function name
returnClass = Ptg.CLASS_VALUE;
paramClass = new byte[] {Ptg.CLASS_VALUE};
} else {
returnClass = fm.getReturnClassCode();
paramClass = fm.getParameterClassCodes();
}
}
/**
@ -60,7 +65,7 @@ public final class FuncVarPtg extends AbstractFunctionPtg{
}
public void writeBytes(byte[] array, int offset) {
array[offset+0]=(byte) (sid + ptgClass);
array[offset+0]=(byte) (sid + getPtgClass());
array[offset+1]=field_1_num_args;
LittleEndian.putShort(array,offset+2,field_2_fnc_index);
}
@ -69,14 +74,6 @@ public final class FuncVarPtg extends AbstractFunctionPtg{
return field_1_num_args;
}
public Object clone() {
FuncVarPtg ptg = new FuncVarPtg();
ptg.field_1_num_args = field_1_num_args;
ptg.field_2_fnc_index = field_2_fnc_index;
ptg.setClass(ptgClass);
return ptg;
}
public int getSize() {
return SIZE;
}

View File

@ -1,4 +1,3 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
@ -16,75 +15,40 @@
limitations under the License.
==================================================================== */
package org.apache.poi.hssf.record.formula;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.record.RecordInputStream;
/**
* PTG class to implement greater or equal to
*
* @author fred at stsci dot edu
*/
public class GreaterEqualPtg
extends OperationPtg
{
public final class GreaterEqualPtg extends ValueOperatorPtg {
public final static int SIZE = 1;
public final static byte sid = 0x0c;
/** Creates new GreaterEqualPtg */
public static final ValueOperatorPtg instance = new GreaterEqualPtg();
public GreaterEqualPtg()
{
private GreaterEqualPtg() {
// enforce singleton
}
protected byte getSid() {
return sid;
}
public GreaterEqualPtg(RecordInputStream in)
{
// doesn't need anything
}
public void writeBytes(byte [] array, int offset)
{
array[ offset + 0 ] = sid;
}
public int getSize()
{
return SIZE;
}
public int getType()
{
return TYPE_BINARY;
}
public int getNumberOfOperands()
{
public int getNumberOfOperands() {
return 2;
}
public String toFormulaString(HSSFWorkbook book)
{
return ">=";
}
public String toFormulaString(String[] operands) {
StringBuffer buffer = new StringBuffer();
buffer.append(operands[ 0 ]);
buffer.append(toFormulaString((HSSFWorkbook)null));
buffer.append(">=");
buffer.append(operands[ 1 ]);
return buffer.toString();
}
public Object clone() {
return new GreaterEqualPtg();
}
}

View File

@ -15,93 +15,35 @@
limitations under the License.
==================================================================== */
/*
* GreaterThanPtg.java
*
* Created on January 23, 2003, 9:47 AM
*/
package org.apache.poi.hssf.record.formula;
import java.util.List;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.record.RecordInputStream;
/**
* Greater than operator PTG ">"
* @author Cameron Riley (criley at ekmail.com)
*/
public class GreaterThanPtg
extends OperationPtg
{
public final static int SIZE = 1;
public final class GreaterThanPtg extends ValueOperatorPtg {
public final static byte sid = 0x0D;
private final static String GREATERTHAN = ">";
/**
* Constructor. Creates new GreaterThanPtg
*/
public GreaterThanPtg()
{
//deliberately empty
}
public static final ValueOperatorPtg instance = new GreaterThanPtg();
/**
* Constructor. Create a new GreaterThanPtg.
* @param in the RecordInputstream to read the record from
*/
public GreaterThanPtg(RecordInputStream in)
{
//deliberately empty
private GreaterThanPtg() {
// enforce singleton
}
/**
* Write the sid to an array
* @param array the array of bytes to write the sid to
* @param offset the offset to add the sid to
*/
public void writeBytes(byte [] array, int offset)
{
array[ offset + 0 ] = sid;
}
/**
* Get the size of the sid
* @return int the size of the sid in terms of byte additions to an array
*/
public int getSize()
{
return SIZE;
}
/**
* Get the type of PTG for Greater Than
* @return int the identifier for the type
*/
public int getType()
{
return TYPE_BINARY;
protected byte getSid() {
return sid;
}
/**
* Get the number of operands for the Less than operator
* @return int the number of operands
*/
public int getNumberOfOperands()
{
public int getNumberOfOperands() {
return 2;
}
/**
* Implementation of method from Ptg
* @param book the Sheet References
*/
public String toFormulaString(HSSFWorkbook book)
{
return this.GREATERTHAN;
}
/**
* Implementation of method from OperationsPtg
* @param operands a String array of operands
@ -112,26 +54,8 @@ public class GreaterThanPtg
StringBuffer buffer = new StringBuffer();
buffer.append(operands[ 0 ]);
buffer.append(this.GREATERTHAN);
buffer.append(GREATERTHAN);
buffer.append(operands[ 1 ]);
return buffer.toString();
}
/**
* Get the default operands class value
* @return byte the Ptg Class Value as a byte from the Ptg Parent object
*/
public byte getDefaultOperandClass()
{
return Ptg.CLASS_VALUE;
}
/**
* Implementation of clone method from Object
* @return Object a clone of this class as an Object
*/
public Object clone()
{
return new GreaterThanPtg();
}
}

View File

@ -27,7 +27,7 @@ import org.apache.poi.hssf.record.RecordInputStream;
* @author Andrew C. Oliver (acoliver at apache dot org)
* @author Jason Height (jheight at chariot dot net dot au)
*/
public final class IntPtg extends Ptg {
public final class IntPtg extends ScalarConstantPtg {
// 16 bit unsigned integer
private static final int MIN_VALUE = 0x0000;
private static final int MAX_VALUE = 0xFFFF;
@ -43,13 +43,12 @@ public final class IntPtg extends Ptg {
public final static int SIZE = 3;
public final static byte sid = 0x1e;
private int field_1_value;
private final int field_1_value;
public IntPtg(RecordInputStream in) {
this(in.readUShort());
}
public IntPtg(int value) {
if(!isInRange(value)) {
throw new IllegalArgumentException("value is out of range: " + value);
@ -61,7 +60,6 @@ public final class IntPtg extends Ptg {
return field_1_value;
}
public void writeBytes(byte [] array, int offset)
{
array[ offset + 0 ] = sid;
@ -75,13 +73,7 @@ public final class IntPtg extends Ptg {
public String toFormulaString(HSSFWorkbook book) {
return String.valueOf(getValue());
}
public byte getDefaultOperandClass() {
return Ptg.CLASS_VALUE;
}
public Object clone() {
return new IntPtg(field_1_value);
}
public String toString() {
StringBuffer sb = new StringBuffer(64);
sb.append(getClass().getName()).append(" [");

View File

@ -18,26 +18,23 @@
package org.apache.poi.hssf.record.formula;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.record.RecordInputStream;
/**
* @author Daniel Noll (daniel at nuix dot com dot au)
*/
public class IntersectionPtg extends OperationPtg
{
public final class IntersectionPtg extends OperationPtg {
public final static byte sid = 0x0f;
public static final OperationPtg instance = new IntersectionPtg();
public IntersectionPtg()
{
private IntersectionPtg() {
// enforce singleton
}
public IntersectionPtg(RecordInputStream in)
{
// doesn't need anything
public final boolean isBaseToken() {
return true;
}
public int getSize()
{
return 1;
@ -48,16 +45,6 @@ public class IntersectionPtg extends OperationPtg
array[ offset + 0 ] = sid;
}
public Object clone()
{
return new IntersectionPtg();
}
public int getType()
{
return TYPE_BINARY;
}
/** Implementation of method from Ptg */
public String toFormulaString(HSSFWorkbook book)
{

View File

@ -16,12 +16,9 @@
limitations under the License.
==================================================================== */
package org.apache.poi.hssf.record.formula;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.record.RecordInputStream;
/**
@ -29,61 +26,28 @@ import org.apache.poi.hssf.record.RecordInputStream;
*
* @author fred at stsci dot edu
*/
public class LessEqualPtg
extends OperationPtg
{
public final static int SIZE = 1;
public final class LessEqualPtg extends ValueOperatorPtg {
public final static byte sid = 0x0a;
/**
* Creates new LessEqualPtg
*/
public LessEqualPtg()
{
public static final ValueOperatorPtg instance = new LessEqualPtg();
private LessEqualPtg() {
// enforce singleton
}
protected byte getSid() {
return sid;
}
public LessEqualPtg( RecordInputStream in )
{
// doesn't need anything
}
public void writeBytes( byte[] array, int offset )
{
array[offset + 0] = sid;
}
public int getSize()
{
return SIZE;
}
public int getType()
{
return TYPE_BINARY;
}
public int getNumberOfOperands()
{
public int getNumberOfOperands() {
return 2;
}
public String toFormulaString( HSSFWorkbook book )
{
return "<=";
}
public String toFormulaString( String[] operands )
{
public String toFormulaString(String[] operands) {
StringBuffer buffer = new StringBuffer();
buffer.append( operands[0] );
buffer.append( toFormulaString( (HSSFWorkbook) null ) );
buffer.append("<=");
buffer.append( operands[1] );
return buffer.toString();
}
public Object clone()
{
return new LessEqualPtg();
}
}

View File

@ -15,103 +15,40 @@
limitations under the License.
==================================================================== */
/*
* LessThanPtg.java
*
* Created on January 23, 2003, 9:47 AM
*/
package org.apache.poi.hssf.record.formula;
//JDK
import java.util.List;
//POI
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.record.RecordInputStream;
/**
* Less than operator PTG "<". The SID is taken from the
* Openoffice.orgs Documentation of the Excel File Format,
* Table 3.5.7
* @author Cameron Riley (criley at ekmail.com)
*/
public class LessThanPtg
extends OperationPtg
{
/** the size of the Ptg */
public final static int SIZE = 1;
public final class LessThanPtg extends ValueOperatorPtg {
/** the sid for the less than operator as hex */
public final static byte sid = 0x09;
/** identifier for LESS THAN char */
private final static String LESSTHAN = "<";
/**
* Constructor. Creates new LessThanPtg
*/
public LessThanPtg()
{
//deliberately empty
}
public static final ValueOperatorPtg instance = new LessThanPtg();
/**
* Constructor. Create a new LessThanPtg.
* @param in the RecordInputstream to read the record from
*/
public LessThanPtg(RecordInputStream in)
{
//deliberately empty
private LessThanPtg() {
// enforce singleton
}
/**
* Write the sid to an array
* @param array the array of bytes to write the sid to
* @param offset the offset to add the sid to
*/
public void writeBytes(byte[] array, int offset)
{
array[ offset + 0 ] = sid;
}
/**
* Get the size of the sid
* @return int the size of the sid in terms of byte additions to an array
*/
public int getSize()
{
return SIZE;
}
/**
* Get the type of PTG for Less Than
* @return int the identifier for the type
*/
public int getType()
{
return TYPE_BINARY;
protected byte getSid() {
return sid;
}
/**
* Get the number of operands for the Less than operator
* @return int the number of operands
*/
public int getNumberOfOperands()
{
public int getNumberOfOperands() {
return 2;
}
/**
* Implementation of method from Ptg
* @param book the Sheet References
*/
public String toFormulaString(HSSFWorkbook book)
{
return this.LESSTHAN;
}
/**
/**
* Implementation of method from OperationsPtg
* @param operands a String array of operands
* @return String the Formula as a String
@ -120,27 +57,8 @@ public class LessThanPtg
{
StringBuffer buffer = new StringBuffer();
buffer.append(operands[ 0 ]);
buffer.append(this.LESSTHAN);
buffer.append(LESSTHAN);
buffer.append(operands[ 1 ]);
return buffer.toString();
}
/**
* Get the default operands class value
* @return byte the Ptg Class Value as a byte from the Ptg Parent object
*/
public byte getDefaultOperandClass()
{
return Ptg.CLASS_VALUE;
}
/**
* Implementation of clone method from Object
* @return Object a clone of this class as an Object
*/
public Object clone()
{
return new LessThanPtg();
}
}

View File

@ -1,4 +1,3 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
@ -16,12 +15,6 @@
limitations under the License.
==================================================================== */
/*
* MemAreaPtg.java
*
* Created on November 21, 2001, 8:46 AM
*/
package org.apache.poi.hssf.record.formula;
import org.apache.poi.util.LittleEndian;
@ -31,9 +24,7 @@ import org.apache.poi.hssf.record.RecordInputStream;
/**
* @author Daniel Noll (daniel at nuix dot com dot au)
*/
public class MemAreaPtg
extends Ptg
{
public class MemAreaPtg extends OperandPtg {
public final static short sid = 0x26;
private final static int SIZE = 7;
private int field_1_reserved;
@ -73,7 +64,7 @@ public class MemAreaPtg
public void writeBytes(byte [] array, int offset)
{
array[offset] = (byte) (sid + ptgClass);
array[offset] = (byte) (sid + getPtgClass());
LittleEndian.putInt(array, offset + 1, field_1_reserved);
LittleEndian.putShort(array, offset + 5, field_2_subex_len);
}
@ -88,12 +79,7 @@ public class MemAreaPtg
return ""; // TODO: Not sure how to format this. -- DN
}
public byte getDefaultOperandClass() {return Ptg.CLASS_VALUE;}
public Object clone() {
MemAreaPtg ptg = new MemAreaPtg();
ptg.field_1_reserved = field_1_reserved;
ptg.field_2_subex_len = field_2_subex_len;
return ptg;
public byte getDefaultOperandClass() {
return Ptg.CLASS_VALUE;
}
}

View File

@ -1,4 +1,3 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
@ -16,17 +15,10 @@
limitations under the License.
==================================================================== */
/*
* MemErrPtg.java
*
* Created on November 21, 2001, 8:46 AM
*/
package org.apache.poi.hssf.record.formula;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
/**
*
@ -35,9 +27,7 @@ import org.apache.poi.hssf.record.RecordInputStream;
* @author Daniel Noll (daniel at nuix dot com dot au)
*/
public class MemErrPtg
extends MemAreaPtg
{
public final class MemErrPtg extends MemAreaPtg {
public final static short sid = 0x27;
/** Creates new MemErrPtg */
@ -46,26 +36,17 @@ public class MemErrPtg
{
}
public MemErrPtg(RecordInputStream in)
{
public MemErrPtg(RecordInputStream in) {
super(in);
}
public void writeBytes(byte [] array, int offset)
{
public void writeBytes(byte [] array, int offset) {
super.writeBytes(array, offset);
array[offset] = (byte) (sid + ptgClass);
array[offset] = (byte) (sid + getPtgClass());
}
public String toFormulaString(HSSFWorkbook book)
{
return "ERR#";
}
public Object clone() {
MemErrPtg ptg = new MemErrPtg();
ptg.setReserved(getReserved());
ptg.setSubexpressionLength(getSubexpressionLength());
return ptg;
}
}

View File

@ -15,12 +15,6 @@
limitations under the License.
==================================================================== */
/*
* Ptg.java
*
* Created on October 28, 2001, 6:30 PM
*/
package org.apache.poi.hssf.record.formula;
import org.apache.poi.util.LittleEndian;
@ -30,26 +24,23 @@ import org.apache.poi.hssf.record.RecordInputStream;
/**
* @author Glen Stampoultzis (glens at apache.org)
*/
public class MemFuncPtg extends ControlPtg
{
public final class MemFuncPtg extends OperandPtg {
public final static byte sid = 0x29;
private short field_1_len_ref_subexpression = 0;
public MemFuncPtg()
{
//Required for clone methods
}
private final int field_1_len_ref_subexpression;
/**Creates new function pointer from a byte array
* usually called while reading an excel file.
*/
public MemFuncPtg( RecordInputStream in )
{
field_1_len_ref_subexpression = in.readShort();
public MemFuncPtg(RecordInputStream in) {
this(in.readUShort());
}
public int getSize()
public MemFuncPtg(int subExprLen) {
field_1_len_ref_subexpression = subExprLen;
}
public int getSize()
{
return 3;
}
@ -57,7 +48,7 @@ public class MemFuncPtg extends ControlPtg
public void writeBytes( byte[] array, int offset )
{
array[offset + 0] = sid ;
LittleEndian.putShort( array, offset + 1, (short)field_1_len_ref_subexpression );
LittleEndian.putUShort( array, offset + 1, field_1_len_ref_subexpression );
}
public String toFormulaString(HSSFWorkbook book)
@ -67,7 +58,7 @@ public class MemFuncPtg extends ControlPtg
public byte getDefaultOperandClass()
{
return 0;
return Ptg.CLASS_REF;
}
public int getNumberOfOperands()
@ -75,21 +66,8 @@ public class MemFuncPtg extends ControlPtg
return field_1_len_ref_subexpression;
}
public Object clone()
{
MemFuncPtg ptg = new MemFuncPtg();
ptg.field_1_len_ref_subexpression = this.field_1_len_ref_subexpression;
return ptg;
}
public int getLenRefSubexpression()
{
return field_1_len_ref_subexpression;
}
public void setLenRefSubexpression(int len)
{
field_1_len_ref_subexpression = (short)len;
}
}

View File

@ -18,7 +18,6 @@
package org.apache.poi.hssf.record.formula;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.record.RecordInputStream;
/**
* Missing Function Arguments
@ -26,23 +25,15 @@ import org.apache.poi.hssf.record.RecordInputStream;
* Avik Sengupta &lt;avik at apache.org&gt;
* @author Jason Height (jheight at chariot dot net dot au)
*/
public class MissingArgPtg
extends Ptg
{
public final class MissingArgPtg extends ScalarConstantPtg {
private final static int SIZE = 1;
public final static byte sid = 0x16;
public MissingArgPtg()
public static final Ptg instance = new MissingArgPtg();
private MissingArgPtg()
{
}
public MissingArgPtg(RecordInputStream in)
{
// doesn't need anything
}
public void writeBytes(byte [] array, int offset)
{
@ -53,17 +44,9 @@ public class MissingArgPtg
{
return SIZE;
}
public String toFormulaString(HSSFWorkbook book)
{
return " ";
}
public byte getDefaultOperandClass() {return Ptg.CLASS_VALUE;}
public Object clone() {
return new MissingArgPtg();
}
}

View File

@ -14,85 +14,37 @@
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hssf.record.formula;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.record.RecordInputStream;
package org.apache.poi.hssf.record.formula;
/**
* Implements the standard mathmatical multiplication - *
* @author Andrew C. Oliver (acoliver at apache dot org)
* @author Jason Height (jheight at chariot dot net dot au)
*/
public class MultiplyPtg
extends OperationPtg
{
public final static int SIZE = 1;
public final class MultiplyPtg extends ValueOperatorPtg {
public final static byte sid = 0x05;
/** Creates new AddPtg */
public static final ValueOperatorPtg instance = new MultiplyPtg();
public MultiplyPtg()
{
}
public MultiplyPtg(RecordInputStream in)
{
// doesn't need anything
private MultiplyPtg() {
// enforce singleton
}
public void writeBytes(byte [] array, int offset)
{
array[ offset + 0 ] = sid;
protected byte getSid() {
return sid;
}
public int getSize()
{
return SIZE;
}
public int getType()
{
return TYPE_BINARY;
}
public int getNumberOfOperands()
{
public int getNumberOfOperands() {
return 2;
}
public int getStringLength() {
return 1;
}
public String toFormulaString(HSSFWorkbook book)
{
return "*";
}
public String toFormulaString(Ptg [] operands)
{
StringBuffer buffer = new StringBuffer();
buffer.append(operands[ 0 ].toFormulaString((HSSFWorkbook)null));
buffer.append("*");
buffer.append(operands[ 1 ].toFormulaString((HSSFWorkbook)null));
return buffer.toString();
}
public String toFormulaString(String[] operands) {
StringBuffer buffer = new StringBuffer();
buffer.append(operands[ 0 ]);
buffer.append(toFormulaString((HSSFWorkbook)null));
buffer.append("*");
buffer.append(operands[ 1 ]);
return buffer.toString();
}
public Object clone() {
return new MultiplyPtg();
}
}

View File

@ -17,32 +17,22 @@
package org.apache.poi.hssf.record.formula;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.hssf.usermodel.HSSFName;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.record.NameRecord;
import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.util.LittleEndian;
/**
*
* @author andy
* @author Jason Height (jheight at chariot dot net dot au)
*/
public class NamePtg
extends Ptg
{
public final class NamePtg extends OperandPtg {
public final static short sid = 0x23;
private final static int SIZE = 5;
/** one-based index to defined name record */
private short field_1_label_index;
private short field_2_zero; // reserved must be 0
boolean xtra=false;
private NamePtg() {
//Required for clone methods
}
/**
* Creates new NamePtg and sets its name index to that of the corresponding defined name record
@ -72,12 +62,9 @@ public class NamePtg
/** Creates new NamePtg */
public NamePtg(RecordInputStream in)
{
//field_1_ixti = LittleEndian.getShort(data, offset);
public NamePtg(RecordInputStream in) {
field_1_label_index = in.readShort();
field_2_zero = in.readShort();
//if (data[offset+6]==0) xtra=true;
}
/**
@ -87,15 +74,13 @@ public class NamePtg
return field_1_label_index-1; // convert to zero based
}
public void writeBytes(byte [] array, int offset)
{
array[offset+0]= (byte) (sid + ptgClass);
public void writeBytes(byte [] array, int offset) {
array[offset+0]= (byte) (sid + getPtgClass());
LittleEndian.putShort(array,offset+1,field_1_label_index);
LittleEndian.putShort(array,offset+3, field_2_zero);
}
public int getSize()
{
public int getSize() {
return SIZE;
}
@ -104,12 +89,7 @@ public class NamePtg
return book.getNameName(field_1_label_index - 1);
}
public byte getDefaultOperandClass() {return Ptg.CLASS_REF;}
public Object clone() {
NamePtg ptg = new NamePtg();
ptg.field_1_label_index = field_1_label_index;
ptg.field_2_zero = field_2_zero;
return ptg;
}
public byte getDefaultOperandClass() {
return Ptg.CLASS_REF;
}
}

View File

@ -25,7 +25,7 @@ import org.apache.poi.hssf.record.RecordInputStream;
*
* @author aviks
*/
public final class NameXPtg extends Ptg {
public final class NameXPtg extends OperandPtg {
public final static short sid = 0x39;
private final static int SIZE = 7;
private short field_1_ixals; // index to REF entry in externsheet record
@ -33,31 +33,20 @@ public final class NameXPtg extends Ptg {
private short field_3_reserved; // reserved must be 0
private NameXPtg() {
//Required for clone methods
}
/** Creates new NamePtg */
public NameXPtg(RecordInputStream in)
{
public NameXPtg(RecordInputStream in) {
field_1_ixals = in.readShort();
field_2_ilbl = in.readShort();
field_3_reserved = in.readShort();
//field_2_reserved = LittleEndian.getByteArray(data, offset + 12,12);
}
public void writeBytes(byte [] array, int offset)
{
array[ offset + 0 ] = (byte)(sid + ptgClass);
public void writeBytes(byte [] array, int offset) {
array[ offset + 0 ] = (byte)(sid + getPtgClass());
LittleEndian.putShort(array, offset + 1, field_1_ixals);
LittleEndian.putShort(array,offset+3, field_2_ilbl);
LittleEndian.putShort(array, offset + 5, field_3_reserved);
}
public int getSize()
{
public int getSize() {
return SIZE;
}
@ -67,14 +56,7 @@ public final class NameXPtg extends Ptg {
return book.resolveNameXText(field_1_ixals, field_2_ilbl-1);
}
public byte getDefaultOperandClass() {return Ptg.CLASS_VALUE;}
public Object clone() {
NameXPtg ptg = new NameXPtg();
ptg.field_1_ixals = field_1_ixals;
ptg.field_3_reserved = field_3_reserved;
ptg.field_2_ilbl = field_2_ilbl;
ptg.setClass(ptgClass);
return ptg;
}
public byte getDefaultOperandClass() {
return Ptg.CLASS_VALUE;
}
}

View File

@ -1,4 +1,3 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
@ -18,72 +17,36 @@
package org.apache.poi.hssf.record.formula;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.record.RecordInputStream;
/**
* Ptg class to implement not equal
*
* @author fred at stsci dot edu
*/
public class NotEqualPtg
extends OperationPtg
{
public final static int SIZE = 1;
public final class NotEqualPtg extends ValueOperatorPtg {
public final static byte sid = 0x0e;
/**
* Creates new NotEqualPtg
*/
public NotEqualPtg()
{
public static final ValueOperatorPtg instance = new NotEqualPtg();
private NotEqualPtg() {
// enforce singleton
}
protected byte getSid() {
return sid;
}
public NotEqualPtg( RecordInputStream in )
{
// doesn't need anything
}
public void writeBytes( byte[] array, int offset )
{
array[offset + 0] = sid;
}
public int getSize()
{
return SIZE;
}
public int getType()
{
return TYPE_BINARY;
}
public int getNumberOfOperands()
{
public int getNumberOfOperands() {
return 2;
}
public String toFormulaString( HSSFWorkbook book )
{
return "<>";
}
public String toFormulaString( String[] operands )
{
public String toFormulaString(String[] operands) {
StringBuffer buffer = new StringBuffer();
buffer.append( operands[0] );
buffer.append( toFormulaString( (HSSFWorkbook) null ) );
buffer.append("<>");
buffer.append( operands[1] );
return buffer.toString();
}
public Object clone()
{
return new NotEqualPtg();
}
}

View File

@ -28,22 +28,15 @@ import org.apache.poi.hssf.record.RecordInputStream;
* @author Avik Sengupta
* @author Jason Height (jheight at chariot dot net dot au)
*/
public class NumberPtg
extends Ptg
{
public final class NumberPtg extends ScalarConstantPtg {
public final static int SIZE = 9;
public final static byte sid = 0x1f;
private double field_1_value;
private NumberPtg() {
//Required for clone methods
}
private final double field_1_value;
/** Create a NumberPtg from a byte array read from disk */
public NumberPtg(RecordInputStream in)
{
setValue(in.readDouble());
field_1_value = in.readDouble();
}
/** Create a NumberPtg from a string representation of the number
@ -52,13 +45,7 @@ public class NumberPtg
* @param value : String representation of a floating point number
*/
public NumberPtg(String value) {
setValue(Double.parseDouble(value));
}
public void setValue(double value)
{
field_1_value = value;
field_1_value = Double.parseDouble(value);
}
@ -82,11 +69,4 @@ public class NumberPtg
{
return "" + getValue();
}
public byte getDefaultOperandClass() {return Ptg.CLASS_VALUE;}
public Object clone() {
NumberPtg ptg = new NumberPtg();
ptg.field_1_value = field_1_value;
return ptg;
}
}

View File

@ -17,38 +17,15 @@
package org.apache.poi.hssf.record.formula;
import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
/**
* RefNVPtg
* @author Jason Height (jheight at chariot dot net dot au)
* @author Josh Micich
*/
public abstract class OperandPtg extends Ptg {
public final class RefNVPtg extends ReferencePtg {
public final static byte sid = 0x4C;
protected RefNVPtg() {
//Required for clone methods
}
/** Creates new ValueReferencePtg */
public RefNVPtg(RecordInputStream in)
{
super(in);
}
public String getRefPtgName() {
return "RefNVPtg";
}
public String toFormulaString(HSSFWorkbook book)
{
throw notImplemented();
}
public Object clone() {
throw notImplemented();
}
/**
* All Operand <tt>Ptg</tt>s are classifed ('relative', 'value', 'array')
*/
public final boolean isBaseToken() {
return false;
}
}

View File

@ -17,21 +17,15 @@
package org.apache.poi.hssf.record.formula;
/**
* defines a Ptg that is an operation instead of an operand
* @author andy
*/
public abstract class OperationPtg extends Ptg
{
public abstract class OperationPtg extends Ptg {
public final static int TYPE_UNARY = 0;
public final static int TYPE_BINARY = 1;
public final static int TYPE_FUNCTION = 2;
public abstract int getType();
/**
* returns a string representation of the operations
* the length of the input array should equal the number returned by
@ -45,6 +39,12 @@ public abstract class OperationPtg extends Ptg
*/
public abstract int getNumberOfOperands();
public byte getDefaultOperandClass() {return Ptg.CLASS_VALUE;}
public byte getDefaultOperandClass() {
return Ptg.CLASS_VALUE;
}
public final int getType() {
// TODO remove "int getType();" from Eval hierarchy
throw new RuntimeException("remove this method");
}
}

View File

@ -32,24 +32,15 @@ import org.apache.poi.hssf.record.RecordInputStream;
* Andrew C. Oliver (acoliver at apache dot org)
* @author Jason Height (jheight at chariot dot net dot au)
*/
public class ParenthesisPtg
extends OperationPtg
{
public final class ParenthesisPtg extends ControlPtg {
private final static int SIZE = 1;
public final static byte sid = 0x15;
public ParenthesisPtg()
{
public static final ControlPtg instance = new ParenthesisPtg();
private ParenthesisPtg() {
// enforce singleton
}
public ParenthesisPtg(RecordInputStream in)
{
// doesn't need anything
}
public void writeBytes(byte [] array, int offset)
{
@ -61,16 +52,6 @@ public class ParenthesisPtg
return SIZE;
}
public int getType()
{
return TYPE_BINARY;
}
public int getNumberOfOperands()
{
return 1;
}
public String toFormulaString(HSSFWorkbook book)
{
return "()";
@ -80,11 +61,4 @@ public class ParenthesisPtg
public String toFormulaString(String[] operands) {
return "("+operands[0]+")";
}
public byte getDefaultOperandClass() {return Ptg.CLASS_VALUE;}
public Object clone() {
return new ParenthesisPtg();
}
}

View File

@ -1,4 +1,3 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
@ -16,70 +15,33 @@
limitations under the License.
==================================================================== */
/*
* PercentPtg.java
*
* Created on March 29, 2006, 9:23 PM
*/
package org.apache.poi.hssf.record.formula;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.record.RecordInputStream;
/**
* Percent PTG.
*
* @author Daniel Noll (daniel at nuix.com.au)
*/
public class PercentPtg
extends OperationPtg
{
public final class PercentPtg extends ValueOperatorPtg {
public final static int SIZE = 1;
public final static byte sid = 0x14;
private final static String PERCENT = "%";
/** Creates new PercentPtg */
public static final ValueOperatorPtg instance = new PercentPtg();
public PercentPtg()
{
}
public PercentPtg(RecordInputStream in)
{
// doesn't need anything
private PercentPtg() {
// enforce singleton
}
public void writeBytes(byte [] array, int offset)
{
array[ offset + 0 ] = sid;
protected byte getSid() {
return sid;
}
public int getSize()
{
return SIZE;
}
public int getType()
{
return TYPE_UNARY;
}
public int getNumberOfOperands()
{
public int getNumberOfOperands() {
return 1;
}
/** Implementation of method from Ptg */
public String toFormulaString(HSSFWorkbook book)
{
return "%";
}
/** implementation of method from OperationsPtg*/
public String toFormulaString(String[] operands) {
StringBuffer buffer = new StringBuffer();
@ -87,11 +49,4 @@ public class PercentPtg
buffer.append(PERCENT);
return buffer.toString();
}
public byte getDefaultOperandClass() {return Ptg.CLASS_VALUE;}
public Object clone() {
return new PercentPtg();
}
}

View File

@ -17,58 +17,26 @@
package org.apache.poi.hssf.record.formula;
import java.util.List;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.record.RecordInputStream;
/**
*
* @author andy
* @author Jason Height (jheight at chariot dot net dot au)
*/
public class PowerPtg
extends OperationPtg
{
public final static int SIZE = 1;
public final class PowerPtg extends ValueOperatorPtg {
public final static byte sid = 0x07;
/** Creates new AddPtg */
public static final ValueOperatorPtg instance = new PowerPtg();
public PowerPtg()
{
private PowerPtg() {
// enforce singleton
}
protected byte getSid() {
return sid;
}
public PowerPtg(RecordInputStream in)
{
// doesn't need anything
}
public void writeBytes(byte [] array, int offset)
{
array[ offset + 0 ] = sid;
}
public int getSize()
{
return SIZE;
}
public int getType()
{
return TYPE_BINARY;
}
public int getNumberOfOperands()
{
return 2;
}
public String toFormulaString(HSSFWorkbook book)
{
return "^";
public int getNumberOfOperands() {
return 2; // TODO - 2 seems wrong (Jun 2008). Maybe this method is not relevant
}
public String toFormulaString(String[] operands) {
@ -76,13 +44,8 @@ public class PowerPtg
buffer.append(operands[ 0 ]);
buffer.append(toFormulaString((HSSFWorkbook)null));
buffer.append("^");
buffer.append(operands[ 1 ]);
return buffer.toString();
}
public Object clone() {
return new PowerPtg();
}
}

View File

@ -17,456 +17,371 @@
package org.apache.poi.hssf.record.formula;
import java.util.List;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
/**
* <tt>Ptg</tt> represents a syntactic token in a formula. 'PTG' is an acronym for
* '<b>p</b>arse <b>t</b>hin<b>g</b>'. Originally, the name referred to the single
* byte identifier at the start of the token, but in POI, <tt>Ptg</tt> encapsulates
* the whole formula token (initial byte + value data).
* <p/>
*
* <tt>Ptg</tt>s are logically arranged in a tree representing the structure of the
* parsed formula. However, in BIFF files <tt>Ptg</tt>s are written/read in
* <em>Reverse-Polish Notation</em> order. The RPN ordering also simplifies formula
* evaluation logic, so POI mostly accesses <tt>Ptg</tt>s in the same way.
*
* @author andy
* @author avik
* @author Jason Height (jheight at chariot dot net dot au)
*/
public abstract class Ptg
{
/* convert infix order ptg list to rpn order ptg list
* @return List ptgs in RPN order
* @param infixPtgs List of ptgs in infix order
*/
/* DO NOT REMOVE
*we keep this method in case we wish to change the way we parse
*It needs a getPrecedence in OperationsPtg
public static List ptgsToRpn(List infixPtgs) {
java.util.Stack operands = new java.util.Stack();
java.util.List retval = new java.util.Stack();
java.util.ListIterator i = infixPtgs.listIterator();
Object p;
OperationPtg o ;
boolean weHaveABracket = false;
while (i.hasNext()) {
p=i.next();
if (p instanceof OperationPtg) {
if (p instanceof ParenthesisPtg) {
if (!weHaveABracket) {
operands.push(p);
weHaveABracket = true;
} else {
o = (OperationPtg) operands.pop();
while (!(o instanceof ParenthesisPtg)) {
retval.add(o);
}
weHaveABracket = false;
}
} else {
while (!operands.isEmpty() && ((OperationPtg) operands.peek()).getPrecedence() >= ((OperationPtg) p).getPrecedence() ) { //TODO handle ^ since it is right associative
retval.add(operands.pop());
}
operands.push(p);
}
} else {
retval.add(p);
}
}
while (!operands.isEmpty()) {
if (operands.peek() instanceof ParenthesisPtg ){
//throw some error
} else {
retval.add(operands.pop());
}
}
return retval;
}
*/
/**
* Reads <tt>size</tt> bytes of the input stream, to create an array of <tt>Ptg</tt>s.
* Extra data (beyond <tt>size</tt>) may be read if and <tt>ArrayPtg</tt>s are present.
*/
public static Stack createParsedExpressionTokens(short size, RecordInputStream in )
{
Stack stack = new Stack();
int pos = 0;
List arrayPtgs = null;
while ( pos < size )
{
Ptg ptg = Ptg.createPtg( in );
if (ptg instanceof ArrayPtg) {
if (arrayPtgs == null)
arrayPtgs = new ArrayList(5);
arrayPtgs.add(ptg);
pos += 8;
} else pos += ptg.getSize();
stack.push( ptg );
}
if(pos != size) {
throw new RuntimeException("Ptg array size mismatch");
}
if (arrayPtgs != null) {
for (int i=0;i<arrayPtgs.size();i++) {
ArrayPtg p = (ArrayPtg)arrayPtgs.get(i);
p.readTokenValues(in);
}
}
return stack;
}
public static Ptg createPtg(RecordInputStream in)
{
byte id = in.readByte();
Ptg retval = null;
switch (id)
{
case ExpPtg.sid : // 0x01
retval = new ExpPtg(in);
break;
case AddPtg.sid : // 0x03
retval = new AddPtg(in);
break;
case SubtractPtg.sid : // 0x04
retval = new SubtractPtg(in);
break;
case MultiplyPtg.sid : // 0x05
retval = new MultiplyPtg(in);
break;
case DividePtg.sid : // 0x06
retval = new DividePtg(in);
break;
case PowerPtg.sid : // 0x07
retval = new PowerPtg(in);
break;
case ConcatPtg.sid : // 0x08
retval = new ConcatPtg(in);
break;
case LessThanPtg.sid: // 0x09
retval = new LessThanPtg(in);
break;
case LessEqualPtg.sid : // 0x0a
retval = new LessEqualPtg(in);
break;
case EqualPtg.sid : // 0x0b
retval = new EqualPtg(in);
break;
case GreaterEqualPtg.sid : // 0x0c
retval = new GreaterEqualPtg(in);
break;
case GreaterThanPtg.sid : // 0x0d
retval = new GreaterThanPtg(in);
break;
case NotEqualPtg.sid : // 0x0e
retval = new NotEqualPtg(in);
break;
case IntersectionPtg.sid : // 0x0f
retval = new IntersectionPtg(in);
break;
case UnionPtg.sid : // 0x10
retval = new UnionPtg(in);
break;
case RangePtg.sid : // 0x11
retval = new RangePtg(in);
break;
case UnaryPlusPtg.sid : // 0x12
retval = new UnaryPlusPtg(in);
break;
case UnaryMinusPtg.sid : // 0x13
retval = new UnaryMinusPtg(in);
break;
case PercentPtg.sid : // 0x14
retval = new PercentPtg(in);
break;
case ParenthesisPtg.sid : // 0x15
retval = new ParenthesisPtg(in);
break;
case MissingArgPtg.sid : // 0x16
retval = new MissingArgPtg(in);
break;
case StringPtg.sid : // 0x17
retval = new StringPtg(in);
break;
case AttrPtg.sid : // 0x19
case 0x1a :
retval = new AttrPtg(in);
break;
case ErrPtg.sid : // 0x1c
retval = new ErrPtg(in);
break;
case BoolPtg.sid : // 0x1d
retval = new BoolPtg(in);
break;
case IntPtg.sid : // 0x1e
retval = new IntPtg(in);
break;
case NumberPtg.sid : // 0x1f
retval = new NumberPtg(in);
break;
case ArrayPtg.sid : // 0x20
retval = new ArrayPtg(in);
break;
case ArrayPtgV.sid : // 0x40
retval = new ArrayPtgV(in);
break;
case ArrayPtgA.sid : // 0x60
retval = new ArrayPtgA(in);
break;
case FuncPtg.sid : // 0x21
case FuncPtg.sid + 0x20 : // 0x41
case FuncPtg.sid + 0x40 : // 0x61
retval = new FuncPtg(in);
break;
case FuncVarPtg.sid : // 0x22
case FuncVarPtg.sid + 0x20 : // 0x42
case FuncVarPtg.sid + 0x40 : // 0x62
retval = new FuncVarPtg(in);
break;
case ReferencePtg.sid : // 0x24
retval = new ReferencePtg(in);
break;
case RefAPtg.sid : // 0x64
retval = new RefAPtg(in);
break;
case RefVPtg.sid : // 0x44
retval = new RefVPtg(in);
break;
case RefNAPtg.sid : // 0x6C
retval = new RefNAPtg(in);
break;
case RefNPtg.sid : // 0x2C
retval = new RefNPtg(in);
break;
case RefNVPtg.sid : // 0x4C
retval = new RefNVPtg(in);
break;
case AreaPtg.sid : // 0x25
retval = new AreaPtg(in);
break;
case AreaVPtg.sid: // 0x45
retval = new AreaVPtg(in);
break;
case AreaAPtg.sid: // 0x65
retval = new AreaAPtg(in);
break;
case AreaNAPtg.sid : // 0x6D
retval = new AreaNAPtg(in);
break;
case AreaNPtg.sid : // 0x2D
retval = new AreaNPtg(in);
break;
case AreaNVPtg.sid : // 0x4D
retval = new AreaNVPtg(in);
break;
case MemAreaPtg.sid : // 0x26
case MemAreaPtg.sid + 0x40 : // 0x46
case MemAreaPtg.sid + 0x20 : // 0x66
retval = new MemAreaPtg(in);
break;
case MemErrPtg.sid : // 0x27
case MemErrPtg.sid + 0x20 : // 0x47
case MemErrPtg.sid + 0x40 : // 0x67
retval = new MemErrPtg(in);
break;
case MemFuncPtg.sid : // 0x29
retval = new MemFuncPtg(in);
break;
case RefErrorPtg.sid : // 0x2a
case RefErrorPtg.sid + 0x20 : // 0x4a
case RefErrorPtg.sid + 0x40 : // 0x6a
retval = new RefErrorPtg(in);
break;
case AreaErrPtg.sid : // 0x2b
case AreaErrPtg.sid + 0x20 : // 0x4b
case AreaErrPtg.sid + 0x40 : // 0x6b
retval = new AreaErrPtg(in);
break;
case NamePtg.sid : // 0x23
case NamePtg.sid + 0x20 : // 0x43
case NamePtg.sid + 0x40 : // 0x63
retval = new NamePtg(in);
break;
case NameXPtg.sid : // 0x39
case NameXPtg.sid + 0x20 : // 0x45
case NameXPtg.sid + 0x40 : // 0x79
retval = new NameXPtg(in);
break;
case Area3DPtg.sid : // 0x3b
case Area3DPtg.sid + 0x20 : // 0x5b
case Area3DPtg.sid + 0x40 : // 0x7b
retval = new Area3DPtg(in);
break;
case Ref3DPtg.sid : // 0x3a
case Ref3DPtg.sid + 0x20: // 0x5a
case Ref3DPtg.sid + 0x40: // 0x7a
retval = new Ref3DPtg(in);
break;
case DeletedRef3DPtg.sid: // 0x3c
case DeletedRef3DPtg.sid + 0x20: // 0x5c
case DeletedRef3DPtg.sid + 0x40: // 0x7c
retval = new DeletedRef3DPtg(in);
break;
case DeletedArea3DPtg.sid : // 0x3d
case DeletedArea3DPtg.sid + 0x20 : // 0x5d
case DeletedArea3DPtg.sid + 0x40 : // 0x7d
retval = new DeletedArea3DPtg(in);
break;
case 0x00:
retval = new UnknownPtg();
break;
default :
//retval = new UnknownPtg();
throw new java.lang.UnsupportedOperationException(" Unknown Ptg in Formula: 0x"+
Integer.toHexString(( int ) id) + " (" + ( int ) id + ")");
}
if (id > 0x60) {
retval.setClass(CLASS_ARRAY);
} else if (id > 0x40) {
retval.setClass(CLASS_VALUE);
} else {
retval.setClass(CLASS_REF);
}
return retval;
}
public static int serializePtgStack(Stack expression, byte[] array, int offset) {
int pos = 0;
int size = 0;
if (expression != null)
size = expression.size();
List arrayPtgs = null;
for (int k = 0; k < size; k++) {
Ptg ptg = ( Ptg ) expression.get(k);
ptg.writeBytes(array, pos + offset);
if (ptg instanceof ArrayPtg) {
if (arrayPtgs == null)
arrayPtgs = new ArrayList(5);
arrayPtgs.add(ptg);
pos += 8;
} else pos += ptg.getSize();
}
if (arrayPtgs != null) {
for (int i=0;i<arrayPtgs.size();i++) {
ArrayPtg p = (ArrayPtg)arrayPtgs.get(i);
pos += p.writeTokenValueBytes(array, pos + offset);
}
}
return pos;
}
public abstract int getSize();
public final byte [] getBytes()
{
int size = getSize();
byte[] bytes = new byte[ size ];
writeBytes(bytes, 0);
return bytes;
}
/** write this Ptg to a byte array*/
public abstract void writeBytes(byte [] array, int offset);
/**
* return a string representation of this token alone
*/
public abstract String toFormulaString(HSSFWorkbook book);
/**
* dump a debug representation (hexdump) to a string
*/
public String toDebugString() {
byte[] ba = new byte[getSize()];
String retval=null;
writeBytes(ba,0);
try {
retval = org.apache.poi.util.HexDump.dump(ba,0,0);
} catch (Exception e) {
e.printStackTrace();
}
return retval;
}
/** Overridden toString method to ensure object hash is not printed.
* This helps get rid of gratuitous diffs when comparing two dumps
* Subclasses may output more relevant information by overriding this method
**/
public String toString(){
return this.getClass().toString();
}
public static final byte CLASS_REF = 0x00;
public static final byte CLASS_VALUE = 0x20;
public static final byte CLASS_ARRAY = 0x40;
protected byte ptgClass = CLASS_REF; //base ptg
public void setClass(byte thePtgClass) {
ptgClass = thePtgClass;
}
/** returns the class (REF/VALUE/ARRAY) for this Ptg */
public byte getPtgClass() {
return ptgClass;
}
public abstract byte getDefaultOperandClass();
public abstract Object clone();
public abstract class Ptg implements Cloneable {
/* convert infix order ptg list to rpn order ptg list
* @return List ptgs in RPN order
* @param infixPtgs List of ptgs in infix order
*/
/* DO NOT REMOVE
*we keep this method in case we wish to change the way we parse
*It needs a getPrecedence in OperationsPtg
public static List ptgsToRpn(List infixPtgs) {
java.util.Stack operands = new java.util.Stack();
java.util.List retval = new java.util.Stack();
java.util.ListIterator i = infixPtgs.listIterator();
Object p;
OperationPtg o ;
boolean weHaveABracket = false;
while (i.hasNext()) {
p=i.next();
if (p instanceof OperationPtg) {
if (p instanceof ParenthesisPtg) {
if (!weHaveABracket) {
operands.push(p);
weHaveABracket = true;
} else {
o = (OperationPtg) operands.pop();
while (!(o instanceof ParenthesisPtg)) {
retval.add(o);
}
weHaveABracket = false;
}
} else {
while (!operands.isEmpty() && ((OperationPtg) operands.peek()).getPrecedence() >= ((OperationPtg) p).getPrecedence() ) { //TODO handle ^ since it is right associative
retval.add(operands.pop());
}
operands.push(p);
}
} else {
retval.add(p);
}
}
while (!operands.isEmpty()) {
if (operands.peek() instanceof ParenthesisPtg ){
//throw some error
} else {
retval.add(operands.pop());
}
}
return retval;
}
*/
/**
* Reads <tt>size</tt> bytes of the input stream, to create an array of <tt>Ptg</tt>s.
* Extra data (beyond <tt>size</tt>) may be read if and <tt>ArrayPtg</tt>s are present.
*/
public static Ptg[] readTokens(int size, RecordInputStream in) {
Stack temp = createParsedExpressionTokens((short)size, in);
return toPtgArray(temp);
}
/**
* @deprecated - use readTokens()
*/
public static Stack createParsedExpressionTokens(short size, RecordInputStream in)
{
Stack stack = new Stack();
int pos = 0;
List arrayPtgs = null;
while ( pos < size )
{
Ptg ptg = Ptg.createPtg( in );
if (ptg instanceof ArrayPtg) {
if (arrayPtgs == null)
arrayPtgs = new ArrayList(5);
arrayPtgs.add(ptg);
pos += 8;
} else pos += ptg.getSize();
stack.push( ptg );
}
if(pos != size) {
throw new RuntimeException("Ptg array size mismatch");
}
if (arrayPtgs != null) {
for (int i=0;i<arrayPtgs.size();i++) {
ArrayPtg p = (ArrayPtg)arrayPtgs.get(i);
p.readTokenValues(in);
}
}
return stack;
}
public static Ptg createPtg(RecordInputStream in) {
byte id = in.readByte();
if (id < 0x20) {
return createBasePtg(id, in);
}
Ptg retval = createClassifiedPtg(id, in);
if (id > 0x60) {
retval.setClass(CLASS_ARRAY);
} else if (id > 0x40) {
retval.setClass(CLASS_VALUE);
} else {
retval.setClass(CLASS_REF);
}
return retval;
}
private static Ptg createClassifiedPtg(byte id, RecordInputStream in) {
int baseId = id & 0x1F | 0x20;
switch (baseId) {
case ArrayPtg.sid: return new ArrayPtg(in); // 0x20, 0x40, 0x60
case FuncPtg.sid: return new FuncPtg(in); // 0x21, 0x41, 0x61
case FuncVarPtg.sid: return new FuncVarPtg(in); // 0x22, 0x42, 0x62
case NamePtg.sid: return new NamePtg(in); // 0x23, 0x43, 0x63
case RefPtg.sid: return new RefPtg(in); // 0x24, 0x44, 0x64
case AreaPtg.sid: return new AreaPtg(in); // 0x25, 0x45, 0x65
case MemAreaPtg.sid: return new MemAreaPtg(in); // 0x26, 0x46, 0x66
case MemErrPtg.sid: return new MemErrPtg(in); // 0x27, 0x47, 0x67
case MemFuncPtg.sid: return new MemFuncPtg(in); // 0x29, 0x49, 0x69
case RefErrorPtg.sid: return new RefErrorPtg(in);// 0x2a, 0x4a, 0x6a
case AreaErrPtg.sid: return new AreaErrPtg(in); // 0x2b, 0x4b, 0x6b
case RefNPtg.sid: return new RefNPtg(in); // 0x2c, 0x4c, 0x6c
case AreaNPtg.sid: return new AreaNPtg(in); // 0x2d, 0x4d, 0x6d
case NameXPtg.sid: return new NameXPtg(in); // 0x39, 0x49, 0x79
case Ref3DPtg.sid: return new Ref3DPtg(in); // 0x3a, 0x5a, 0x7a
case Area3DPtg.sid: return new Area3DPtg(in); // 0x3b, 0x5b, 0x7b
case DeletedRef3DPtg.sid: return new DeletedRef3DPtg(in); // 0x3c, 0x5c, 0x7c
case DeletedArea3DPtg.sid: return new DeletedArea3DPtg(in); // 0x3d, 0x5d, 0x7d
}
throw new UnsupportedOperationException(" Unknown Ptg in Formula: 0x"+
Integer.toHexString(id) + " (" + ( int ) id + ")");
}
private static Ptg createBasePtg(byte id, RecordInputStream in) {
switch(id) {
case 0x00: return new UnknownPtg(); // TODO - not a real Ptg
case ExpPtg.sid: return new ExpPtg(in); // 0x01
case AddPtg.sid: return AddPtg.instance; // 0x03
case SubtractPtg.sid: return SubtractPtg.instance; // 0x04
case MultiplyPtg.sid: return MultiplyPtg.instance; // 0x05
case DividePtg.sid: return DividePtg.instance; // 0x06
case PowerPtg.sid: return PowerPtg.instance; // 0x07
case ConcatPtg.sid: return ConcatPtg.instance; // 0x08
case LessThanPtg.sid: return LessThanPtg.instance; // 0x09
case LessEqualPtg.sid: return LessEqualPtg.instance; // 0x0a
case EqualPtg.sid: return EqualPtg.instance; // 0x0b
case GreaterEqualPtg.sid: return GreaterEqualPtg.instance;// 0x0c
case GreaterThanPtg.sid: return GreaterThanPtg.instance; // 0x0d
case NotEqualPtg.sid: return NotEqualPtg.instance; // 0x0e
case IntersectionPtg.sid: return IntersectionPtg.instance;// 0x0f
case UnionPtg.sid: return UnionPtg.instance; // 0x10
case RangePtg.sid: return RangePtg.instance; // 0x11
case UnaryPlusPtg.sid: return UnaryPlusPtg.instance; // 0x12
case UnaryMinusPtg.sid: return UnaryMinusPtg.instance; // 0x13
case PercentPtg.sid: return PercentPtg.instance; // 0x14
case ParenthesisPtg.sid: return ParenthesisPtg.instance; // 0x15
case MissingArgPtg.sid: return MissingArgPtg.instance; // 0x16
case StringPtg.sid: return new StringPtg(in); // 0x17
case AttrPtg.sid:
case 0x1a: return new AttrPtg(in); // 0x19
case ErrPtg.sid: return new ErrPtg(in); // 0x1c
case BoolPtg.sid: return new BoolPtg(in); // 0x1d
case IntPtg.sid: return new IntPtg(in); // 0x1e
case NumberPtg.sid: return new NumberPtg(in); // 0x1f
}
throw new RuntimeException("Unexpected base token id (" + id + ")");
}
/**
*
*
*/
public static int getEncodedSize(Stack ptgs) {
return getEncodedSize(toPtgArray(ptgs));
}
/**
* @return a distinct copy of this <tt>Ptg</tt> if the class is mutable, or the same instance
* if the class is immutable.
*/
public final Ptg copy() {
// TODO - all base tokens are logically immutable, but AttrPtg needs some clean-up
if (this instanceof ValueOperatorPtg) {
return this;
}
if (this instanceof ScalarConstantPtg) {
return this;
}
return (Ptg) clone();
}
protected Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
private static Ptg[] toPtgArray(List l) {
Ptg[] result = new Ptg[l.size()];
l.toArray(result);
return result;
}
private static Stack createStack(Ptg[] formulaTokens) {
Stack result = new Stack();
for (int i = 0; i < formulaTokens.length; i++) {
result.add(formulaTokens[i]);
}
return result;
}
// TODO - several duplicates of this code should be refactored here
public static int getEncodedSize(Ptg[] ptgs) {
int result = 0;
for (int i = 0; i < ptgs.length; i++) {
result += ptgs[i].getSize();
}
return result;
}
/**
* Writes the ptgs to the data buffer, starting at the specified offset.
*
* <br/>
* The 2 byte encode length field is <b>not</b> written by this method.
* @return number of bytes written
*/
public static int serializePtgs(Ptg[] ptgs, byte[] data, int offset) {
return serializePtgStack(createStack(ptgs), data, offset);
}
/**
* @deprecated use serializePtgs()
*/
public static int serializePtgStack(Stack expression, byte[] array, int offset) {
int pos = 0;
int size = 0;
if (expression != null)
size = expression.size();
List arrayPtgs = null;
for (int k = 0; k < size; k++) {
Ptg ptg = ( Ptg ) expression.get(k);
ptg.writeBytes(array, pos + offset);
if (ptg instanceof ArrayPtg) {
if (arrayPtgs == null)
arrayPtgs = new ArrayList(5);
arrayPtgs.add(ptg);
pos += 8;
} else pos += ptg.getSize();
}
if (arrayPtgs != null) {
for (int i=0;i<arrayPtgs.size();i++) {
ArrayPtg p = (ArrayPtg)arrayPtgs.get(i);
pos += p.writeTokenValueBytes(array, pos + offset);
}
}
return pos;
}
/**
* @return the encoded length of this Ptg, including the initial Ptg type identifier byte.
*/
public abstract int getSize();
/**
* @return the encoded length of this Ptg, not including the initial Ptg type identifier byte.
*/
// public abstract int getDataSize();
public final byte [] getBytes()
{
int size = getSize();
byte[] bytes = new byte[ size ];
writeBytes(bytes, 0);
return bytes;
}
/** write this Ptg to a byte array*/
public abstract void writeBytes(byte [] array, int offset);
/**
* return a string representation of this token alone
*/
public abstract String toFormulaString(HSSFWorkbook book);
/**
* dump a debug representation (hexdump) to a string
*/
public final String toDebugString() {
byte[] ba = new byte[getSize()];
String retval=null;
writeBytes(ba,0);
try {
retval = org.apache.poi.util.HexDump.dump(ba,0,0);
} catch (Exception e) {
e.printStackTrace();
}
return retval;
}
/** Overridden toString method to ensure object hash is not printed.
* This helps get rid of gratuitous diffs when comparing two dumps
* Subclasses may output more relevant information by overriding this method
**/
public String toString(){
return this.getClass().toString();
}
public static final byte CLASS_REF = 0x00;
public static final byte CLASS_VALUE = 0x20;
public static final byte CLASS_ARRAY = 0x40;
private byte ptgClass = CLASS_REF; //base ptg
public final void setClass(byte thePtgClass) {
if (isBaseToken()) {
throw new RuntimeException("setClass should not be called on a base token");
}
ptgClass = thePtgClass;
}
/**
* @return the 'operand class' (REF/VALUE/ARRAY) for this Ptg
*/
public final byte getPtgClass() {
return ptgClass;
}
public abstract byte getDefaultOperandClass();
/**
* @return <code>false</code> if this token is classified as 'reference', 'value', or 'array'
*/
public abstract boolean isBaseToken();
}

View File

@ -18,26 +18,24 @@
package org.apache.poi.hssf.record.formula;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.record.RecordInputStream;
/**
* @author Daniel Noll (daniel at nuix dot com dot au)
*/
public class RangePtg extends OperationPtg
{
public final class RangePtg extends OperationPtg {
public final static int SIZE = 1;
public final static byte sid = 0x11;
public RangePtg()
{
public static final OperationPtg instance = new RangePtg();
private RangePtg() {
// enforce singleton
}
public RangePtg(RecordInputStream in)
{
// No contents
public final boolean isBaseToken() {
return true;
}
public int getSize()
{
return SIZE;
@ -48,17 +46,6 @@ public class RangePtg extends OperationPtg
array[ offset + 0 ] = sid;
}
public Object clone()
{
return new RangePtg();
}
public int getType()
{
return TYPE_BINARY;
}
/** Implementation of method from Ptg */
public String toFormulaString(HSSFWorkbook book)
{
return ":";

View File

@ -15,11 +15,10 @@
limitations under the License.
==================================================================== */
package org.apache.poi.hssf.record.formula;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.util.CellReference;
import org.apache.poi.hssf.util.RangeAddress;
import org.apache.poi.hssf.util.SheetReferences;
@ -35,8 +34,7 @@ import org.apache.poi.util.LittleEndian;
* @author Jason Height (jheight at chariot dot net dot au)
* @version 1.0-pre
*/
public class Ref3DPtg extends Ptg {
public final class Ref3DPtg extends OperandPtg {
public final static byte sid = 0x3a;
private final static int SIZE = 7; // 6 + 1 for Ptg
private short field_1_index_extern_sheet;
@ -70,20 +68,19 @@ public class Ref3DPtg extends Ptg {
}
public String toString() {
StringBuffer buffer = new StringBuffer();
buffer.append("Ref3dPtg\n");
buffer.append("Index to Extern Sheet = " + getExternSheetIndex()).append("\n");
buffer.append("Row = " + getRow()).append("\n");
buffer.append("Col = " + getColumn()).append("\n");
buffer.append("ColRowRel= "
+ isRowRelative()).append("\n");
buffer.append("ColRel = " + isColRelative()).append("\n");
return buffer.toString();
CellReference cr = new CellReference(getRow(), getColumn(), !isRowRelative(),!isColRelative());
StringBuffer sb = new StringBuffer();
sb.append(getClass().getName());
sb.append(" [");
sb.append("sheetIx=").append(getExternSheetIndex());
sb.append(" ! ");
sb.append(cr.formatAsString());
sb.append("]");
return sb.toString();
}
public void writeBytes(byte [] array, int offset) {
array[ 0 + offset ] = (byte) (sid + ptgClass);
array[ 0 + offset ] = (byte) (sid + getPtgClass());
LittleEndian.putShort(array, 1 + offset , getExternSheetIndex());
LittleEndian.putShort(array, 3 + offset , (short)getRow());
LittleEndian.putShort(array, 5 + offset , (short)getColumnRaw());
@ -191,14 +188,7 @@ public class Ref3DPtg extends Ptg {
return retval.toString();
}
public byte getDefaultOperandClass() {return Ptg.CLASS_REF;}
public Object clone() {
Ref3DPtg ptg = new Ref3DPtg();
ptg.field_1_index_extern_sheet = field_1_index_extern_sheet;
ptg.field_2_row = field_2_row;
ptg.field_3_column = field_3_column;
ptg.setClass(ptgClass);
return ptg;
}
public byte getDefaultOperandClass() {
return Ptg.CLASS_REF;
}
}

View File

@ -17,28 +17,20 @@
package org.apache.poi.hssf.record.formula;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.BitField;
import org.apache.poi.hssf.util.CellReference;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.util.LittleEndian;
/**
* RefError - handles deleted cell reference
* @author Jason Height (jheight at chariot dot net dot au)
*/
public final class RefErrorPtg extends OperandPtg {
public class RefErrorPtg extends Ptg
{
private final static int SIZE = 5;
public final static byte sid = 0x2a;
private int field_1_reserved;
private RefErrorPtg() {
//Required for clone methods
}
public RefErrorPtg(RecordInputStream in)
{
field_1_reserved = in.readInt();
@ -55,7 +47,7 @@ public class RefErrorPtg extends Ptg
public void writeBytes(byte [] array, int offset)
{
array[offset] = (byte) (sid + ptgClass);
array[offset] = (byte) (sid + getPtgClass());
LittleEndian.putInt(array,offset+1,field_1_reserved);
}
@ -83,11 +75,4 @@ public class RefErrorPtg extends Ptg
public byte getDefaultOperandClass() {
return Ptg.CLASS_REF;
}
public Object clone() {
RefErrorPtg ptg = new RefErrorPtg();
ptg.field_1_reserved = field_1_reserved;
ptg.setClass(ptgClass);
return ptg;
}
}

View File

@ -18,37 +18,21 @@
package org.apache.poi.hssf.record.formula;
import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
/**
* RefNPtg
* @author Jason Height (jheight at apache dot com)
*/
public final class RefNPtg extends ReferencePtg
{
public final class RefNPtg extends RefPtgBase {
public final static byte sid = 0x2C;
protected RefNPtg() {
//Required for clone methods
}
/** Creates new ValueReferencePtg */
public RefNPtg(RecordInputStream in)
{
public RefNPtg(RecordInputStream in) {
super(in);
}
public String getRefPtgName() {
return "RefNPtg";
}
public String toFormulaString(HSSFWorkbook book)
{
throw notImplemented();
}
public Object clone() {
throw notImplemented();
protected byte getSid() {
return sid;
}
}

View File

@ -1,55 +1,53 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hssf.record.formula;
import org.apache.poi.hssf.record.RecordInputStream;
/**
* RefNAPtg
* @author Jason Height (jheight at chariot dot net dot au)
*/
public final class RefAPtg extends ReferencePtg {
public final static byte sid = 0x64;
protected RefAPtg() {
super();
}
public RefAPtg(int row, int column, boolean isRowRelative, boolean isColumnRelative) {
super(row, column, isRowRelative, isColumnRelative);
}
public RefAPtg(RecordInputStream in)
{
super(in);
}
public String getRefPtgName() {
return "RefAPtg";
}
public Object clone() {
RefAPtg ptg = new RefAPtg();
ptg.setRow(getRow());
ptg.setColumnRaw(getColumnRaw());
ptg.setClass(ptgClass);
return ptg;
}
}
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hssf.record.formula;
import org.apache.poi.hssf.record.RecordInputStream;
/**
* ReferencePtg - handles references (such as A1, A2, IA4)
* @author Andrew C. Oliver (acoliver@apache.org)
* @author Jason Height (jheight at chariot dot net dot au)
*/
public final class RefPtg extends RefPtgBase {
public final static byte sid = 0x24;
/**
* Takes in a String representation of a cell reference and fills out the
* numeric fields.
*/
public RefPtg(String cellref) {
super(cellref);
}
public RefPtg(int row, int column, boolean isRowRelative, boolean isColumnRelative) {
setRow(row);
setColumn(column);
setRowRelative(isRowRelative);
setColRelative(isColumnRelative);
}
public RefPtg(RecordInputStream in) {
super(in);
}
protected byte getSid() {
return sid;
}
}

View File

@ -26,98 +26,75 @@ import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.record.RecordInputStream;
/**
* ReferencePtg - handles references (such as A1, A2, IA4)
* ReferencePtgBase - handles references (such as A1, A2, IA4)
* @author Andrew C. Oliver (acoliver@apache.org)
* @author Jason Height (jheight at chariot dot net dot au)
*/
public class ReferencePtg extends Ptg {
/**
* TODO - (May-2008) fix subclasses of ReferencePtg 'RefN~' which are used in shared formulas.
* (See bugzilla 44921)
* The 'RefN~' instances do not work properly, and are expected to be converted by
* SharedFormulaRecord.convertSharedFormulas().
* This conversion currently does not take place for formulas of named ranges, conditional
* format rules and data validation rules.
* Furthermore, conversion is probably not appropriate in those instances.
*/
protected final RuntimeException notImplemented() {
return new RuntimeException("Coding Error: This method should never be called. This ptg should be converted");
}
public abstract class RefPtgBase extends OperandPtg {
private final static int SIZE = 5;
public final static byte sid = 0x24;
private final static int MAX_ROW_NUMBER = 65536;
private final static int MAX_ROW_NUMBER = 65536;
/** The row index - zero based unsigned 16 bit value */
private int field_1_row;
/** Field 2
* - lower 8 bits is the zero based unsigned byte column index
/** Field 2
* - lower 8 bits is the zero based unsigned byte column index
* - bit 16 - isRowRelative
* - bit 15 - isColumnRelative
* - bit 15 - isColumnRelative
*/
private int field_2_col;
private static final BitField rowRelative = BitFieldFactory.getInstance(0x8000);
private static final BitField colRelative = BitFieldFactory.getInstance(0x4000);
private static final BitField column = BitFieldFactory.getInstance(0x00FF);
protected ReferencePtg() {
protected RefPtgBase() {
//Required for clone methods
}
/**
* Takes in a String represnetation of a cell reference and fills out the
* Takes in a String representation of a cell reference and fills out the
* numeric fields.
*/
public ReferencePtg(String cellref) {
protected RefPtgBase(String cellref) {
CellReference c= new CellReference(cellref);
setRow(c.getRow());
setColumn(c.getCol());
setColRelative(!c.isColAbsolute());
setRowRelative(!c.isRowAbsolute());
}
public ReferencePtg(int row, int column, boolean isRowRelative, boolean isColumnRelative) {
protected RefPtgBase(int row, int column, boolean isRowRelative, boolean isColumnRelative) {
setRow(row);
setColumn(column);
setRowRelative(isRowRelative);
setColRelative(isColumnRelative);
}
}
/** Creates new ValueReferencePtg */
public ReferencePtg(RecordInputStream in)
{
protected RefPtgBase(RecordInputStream in) {
field_1_row = in.readUShort();
field_2_col = in.readUShort();
}
public String getRefPtgName() {
return "ReferencePtg";
}
public String toString()
{
StringBuffer buffer = new StringBuffer("[");
buffer.append(getRefPtgName());
buffer.append("]\n");
buffer.append("row = ").append(getRow()).append("\n");
buffer.append("col = ").append(getColumn()).append("\n");
buffer.append("rowrelative = ").append(isRowRelative()).append("\n");
buffer.append("colrelative = ").append(isColRelative()).append("\n");
return buffer.toString();
public final String toString() {
CellReference cr = new CellReference(getRow(), getColumn(), !isRowRelative(),!isColRelative());
StringBuffer sb = new StringBuffer();
sb.append(getClass().getName());
sb.append(" [");
sb.append(cr.formatAsString());
sb.append("]");
return sb.toString();
}
public void writeBytes(byte [] array, int offset)
{
array[offset] = (byte) (sid + ptgClass);
public final void writeBytes(byte [] array, int offset) {
array[offset] = (byte) (getSid() + getPtgClass());
LittleEndian.putShort(array, offset+1, (short)field_1_row);
LittleEndian.putShort(array, offset+3, (short)field_2_col);
}
protected abstract byte getSid();
public void setRow(int row)
{
public final void setRow(int row) {
if(row < 0 || row >= MAX_ROW_NUMBER) {
throw new IllegalArgumentException("The row number, when specified as an integer, must be between 0 and " + MAX_ROW_NUMBER);
}
@ -128,81 +105,61 @@ public class ReferencePtg extends Ptg {
* Returns the row number as a short, which will be
* wrapped (negative) for values between 32769 and 65535
*/
public int getRow()
{
public final int getRow(){
return field_1_row;
}
/**
* Returns the row number as an int, between 0 and 65535
*/
public int getRowAsInt()
{
if(field_1_row < 0) {
return field_1_row + MAX_ROW_NUMBER;
}
public final int getRowAsInt() {
return field_1_row;
}
public boolean isRowRelative()
{
public final boolean isRowRelative() {
return rowRelative.isSet(field_2_col);
}
public void setRowRelative(boolean rel) {
public final void setRowRelative(boolean rel) {
field_2_col=rowRelative.setBoolean(field_2_col,rel);
}
public boolean isColRelative()
{
public final boolean isColRelative() {
return colRelative.isSet(field_2_col);
}
public void setColRelative(boolean rel) {
public final void setColRelative(boolean rel) {
field_2_col=colRelative.setBoolean(field_2_col,rel);
}
public void setColumnRaw(int col)
{
public final void setColumnRawX(int col) { // TODO
field_2_col = col;
}
public int getColumnRaw()
{
public int getColumnRawX() { // TODO
return field_2_col;
}
public void setColumn(int col)
{
if(col < 0 || col > 0x100) {
public final void setColumn(int col) {
if(col < 0 || col >= 0x100) {
throw new IllegalArgumentException("Specified colIx (" + col + ") is out of range");
}
field_2_col = column.setValue(field_2_col, col);
}
public int getColumn() {
public final int getColumn() {
return column.getValue(field_2_col);
}
public int getSize()
{
public final int getSize() {
return SIZE;
}
public String toFormulaString(HSSFWorkbook book)
{
public final String toFormulaString(HSSFWorkbook book) {
//TODO -- should we store a cellreference instance in this ptg?? but .. memory is an issue, i believe!
return (new CellReference(getRowAsInt(),getColumn(),!isRowRelative(),!isColRelative())).formatAsString();
}
public byte getDefaultOperandClass() {
public final byte getDefaultOperandClass() {
return Ptg.CLASS_REF;
}
public Object clone() {
ReferencePtg ptg = new ReferencePtg();
ptg.field_1_row = field_1_row;
ptg.field_2_col = field_2_col;
ptg.setClass(ptgClass);
return ptg;
}
}

View File

@ -1,57 +0,0 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hssf.record.formula;
import org.apache.poi.hssf.record.RecordInputStream;
/**
* RefVPtg
* @author Jason Height (jheight at chariot dot net dot au)
*/
public final class RefVPtg extends ReferencePtg {
public final static byte sid = 0x44;
protected RefVPtg() {
super();
}
public RefVPtg(int row, int column, boolean isRowRelative, boolean isColumnRelative) {
super(row, column, isRowRelative, isColumnRelative);
setClass(CLASS_VALUE);
}
/** Creates new ValueReferencePtg */
public RefVPtg(RecordInputStream in)
{
super(in);
}
public String getRefPtgName() {
return "RefVPtg";
}
public Object clone() {
RefVPtg ptg = new RefVPtg();
ptg.setRow(getRow());
ptg.setColumnRaw(getColumnRaw());
ptg.setClass(ptgClass);
return ptg;
}
}

View File

@ -1,52 +1,30 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hssf.record.formula;
import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
/**
* RefNAPtg
* @author Jason Height (jheight at chariot dot net dot au)
*/
public final class RefNAPtg extends ReferencePtg
{
public final static byte sid = 0x6C;
protected RefNAPtg() {
//Required for clone methods
}
public RefNAPtg(RecordInputStream in)
{
super(in);
}
public String getRefPtgName() {
return "RefNAPtg";
}
public String toFormulaString(HSSFWorkbook book)
{
throw notImplemented();
}
public Object clone() {
throw notImplemented();
}
}
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hssf.record.formula;
/**
* @author Josh Micich
*/
abstract class ScalarConstantPtg extends Ptg {
public boolean isBaseToken() {
return true;
}
public final byte getDefaultOperandClass() {
return Ptg.CLASS_VALUE;
}
}

View File

@ -31,7 +31,7 @@ import org.apache.poi.hssf.record.RecordInputStream;
* @author Jason Height (jheight at chariot dot net dot au)
* @author Bernard Chesnoy
*/
public final class StringPtg extends Ptg {
public final class StringPtg extends ScalarConstantPtg {
public final static int SIZE = 9;
public final static byte sid = 0x17;
private static final BitField fHighByte = BitFieldFactory.getInstance(0x01);
@ -42,15 +42,11 @@ public final class StringPtg extends Ptg {
* NOTE: OO doc says 16bit length, but BiffViewer says 8 Book says something
* totally different, so don't look there!
*/
private int field_1_length;
private byte field_2_options;
private String field_3_string;
private final int field_1_length;
private final byte field_2_options;
private final String field_3_string;
private StringPtg() {
// Required for clone methods
}
/** Create a StringPtg from a byte array read from disk */
/** Create a StringPtg from a stream */
public StringPtg(RecordInputStream in) {
field_1_length = in.readUByte();
field_2_options = in.readByte();
@ -76,9 +72,7 @@ public final class StringPtg extends Ptg {
throw new IllegalArgumentException(
"String literals in formulas can't be bigger than 255 characters ASCII");
}
field_2_options = 0;
field_2_options = (byte) fHighByte.setBoolean(field_2_options, StringUtil
.hasMultibyte(value));
field_2_options = (byte) fHighByte.setBoolean(0, StringUtil.hasMultibyte(value));
field_3_string = value;
field_1_length = value.length(); // for the moment, we support only ASCII strings in formulas we create
}
@ -124,18 +118,6 @@ public final class StringPtg extends Ptg {
return sb.toString();
}
public byte getDefaultOperandClass() {
return Ptg.CLASS_VALUE;
}
public Object clone() {
StringPtg ptg = new StringPtg();
ptg.field_1_length = field_1_length;
ptg.field_2_options = field_2_options;
ptg.field_3_string = field_3_string;
return ptg;
}
public String toString() {
StringBuffer sb = new StringBuffer(64);
sb.append(getClass().getName()).append(" [");

View File

@ -17,57 +17,27 @@
package org.apache.poi.hssf.record.formula;
import java.util.List;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.record.RecordInputStream;
/**
*
* @author andy
* @author Jason Height (jheight at chariot dot net dot au)
*/
public class SubtractPtg
extends OperationPtg
{
public final static int SIZE = 1;
public final class SubtractPtg extends ValueOperatorPtg {
public final static byte sid = 0x04;
public SubtractPtg()
{
public static final ValueOperatorPtg instance = new SubtractPtg();
private SubtractPtg() {
// enforce singleton
}
protected byte getSid() {
return sid;
}
public SubtractPtg(RecordInputStream in)
{
// doesn't need anything
}
public void writeBytes(byte [] array, int offset)
{
array[ offset + 0 ] = sid;
}
public int getSize()
{
return SIZE;
}
public int getType()
{
return TYPE_BINARY;
}
public int getNumberOfOperands()
{
public int getNumberOfOperands() {
return 2;
}
public String toFormulaString(HSSFWorkbook book)
{
return "-";
}
public String toFormulaString(String[] operands) {
StringBuffer buffer = new StringBuffer();
@ -77,8 +47,4 @@ public class SubtractPtg
buffer.append(operands[ 1 ]);
return buffer.toString();
}
public Object clone() {
return new SubtractPtg();
}
}

View File

@ -17,63 +17,30 @@
package org.apache.poi.hssf.record.formula;
import java.util.List;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.record.RecordInputStream;
/**
* Unary Plus operator
* does not have any effect on the operand
* @author Avik Sengupta
*/
public class UnaryMinusPtg extends OperationPtg
{
public final static int SIZE = 1;
public final class UnaryMinusPtg extends ValueOperatorPtg {
public final static byte sid = 0x13;
private final static String MINUS = "-";
/** Creates new AddPtg */
public static final ValueOperatorPtg instance = new UnaryMinusPtg();
public UnaryMinusPtg()
{
}
public UnaryMinusPtg(RecordInputStream in)
{
// doesn't need anything
private UnaryMinusPtg() {
// enforce singleton
}
public void writeBytes(byte [] array, int offset)
{
array[ offset + 0 ] = sid;
protected byte getSid() {
return sid;
}
public int getSize()
{
return SIZE;
}
public int getType()
{
return this.TYPE_UNARY;
}
public int getNumberOfOperands()
{
public int getNumberOfOperands() {
return 1;
}
/** Implementation of method from Ptg */
public String toFormulaString(HSSFWorkbook book)
{
return "+";
}
/** implementation of method from OperationsPtg*/
public String toFormulaString(String[] operands) {
StringBuffer buffer = new StringBuffer();
@ -81,11 +48,4 @@ public class UnaryMinusPtg extends OperationPtg
buffer.append(operands[ 0]);
return buffer.toString();
}
public byte getDefaultOperandClass() {return Ptg.CLASS_VALUE;}
public Object clone() {
return new UnaryPlusPtg();
}
}

View File

@ -17,63 +17,30 @@
package org.apache.poi.hssf.record.formula;
import java.util.List;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.record.RecordInputStream;
/**
* Unary Plus operator
* does not have any effect on the operand
* @author Avik Sengupta
*/
public class UnaryPlusPtg extends OperationPtg
{
public final static int SIZE = 1;
public final class UnaryPlusPtg extends ValueOperatorPtg {
public final static byte sid = 0x12;
private final static String ADD = "+";
/** Creates new AddPtg */
public static final ValueOperatorPtg instance = new UnaryPlusPtg();
public UnaryPlusPtg()
{
}
public UnaryPlusPtg(RecordInputStream in)
{
// doesn't need anything
private UnaryPlusPtg() {
// enforce singleton
}
public void writeBytes(byte [] array, int offset)
{
array[ offset + 0 ] = sid;
protected byte getSid() {
return sid;
}
public int getSize()
{
return SIZE;
}
public int getType()
{
return this.TYPE_UNARY;
}
public int getNumberOfOperands()
{
public int getNumberOfOperands() {
return 1;
}
/** Implementation of method from Ptg */
public String toFormulaString(HSSFWorkbook book)
{
return "+";
}
/** implementation of method from OperationsPtg*/
public String toFormulaString(String[] operands) {
StringBuffer buffer = new StringBuffer();
@ -81,11 +48,4 @@ public class UnaryPlusPtg extends OperationPtg
buffer.append(operands[ 0]);
return buffer.toString();
}
public byte getDefaultOperandClass() {return Ptg.CLASS_VALUE;}
public Object clone() {
return new UnaryPlusPtg();
}
}

View File

@ -18,26 +18,23 @@
package org.apache.poi.hssf.record.formula;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.record.RecordInputStream;
/**
* @author Glen Stampoultzis (glens at apache.org)
*/
public class UnionPtg extends OperationPtg
{
public final class UnionPtg extends OperationPtg {
public final static byte sid = 0x10;
public static final OperationPtg instance = new UnionPtg();
public UnionPtg()
{
private UnionPtg() {
// enforce singleton
}
public UnionPtg(RecordInputStream in)
{
// doesn't need anything
public final boolean isBaseToken() {
return true;
}
public int getSize()
{
return 1;
@ -48,17 +45,6 @@ public class UnionPtg extends OperationPtg
array[ offset + 0 ] = sid;
}
public Object clone()
{
return new UnionPtg();
}
public int getType()
{
return TYPE_BINARY;
}
/** Implementation of method from Ptg */
public String toFormulaString(HSSFWorkbook book)
{
return ",";

View File

@ -24,10 +24,7 @@ import org.apache.poi.hssf.record.RecordInputStream;
* @author andy
* @author Jason Height (jheight at chariot dot net dot au)
*/
public class UnknownPtg
extends Ptg
{
public class UnknownPtg extends Ptg {
private short size = 1;
/** Creates new UnknownPtg */
@ -36,12 +33,13 @@ public class UnknownPtg
{
}
public UnknownPtg(RecordInputStream in)
{
public UnknownPtg(RecordInputStream in) {
// doesn't need anything
}
public boolean isBaseToken() {
return true;
}
public void writeBytes(byte [] array, int offset)
{
}

View File

@ -17,37 +17,38 @@
package org.apache.poi.hssf.record.formula;
import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
/**
* Specifies a rectangular area of cells A1:A4 for instance.
* @author Jason Height (jheight at chariot dot net dot au)
* Common superclass of all value operators.
* Subclasses include all unary and binary operators except for the reference operators (IntersectionPtg, RangePtg, UnionPtg)
*
* @author Josh Micich
*/
public abstract class ValueOperatorPtg extends OperationPtg {
public final class AreaNAPtg extends AreaPtg
{
public final static short sid = 0x6D;
/**
* All Operator <tt>Ptg</tt>s are base tokens (i.e. are not RVA classified)
*/
public final boolean isBaseToken() {
return true;
}
protected AreaNAPtg() {
//Required for clone methods
}
public final byte getDefaultOperandClass() {
return Ptg.CLASS_VALUE;
}
public AreaNAPtg(RecordInputStream in)
{
super(in);
}
public final void writeBytes(byte[] array, int offset) {
array[offset + 0] = getSid();
}
public String getAreaPtgName() {
return "AreaNAPtg";
}
protected abstract byte getSid();
public String toFormulaString(HSSFWorkbook book)
{
throw notImplemented();
}
public Object clone() {
throw notImplemented();
}
public final int getSize() {
return 1;
}
public final String toFormulaString(HSSFWorkbook book) {
// TODO - prune this method out of the hierarchy
throw new RuntimeException("toFormulaString(String[] operands) should be used for subclasses of OperationPtgs");
}
}

View File

@ -17,7 +17,7 @@
package org.apache.poi.hssf.record.formula.eval;
import org.apache.poi.hssf.record.formula.ReferencePtg;
import org.apache.poi.hssf.record.formula.RefPtg;
/**
* @author adeshmukh
@ -26,9 +26,9 @@ import org.apache.poi.hssf.record.formula.ReferencePtg;
public final class Ref2DEval implements RefEval {
private final ValueEval value;
private final ReferencePtg delegate;
private final RefPtg delegate;
public Ref2DEval(ReferencePtg ptg, ValueEval ve) {
public Ref2DEval(RefPtg ptg, ValueEval ve) {
if(ve == null) {
throw new IllegalArgumentException("ve must not be null");
}

View File

@ -220,13 +220,18 @@ public class HSSFDateUtil
// switching stuff, which we can ignore
fs = fs.replaceAll(";@", "");
// If it starts with [$-...], then it is a date, but
// If it starts with [$-...], then could be a date, but
// who knows what that starting bit is all about
fs = fs.replaceAll("\\[\\$\\-.*?\\]", "");
fs = fs.replaceAll("^\\[\\$\\-.*?\\]", "");
// If it starts with something like [Black] or [Yellow],
// then it could be a date
fs = fs.replaceAll("^\\[[a-zA-Z]+\\]", "");
// Otherwise, check it's only made up, in any case, of:
// y m d h s - / , . :
if(fs.matches("^[yYmMdDhHsS\\-/,. :]+$")) {
// optionally followed by AM/PM
if(fs.matches("^[yYmMdDhHsS\\-/,. :]+[ampAMP]*$")) {
return true;
}

View File

@ -40,7 +40,7 @@ import org.apache.poi.hssf.record.formula.OperationPtg;
import org.apache.poi.hssf.record.formula.ParenthesisPtg;
import org.apache.poi.hssf.record.formula.Ptg;
import org.apache.poi.hssf.record.formula.Ref3DPtg;
import org.apache.poi.hssf.record.formula.ReferencePtg;
import org.apache.poi.hssf.record.formula.RefPtg;
import org.apache.poi.hssf.record.formula.StringPtg;
import org.apache.poi.hssf.record.formula.UnionPtg;
import org.apache.poi.hssf.record.formula.UnknownPtg;
@ -342,28 +342,28 @@ public class HSSFFormulaEvaluator {
}
private static ValueEval evaluateCell(HSSFWorkbook workbook, HSSFSheet sheet,
int srcRowNum, short srcColNum, String cellFormulaText) {
FormulaParser parser = new FormulaParser(cellFormulaText, workbook);
parser.parse();
Ptg[] ptgs = parser.getRPNPtg();
// -- parsing over --
Ptg[] ptgs = FormulaParser.parse(cellFormulaText, workbook);
Stack stack = new Stack();
for (int i = 0, iSize = ptgs.length; i < iSize; i++) {
// since we don't know how to handle these yet :(
Ptg ptg = ptgs[i];
if (ptg instanceof ControlPtg) { continue; }
if (ptg instanceof ControlPtg) {
// skip Parentheses, Attr, etc
continue;
}
if (ptg instanceof MemErrPtg) { continue; }
if (ptg instanceof MissingArgPtg) { continue; }
if (ptg instanceof NamePtg) {
// named ranges, macro functions
// named ranges, macro functions
NamePtg namePtg = (NamePtg) ptg;
stack.push(new NameEval(namePtg.getIndex()));
continue;
}
if (ptg instanceof NameXPtg) {
// TODO - external functions
// TODO - external functions
continue;
}
if (ptg instanceof UnknownPtg) { continue; }
@ -371,9 +371,6 @@ public class HSSFFormulaEvaluator {
if (ptg instanceof OperationPtg) {
OperationPtg optg = (OperationPtg) ptg;
// parens can be ignored since we have RPN tokens
if (optg instanceof ParenthesisPtg) { continue; }
if (optg instanceof AttrPtg) { continue; }
if (optg instanceof UnionPtg) { continue; }
OperationEval operation = OperationEvaluatorFactory.create(optg);
@ -389,8 +386,8 @@ public class HSSFFormulaEvaluator {
Eval opresult = invokeOperation(operation, ops, srcRowNum, srcColNum, workbook, sheet);
stack.push(opresult);
}
else if (ptg instanceof ReferencePtg) {
ReferencePtg refPtg = (ReferencePtg) ptg;
else if (ptg instanceof RefPtg) {
RefPtg refPtg = (RefPtg) ptg;
int colIx = refPtg.getColumn();
int rowIx = refPtg.getRow();
HSSFRow row = sheet.getRow(rowIx);
@ -552,7 +549,7 @@ public class HSSFFormulaEvaluator {
Constructor constructor = clazz.getConstructor(AREA3D_CONSTRUCTOR_CLASS_ARRAY);
retval = (OperationEval) constructor.newInstance(new Ptg[] { ptg });
}
else if (ptg instanceof ReferencePtg) {
else if (ptg instanceof RefPtg) {
Constructor constructor = clazz.getConstructor(REFERENCE_CONSTRUCTOR_CLASS_ARRAY);
retval = (OperationEval) constructor.newInstance(new Ptg[] { ptg });
}
@ -610,7 +607,7 @@ public class HSSFFormulaEvaluator {
* Creates a Ref2DEval for ReferencePtg.
* Non existent cells are treated as RefEvals containing BlankEval.
*/
private static Ref2DEval createRef2DEval(ReferencePtg ptg, HSSFCell cell,
private static Ref2DEval createRef2DEval(RefPtg ptg, HSSFCell cell,
HSSFRow row, HSSFSheet sheet, HSSFWorkbook workbook) {
if (cell == null) {
return new Ref2DEval(ptg, BlankEval.INSTANCE);

View File

@ -18,7 +18,6 @@
package org.apache.poi.hssf.usermodel;
import org.apache.poi.hssf.model.Workbook;
import org.apache.poi.hssf.record.BoundSheetRecord;
import org.apache.poi.hssf.record.NameRecord;
import org.apache.poi.hssf.util.RangeAddress;

View File

@ -55,36 +55,72 @@ public class HSSFObjectData
this.record = record;
this.poifs = poifs;
}
/**
* Returns the OLE2 Class Name of the object
*/
public String getOLE2ClassName() {
EmbeddedObjectRefSubRecord subRecord = findObjectRecord();
return subRecord.field_5_ole_classname;
}
/**
* Gets the object data.
* Gets the object data. Only call for ones that have
* data though. See {@link #hasDirectoryEntry()}
*
* @return the object data as an OLE2 directory.
* @throws IOException if there was an error reading the data.
*/
public DirectoryEntry getDirectory() throws IOException
{
Iterator subRecordIter = record.getSubRecords().iterator();
while (subRecordIter.hasNext())
{
Object subRecord = subRecordIter.next();
if (subRecord instanceof EmbeddedObjectRefSubRecord)
{
int streamId = ((EmbeddedObjectRefSubRecord) subRecord).getStreamId();
String streamName = "MBD" + HexDump.toHex(streamId);
public DirectoryEntry getDirectory() throws IOException {
EmbeddedObjectRefSubRecord subRecord = findObjectRecord();
Entry entry = poifs.getRoot().getEntry(streamName);
if (entry instanceof DirectoryEntry)
{
return (DirectoryEntry) entry;
}
else
{
throw new IOException("Stream " + streamName + " was not an OLE2 directory");
}
int streamId = ((EmbeddedObjectRefSubRecord) subRecord).getStreamId();
String streamName = "MBD" + HexDump.toHex(streamId);
Entry entry = poifs.getRoot().getEntry(streamName);
if (entry instanceof DirectoryEntry) {
return (DirectoryEntry) entry;
} else {
throw new IOException("Stream " + streamName + " was not an OLE2 directory");
}
}
/**
* Returns the data portion, for an ObjectData
* that doesn't have an associated POIFS Directory
* Entry
*/
public byte[] getObjectData() {
EmbeddedObjectRefSubRecord subRecord = findObjectRecord();
return subRecord.remainingBytes;
}
/**
* Does this ObjectData have an associated POIFS
* Directory Entry?
* (Not all do, those that don't have a data portion)
*/
public boolean hasDirectoryEntry() {
EmbeddedObjectRefSubRecord subRecord = findObjectRecord();
// Field 6 tells you
return (subRecord.field_6_stream_id != 0);
}
/**
* Finds the EmbeddedObjectRefSubRecord, or throws an
* Exception if there wasn't one
*/
protected EmbeddedObjectRefSubRecord findObjectRecord() {
Iterator subRecordIter = record.getSubRecords().iterator();
while (subRecordIter.hasNext()) {
Object subRecord = subRecordIter.next();
if (subRecord instanceof EmbeddedObjectRefSubRecord) {
return (EmbeddedObjectRefSubRecord)subRecord;
}
}
throw new IllegalStateException("Object data does not contain a reference to an embedded object OLE2 directory");
}
}

View File

@ -26,6 +26,7 @@ import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import java.awt.image.BufferedImage;
import java.awt.*;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.Iterator;
@ -46,6 +47,20 @@ public class HSSFPicture
public static final int PICTURE_TYPE_PNG = HSSFWorkbook.PICTURE_TYPE_PNG; // PNG
public static final int PICTURE_TYPE_DIB = HSSFWorkbook.PICTURE_TYPE_DIB; // Windows DIB
/**
* width of 1px in columns with default width in units of 1/256 of a character width
*/
private static final float PX_DEFAULT = 32.00f;
/**
* width of 1px in columns with overridden width in units of 1/256 of a character width
*/
private static final float PX_MODIFIED = 36.56f;
/**
* Height of 1px of a row
*/
private static final int PX_ROW = 15;
int pictureIndex;
HSSFPatriarch patriarch;
@ -100,59 +115,77 @@ public class HSSFPicture
* @since POI 3.0.2
*/
public HSSFClientAnchor getPreferredSize(){
HSSFClientAnchor anchor = new HSSFClientAnchor();
HSSFClientAnchor anchor = (HSSFClientAnchor)getAnchor();
EscherBSERecord bse = (EscherBSERecord)patriarch.sheet.book.getBSERecord(pictureIndex);
byte[] data = bse.getBlipRecord().getPicturedata();
int type = bse.getBlipTypeWin32();
switch (type){
//we can calculate the preferred size only for JPEG and PNG
//other formats like WMF, EMF and PICT are not supported in Java
case HSSFWorkbook.PICTURE_TYPE_JPEG:
case HSSFWorkbook.PICTURE_TYPE_PNG:
BufferedImage img = null;
ImageReader r = null;
try {
//read the image using javax.imageio.*
ImageInputStream iis = ImageIO.createImageInputStream( new ByteArrayInputStream(data) );
Iterator i = ImageIO.getImageReaders( iis );
r = (ImageReader) i.next();
r.setInput( iis );
img = r.read(0);
Dimension size = getImageDimension();
int[] dpi = getResolution(r);
int imgWidth = img.getWidth()*96/dpi[0];
int imgHeight = img.getHeight()*96/dpi[1];
float w = 0;
//Excel measures cells in units of 1/256th of a character width.
//The cell width calculated based on this info is always "off".
//A better approach seems to be to use empirically obtained cell width and row height
int cellwidth = 64;
int rowheight = 17;
//space in the leftmost cell
w += getColumnWidthInPixels(anchor.col1)*(1 - anchor.dx1/1024);
short col2 = (short)(anchor.col1 + 1);
int dx2 = 0;
int col2 = imgWidth/cellwidth;
int row2 = imgHeight/rowheight;
int dx2 = (int)((float)(imgWidth % cellwidth)/cellwidth * 1024);
int dy2 = (int)((float)(imgHeight % rowheight)/rowheight * 256);
anchor.setCol2((short)col2);
anchor.setDx2(dx2);
anchor.setRow2(row2);
anchor.setDy2(dy2);
} catch (IOException e){
//silently return if ImageIO failed to read the image
log.log(POILogger.WARN, e);
img = null;
}
break;
while(w < size.width){
w += getColumnWidthInPixels(col2++);
}
if(w > size.width) {
//calculate dx2, offset in the rightmost cell
col2--;
float cw = getColumnWidthInPixels(col2);
float delta = w - size.width;
dx2 = (int)((cw-delta)/cw*1024);
}
anchor.col2 = col2;
anchor.dx2 = dx2;
float h = 0;
h += (1 - anchor.dy1/256)* getRowHeightInPixels(anchor.row1);
int row2 = anchor.row1 + 1;
int dy2 = 0;
while(h < size.height){
h += getRowHeightInPixels(row2++);
}
if(h > size.height) {
row2--;
float ch = getRowHeightInPixels(row2);
float delta = h - size.height;
dy2 = (int)((ch-delta)/ch*256);
}
anchor.row2 = row2;
anchor.dy2 = dy2;
return anchor;
}
private float getColumnWidthInPixels(short column){
short cw = patriarch.sheet.getColumnWidth(column);
float px = getPixelWidth(column);
return cw/px;
}
private float getRowHeightInPixels(int i){
HSSFRow row = patriarch.sheet.getRow(i);
float height;
if(row != null) height = row.getHeight();
else height = patriarch.sheet.getDefaultRowHeight();
return height/PX_ROW;
}
private float getPixelWidth(short column){
int def = patriarch.sheet.getDefaultColumnWidth()*256;
short cw = patriarch.sheet.getColumnWidth(column);
return cw == def ? PX_DEFAULT : PX_MODIFIED;
}
/**
* The metadata of PNG and JPEG can contain the width of a pixel in millimeters.
* Return the the "effective" dpi calculated as <code>25.4/HorizontalPixelSize</code>
@ -176,4 +209,42 @@ public class HSSFPicture
return new int[]{hdpi, vdpi};
}
/**
* Return the dimension of this image
*
* @return image dimension
*/
public Dimension getImageDimension(){
EscherBSERecord bse = patriarch.sheet.book.getBSERecord(pictureIndex);
byte[] data = bse.getBlipRecord().getPicturedata();
int type = bse.getBlipTypeWin32();
Dimension size = new Dimension();
switch (type){
//we can calculate the preferred size only for JPEG and PNG
//other formats like WMF, EMF and PICT are not supported in Java
case HSSFWorkbook.PICTURE_TYPE_JPEG:
case HSSFWorkbook.PICTURE_TYPE_PNG:
case HSSFWorkbook.PICTURE_TYPE_DIB:
try {
//read the image using javax.imageio.*
ImageInputStream iis = ImageIO.createImageInputStream( new ByteArrayInputStream(data) );
Iterator i = ImageIO.getImageReaders( iis );
ImageReader r = (ImageReader) i.next();
r.setInput( iis );
BufferedImage img = r.read(0);
int[] dpi = getResolution(r);
size.width = img.getWidth()*96/dpi[0];
size.height = img.getHeight()*96/dpi[1];
} catch (IOException e){
//silently return if ImageIO failed to read the image
log.log(POILogger.WARN, e);
}
break;
}
return size;
}
}

View File

@ -276,8 +276,23 @@ public final class HSSFRow implements Comparable {
/**
* Get the hssfcell representing a given column (logical cell)
* 0-based. If you ask for a cell that is not defined....
* 0-based. If you ask for a cell that is not defined, then
* you get a null.
* This is the basic call, with no policies applied
*
* @param cellnum 0 based column number
* @return HSSFCell representing that column or null if undefined.
*/
private HSSFCell retrieveCell(int cellnum) {
if(cellnum<0||cellnum>=cells.length) return null;
return cells[cellnum];
}
/**
* Get the hssfcell representing a given column (logical cell)
* 0-based. If you ask for a cell that is not defined then
* you get a null, unless you have set a different
* {@link MissingCellPolicy} on the base workbook.
* Short method signature provided to retain binary
* compatibility.
*
@ -288,24 +303,54 @@ public final class HSSFRow implements Comparable {
int ushortCellNum = cellnum & 0x0000FFFF; // avoid sign extension
return getCell(ushortCellNum);
}
/**
* Get the hssfcell representing a given column (logical cell)
* 0-based. If you ask for a cell that is not defined....
* you get a null.
* 0-based. If you ask for a cell that is not defined then
* you get a null, unless you have set a different
* {@link MissingCellPolicy} on the base workbook.
*
* @param cellnum 0 based column number
* @return HSSFCell representing that column or null if undefined.
*/
public HSSFCell getCell(int cellnum) {
if(cellnum<0||cellnum>=cells.length) return null;
return cells[cellnum];
return getCell(cellnum, book.getMissingCellPolicy());
}
/**
* Get the hssfcell representing a given column (logical cell)
* 0-based. If you ask for a cell that is not defined, then
* your supplied policy says what to do
*
* @param cellnum 0 based column number
* @param policy Policy on blank / missing cells
* @return representing that column or null if undefined + policy allows.
*/
public HSSFCell getCell(int cellnum, MissingCellPolicy policy) {
HSSFCell cell = retrieveCell(cellnum);
if(policy == RETURN_NULL_AND_BLANK) {
return cell;
}
if(policy == RETURN_BLANK_AS_NULL) {
if(cell == null) return cell;
if(cell.getCellType() == HSSFCell.CELL_TYPE_BLANK) {
return null;
}
return cell;
}
if(policy == CREATE_NULL_AS_BLANK) {
if(cell == null) {
return createCell((short)cellnum, HSSFCell.CELL_TYPE_BLANK);
}
return cell;
}
throw new IllegalArgumentException("Illegal policy " + policy + " (" + policy.id + ")");
}
/**
* get the number of the first cell contained in this row.
* @return short representing the first logical cell in the row, or -1 if the row does not contain any cells.
*/
public short getFirstCellNum()
{
if (getPhysicalNumberOfCells() == 0)
@ -466,6 +511,26 @@ public final class HSSFRow implements Comparable {
return cellnum;
}
/**
* Used to specify the different possible policies
* if for the case of null and blank cells
*/
public static class MissingCellPolicy {
private static int NEXT_ID = 1;
private final int id;
private MissingCellPolicy() {
this.id = NEXT_ID++;
}
}
/** Missing cells are returned as null, Blank cells are returned as normal */
public static final MissingCellPolicy RETURN_NULL_AND_BLANK = new MissingCellPolicy();
/** Missing cells are returned as null, as are blank cells */
public static final MissingCellPolicy RETURN_BLANK_AS_NULL = new MissingCellPolicy();
/** A new, blank cell is created for missing cells. Blank cells are returned as normal */
public static final MissingCellPolicy CREATE_NULL_AS_BLANK = new MissingCellPolicy();
/**
* @return cell iterator of the physically defined cells.
* Note that the 4th element might well not be cell 4, as the iterator
@ -484,6 +549,9 @@ public final class HSSFRow implements Comparable {
return cellIterator();
}
/**
* An iterator over the (physical) cells in the row.
*/
private class CellIterator implements Iterator
{
int thisId=-1;

View File

@ -37,7 +37,7 @@ import org.apache.poi.hssf.model.Sheet;
import org.apache.poi.hssf.model.Workbook;
import org.apache.poi.hssf.record.*;
import org.apache.poi.hssf.record.formula.Ptg;
import org.apache.poi.hssf.record.formula.ReferencePtg;
import org.apache.poi.hssf.record.formula.RefPtg;
import org.apache.poi.hssf.util.HSSFCellRangeAddress;
import org.apache.poi.hssf.util.HSSFDataValidation;
import org.apache.poi.hssf.util.PaneInformation;
@ -1304,8 +1304,8 @@ public final class HSSFSheet {
Ptg[] ptgs = fp.getRPNPtg();
boolean changed = false;
for(int i=0; i<ptgs.length; i++) {
if(ptgs[i] instanceof ReferencePtg) {
ReferencePtg rptg = (ReferencePtg)ptgs[i];
if(ptgs[i] instanceof RefPtg) {
RefPtg rptg = (RefPtg)ptgs[i];
if(startRow <= rptg.getRowAsInt() &&
rptg.getRowAsInt() <= endRow) {
// References a row that moved

View File

@ -39,7 +39,8 @@ public final class HSSFSheetConditionalFormatting {
/**
* A factory method allowing to create a conditional formatting rule
* with a cell comparison operator
* with a cell comparison operator<p/>
* TODO - formulas containing cell references are currently not parsed properly
*
* @param comparisonOperation - a constant value from
* <tt>{@link HSSFConditionalFormattingRule.ComparisonOperator}</tt>: <p>
@ -72,8 +73,8 @@ public final class HSSFSheetConditionalFormatting {
/**
* A factory method allowing to create a conditional formatting rule with a formula.<br>
*
* The formatting rules are applied by Excel when the value of the formula not equal to 0.
*
* The formatting rules are applied by Excel when the value of the formula not equal to 0.<p/>
* TODO - formulas containing cell references are currently not parsed properly
* @param formula - formula for the valued, compared with the cell
*/
public HSSFConditionalFormattingRule createConditionalFormattingRule(String formula) {

View File

@ -15,12 +15,6 @@
limitations under the License.
==================================================================== */
/*
* HSSFWorkbook.java
*
* Created on September 30, 2001, 3:37 PM
*/
package org.apache.poi.hssf.usermodel;
import org.apache.poi.POIDocument;
@ -35,6 +29,7 @@ import org.apache.poi.hssf.record.*;
import org.apache.poi.hssf.record.formula.Area3DPtg;
import org.apache.poi.hssf.record.formula.MemFuncPtg;
import org.apache.poi.hssf.record.formula.UnionPtg;
import org.apache.poi.hssf.usermodel.HSSFRow.MissingCellPolicy;
import org.apache.poi.hssf.util.CellReference;
import org.apache.poi.hssf.util.SheetReferences;
import org.apache.poi.poifs.filesystem.*;
@ -64,7 +59,6 @@ import java.util.Stack;
* @author Shawn Laubach (slaubach at apache dot org)
* @version 2.0-pre
*/
public class HSSFWorkbook extends POIDocument
{
private static final int DEBUG = POILogger.DEBUG;
@ -88,7 +82,7 @@ public class HSSFWorkbook extends POIDocument
* this holds the HSSFSheet objects attached to this workbook
*/
protected ArrayList sheets;
protected List _sheets;
/**
* this holds the HSSFName objects attached to this workbook
@ -109,6 +103,13 @@ public class HSSFWorkbook extends POIDocument
* someplace else.
*/
private HSSFDataFormat formatter;
/**
* The policy to apply in the event of missing or
* blank cells when fetching from a row.
* See {@link MissingCellPolicy}
*/
private MissingCellPolicy missingCellPolicy = HSSFRow.RETURN_NULL_AND_BLANK;
/** Extended windows meta file */
@ -142,7 +143,7 @@ public class HSSFWorkbook extends POIDocument
{
super(null, null);
workbook = book;
sheets = new ArrayList( INITIAL_CAPACITY );
_sheets = new ArrayList( INITIAL_CAPACITY );
names = new ArrayList( INITIAL_CAPACITY );
}
@ -233,7 +234,7 @@ public class HSSFWorkbook extends POIDocument
this.directory = null;
}
sheets = new ArrayList(INITIAL_CAPACITY);
_sheets = new ArrayList(INITIAL_CAPACITY);
names = new ArrayList(INITIAL_CAPACITY);
// Grab the data from the workbook stream, however
@ -263,7 +264,7 @@ public class HSSFWorkbook extends POIDocument
HSSFSheet hsheet = new HSSFSheet(this, sheet);
sheets.add(hsheet);
_sheets.add(hsheet);
// workbook.setSheetName(sheets.size() -1, "Sheet"+sheets.size());
}
@ -352,8 +353,28 @@ public class HSSFWorkbook extends POIDocument
log.log(POILogger.DEBUG, "convertLabelRecords exit");
}
/**
* Retrieves the current policy on what to do when
* getting missing or blank cells from a row.
* The default is to return blank and null cells.
* {@link MissingCellPolicy}
*/
public MissingCellPolicy getMissingCellPolicy() {
return missingCellPolicy;
}
/**
/**
* Sets the policy on what to do when
* getting missing or blank cells from a row.
* This will then apply to all calls to
* {@link HSSFRow.getCell()}. See
* {@link MissingCellPolicy}
*/
public void setMissingCellPolicy(MissingCellPolicy missingCellPolicy) {
this.missingCellPolicy = missingCellPolicy;
}
/**
* sets the order of appearance for a given sheet.
*
* @param sheetname the name of the sheet to reorder
@ -361,12 +382,12 @@ public class HSSFWorkbook extends POIDocument
*/
public void setSheetOrder(String sheetname, int pos ) {
sheets.add(pos,sheets.remove(getSheetIndex(sheetname)));
_sheets.add(pos,_sheets.remove(getSheetIndex(sheetname)));
workbook.setSheetOrder(sheetname, pos);
}
private void validateSheetIndex(int index) {
int lastSheetIx = sheets.size() - 1;
int lastSheetIx = _sheets.size() - 1;
if (index < 0 || index > lastSheetIx) {
throw new IllegalArgumentException("Sheet index ("
+ index +") is out of range (0.." + lastSheetIx + ")");
@ -380,7 +401,7 @@ public class HSSFWorkbook extends POIDocument
public void setSelectedTab(int index) {
validateSheetIndex(index);
int nSheets = sheets.size();
int nSheets = _sheets.size();
for (int i=0; i<nSheets; i++) {
getSheetAt(i).setSelected(i == index);
}
@ -398,7 +419,7 @@ public class HSSFWorkbook extends POIDocument
for (int i = 0; i < indexes.length; i++) {
validateSheetIndex(indexes[i]);
}
int nSheets = sheets.size();
int nSheets = _sheets.size();
for (int i=0; i<nSheets; i++) {
boolean bSelect = false;
for (int j = 0; j < indexes.length; j++) {
@ -420,7 +441,7 @@ public class HSSFWorkbook extends POIDocument
public void setActiveSheet(int index) {
validateSheetIndex(index);
int nSheets = sheets.size();
int nSheets = _sheets.size();
for (int i=0; i<nSheets; i++) {
getSheetAt(i).setActive(i == index);
}
@ -492,19 +513,15 @@ public class HSSFWorkbook extends POIDocument
* set the sheet name.
* Will throw IllegalArgumentException if the name is greater than 31 chars
* or contains /\?*[]
* @param sheet number (0 based)
* @param sheetIx number (0 based)
*/
public void setSheetName(int sheet, String name)
public void setSheetName(int sheetIx, String name)
{
if (workbook.doesContainsSheetName( name, sheet ))
if (workbook.doesContainsSheetName( name, sheetIx )) {
throw new IllegalArgumentException( "The workbook already contains a sheet with this name" );
if (sheet > (sheets.size() - 1))
{
throw new RuntimeException("Sheet out of bounds");
}
workbook.setSheetName( sheet, name);
validateSheetIndex(sheetIx);
workbook.setSheetName(sheetIx, name);
}
@ -516,15 +533,12 @@ public class HSSFWorkbook extends POIDocument
* or contains /\?*[]
* @param sheet number (0 based)
*/
public void setSheetName( int sheet, String name, short encoding )
public void setSheetName(int sheetIx, String name, short encoding)
{
if (workbook.doesContainsSheetName( name, sheet ))
if (workbook.doesContainsSheetName( name, sheetIx )) {
throw new IllegalArgumentException( "The workbook already contains a sheet with this name" );
if (sheet > (sheets.size() - 1))
{
throw new RuntimeException("Sheet out of bounds");
}
validateSheetIndex(sheetIx);
switch ( encoding ) {
case ENCODING_COMPRESSED_UNICODE:
@ -536,51 +550,39 @@ public class HSSFWorkbook extends POIDocument
throw new RuntimeException( "Unsupported encoding" );
}
workbook.setSheetName( sheet, name, encoding );
workbook.setSheetName( sheetIx, name, encoding );
}
/**
* get the sheet name
* @param sheet Number
* @param sheetIx Number
* @return Sheet name
*/
public String getSheetName(int sheet)
public String getSheetName(int sheetIx)
{
if (sheet > (sheets.size() - 1))
{
throw new RuntimeException("Sheet out of bounds");
}
return workbook.getSheetName(sheet);
validateSheetIndex(sheetIx);
return workbook.getSheetName(sheetIx);
}
/**
* check whether a sheet is hidden
* @param sheet Number
* @param sheetIx Number
* @return True if sheet is hidden
*/
public boolean isSheetHidden(int sheet) {
if (sheet > (sheets.size() - 1))
{
throw new RuntimeException("Sheet out of bounds");
}
return workbook.isSheetHidden(sheet);
public boolean isSheetHidden(int sheetIx) {
validateSheetIndex(sheetIx);
return workbook.isSheetHidden(sheetIx);
}
/**
* Hide or unhide a sheet
*
* @param sheetnum The sheet number
* @param sheetIx The sheet index
* @param hidden True to mark the sheet as hidden, false otherwise
*/
public void setSheetHidden(int sheet, boolean hidden) {
if (sheet > (sheets.size() - 1))
{
throw new RuntimeException("Sheet out of bounds");
}
workbook.setSheetHidden(sheet,hidden);
public void setSheetHidden(int sheetIx, boolean hidden) {
validateSheetIndex(sheetIx);
workbook.setSheetHidden(sheetIx, hidden);
}
/*
@ -602,12 +604,12 @@ public class HSSFWorkbook extends POIDocument
/** Returns the index of the given sheet
* @param sheet the sheet to look up
* @return index of the sheet (0 based)
* @return index of the sheet (0 based). <tt>-1</tt> if not found
*/
public int getSheetIndex(HSSFSheet sheet)
{
for(int i=0; i<sheets.size(); i++) {
if(sheets.get(i) == sheet) {
for(int i=0; i<_sheets.size(); i++) {
if(_sheets.get(i) == sheet) {
return i;
}
}
@ -636,9 +638,9 @@ public class HSSFWorkbook extends POIDocument
{
HSSFSheet sheet = new HSSFSheet(this);
sheets.add(sheet);
workbook.setSheetName(sheets.size() - 1, "Sheet" + (sheets.size() - 1));
boolean isOnlySheet = sheets.size() == 1;
_sheets.add(sheet);
workbook.setSheetName(_sheets.size() - 1, "Sheet" + (_sheets.size() - 1));
boolean isOnlySheet = _sheets.size() == 1;
sheet.setSelected(isOnlySheet);
sheet.setActive(isOnlySheet);
return sheet;
@ -652,13 +654,13 @@ public class HSSFWorkbook extends POIDocument
public HSSFSheet cloneSheet(int sheetNum) {
validateSheetIndex(sheetNum);
HSSFSheet srcSheet = (HSSFSheet) sheets.get(sheetNum);
HSSFSheet srcSheet = (HSSFSheet) _sheets.get(sheetNum);
String srcName = workbook.getSheetName(sheetNum);
HSSFSheet clonedSheet = srcSheet.cloneSheet(this);
clonedSheet.setSelected(false);
clonedSheet.setActive(false);
sheets.add(clonedSheet);
_sheets.add(clonedSheet);
int i = 1;
while (true) {
// Try and find the next sheet name that is unique
@ -672,7 +674,7 @@ public class HSSFWorkbook extends POIDocument
//If the sheet name is unique, then set it otherwise move on to the next number.
if (workbook.getSheetIndex(name) == -1) {
workbook.setSheetName(sheets.size()-1, name);
workbook.setSheetName(_sheets.size()-1, name);
break;
}
}
@ -693,14 +695,14 @@ public class HSSFWorkbook extends POIDocument
public HSSFSheet createSheet(String sheetname)
{
if (workbook.doesContainsSheetName( sheetname, sheets.size() ))
if (workbook.doesContainsSheetName( sheetname, _sheets.size() ))
throw new IllegalArgumentException( "The workbook already contains a sheet of this name" );
HSSFSheet sheet = new HSSFSheet(this);
sheets.add(sheet);
workbook.setSheetName(sheets.size() - 1, sheetname);
boolean isOnlySheet = sheets.size() == 1;
_sheets.add(sheet);
workbook.setSheetName(_sheets.size() - 1, sheetname);
boolean isOnlySheet = _sheets.size() == 1;
sheet.setSelected(isOnlySheet);
sheet.setActive(isOnlySheet);
return sheet;
@ -713,9 +715,14 @@ public class HSSFWorkbook extends POIDocument
public int getNumberOfSheets()
{
return sheets.size();
return _sheets.size();
}
private HSSFSheet[] getSheets() {
HSSFSheet[] result = new HSSFSheet[_sheets.size()];
_sheets.toArray(result);
return result;
}
/**
* Get the HSSFSheet object at the given index.
* @param index of the sheet number (0-based physical & logical)
@ -724,7 +731,7 @@ public class HSSFWorkbook extends POIDocument
public HSSFSheet getSheetAt(int index)
{
return (HSSFSheet) sheets.get(index);
return (HSSFSheet) _sheets.get(index);
}
/**
@ -737,13 +744,13 @@ public class HSSFWorkbook extends POIDocument
{
HSSFSheet retval = null;
for (int k = 0; k < sheets.size(); k++)
for (int k = 0; k < _sheets.size(); k++)
{
String sheetname = workbook.getSheetName(k);
if (sheetname.equalsIgnoreCase(name))
{
retval = (HSSFSheet) sheets.get(k);
retval = (HSSFSheet) _sheets.get(k);
}
}
return retval;
@ -772,11 +779,11 @@ public class HSSFWorkbook extends POIDocument
boolean wasActive = getSheetAt(index).isActive();
boolean wasSelected = getSheetAt(index).isSelected();
sheets.remove(index);
_sheets.remove(index);
workbook.removeSheet(index);
// set the remaining active/selected sheet
int nSheets = sheets.size();
int nSheets = _sheets.size();
if (nSheets < 1) {
// nothing more to do if there are no sheets left
return;
@ -902,9 +909,7 @@ public class HSSFWorkbook extends POIDocument
if (settingRowAndColumn)
{
MemFuncPtg memFuncPtg = new MemFuncPtg();
memFuncPtg.setLenRefSubexpression(23);
ptgs.add(memFuncPtg);
ptgs.add(new MemFuncPtg(23)); // TODO - where did constant '23' come from?
}
if (startColumn >= 0)
{
@ -928,8 +933,7 @@ public class HSSFWorkbook extends POIDocument
}
if (settingRowAndColumn)
{
UnionPtg unionPtg = new UnionPtg();
ptgs.add(unionPtg);
ptgs.add(UnionPtg.instance);
}
nameRecord.setNameDefinition(ptgs);
@ -1152,48 +1156,47 @@ public class HSSFWorkbook extends POIDocument
public byte[] getBytes()
{
if (log.check( POILogger.DEBUG ))
if (log.check( POILogger.DEBUG )) {
log.log(DEBUG, "HSSFWorkbook.getBytes()");
}
HSSFSheet[] sheets = getSheets();
int nSheets = sheets.length;
// before getting the workbook size we must tell the sheets that
// serialization is about to occur.
for (int k = 0; k < sheets.size(); k++)
((HSSFSheet) sheets.get(k)).getSheet().preSerialize();
for (int i = 0; i < nSheets; i++) {
sheets[i].getSheet().preSerialize();
}
int wbsize = workbook.getSize();
int totalsize = workbook.getSize();
// log.debug("REMOVEME: old sizing method "+workbook.serialize().length);
// ArrayList sheetbytes = new ArrayList(sheets.size());
int totalsize = wbsize;
for (int k = 0; k < sheets.size(); k++)
{
// pre-calculate all the sheet sizes and set BOF indexes
int[] estimatedSheetSizes = new int[nSheets];
for (int k = 0; k < nSheets; k++) {
workbook.setSheetBof(k, totalsize);
totalsize += ((HSSFSheet) sheets.get(k)).getSheet().getSize();
int sheetSize = sheets[k].getSheet().getSize();
estimatedSheetSizes[k] = sheetSize;
totalsize += sheetSize;
}
/* if (totalsize < 4096)
{
totalsize = 4096;
}*/
byte[] retval = new byte[totalsize];
int pos = workbook.serialize(0, retval);
// System.arraycopy(wb, 0, retval, 0, wb.length);
for (int k = 0; k < sheets.size(); k++)
{
// byte[] sb = (byte[])sheetbytes.get(k);
// System.arraycopy(sb, 0, retval, pos, sb.length);
int len = ((HSSFSheet) sheets.get(k)).getSheet().serialize(pos,
retval);
pos += len; // sb.length;
for (int k = 0; k < nSheets; k++) {
int serializedSize = sheets[k].getSheet().serialize(pos, retval);
if (serializedSize != estimatedSheetSizes[k]) {
// Wrong offset values have been passed in the call to setSheetBof() above.
// For books with more than one sheet, this discrepancy would cause excel
// to report errors and loose data while reading the workbook
throw new IllegalStateException("Actual serialized sheet size (" + serializedSize
+ ") differs from pre-calculated size (" + estimatedSheetSizes[k]
+ ") for sheet (" + k + ")");
// TODO - add similar sanity check to ensure that Sheet.serializeIndexRecord() does not write mis-aligned offsets either
}
pos += serializedSize;
}
/* for (int k = pos; k < totalsize; k++)
{
retval[k] = 0;
}*/
return retval;
}

View File

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

View File

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

View File

@ -37,6 +37,7 @@ public class RawDataBlock
{
private byte[] _data;
private boolean _eof;
private boolean _hasData;
private static POILogger log = POILogFactory.getLogger(RawDataBlock.class);
/**
@ -66,6 +67,7 @@ public class RawDataBlock
throws IOException {
_data = new byte[ blockSize ];
int count = IOUtils.readFully(stream, _data);
_hasData = (count > 0);
if (count == -1) {
_eof = true;
@ -94,16 +96,21 @@ public class RawDataBlock
/**
* When we read the data, did we hit end of file?
*
* @return true if no data was read because we were at the end of
* the file, else false
*
* @exception IOException
* @return true if the EoF was hit during this block, or
* false if not. If you have a dodgy short last block, then
* it's possible to both have data, and also hit EoF...
*/
public boolean eof()
throws IOException
{
public boolean eof() {
return _eof;
}
/**
* Did we actually find any data to read? It's possible,
* in the event of a short last block, to both have hit
* the EoF, but also to have data
*/
public boolean hasData() {
return _hasData;
}
/* ********** START implementation of ListManagedBlock ********** */
@ -117,7 +124,7 @@ public class RawDataBlock
public byte [] getData()
throws IOException
{
if (eof())
if (! hasData())
{
throw new IOException("Cannot return empty data");
}

View File

@ -51,12 +51,16 @@ public class RawDataBlockList
while (true)
{
RawDataBlock block = new RawDataBlock(stream, bigBlockSize);
// If there was data, add the block to the list
if(block.hasData()) {
blocks.add(block);
}
if (block.eof())
{
// If the stream is now at the End Of File, we're done
if (block.eof()) {
break;
}
blocks.add(block);
}
setBlocks(( RawDataBlock [] ) blocks.toArray(new RawDataBlock[ 0 ]));
}

View File

@ -14,7 +14,7 @@
# limitations under the License.
# Created by (org.apache.poi.hssf.record.formula.function.ExcelFileFormatDocFunctionExtractor)
# from source file 'excelfileformat.odt' (size=355750, crc=0x2FAEA65A)
# from source file 'excelfileformat.odt' (size=356107, md5=0x8f789cb6e75594caf068f8e193004ef4)
#
#Columns: (index, name, minParams, maxParams, returnClass, paramClasses, isVolatile, hasFootnote )
@ -37,7 +37,7 @@
15 SIN 1 1 V V
16 COS 1 1 V V
17 TAN 1 1 V V
18 ARCTAN 1 1 V V
18 ATAN 1 1 V V
19 PI 0 0 V -
20 SQRT 1 1 V V
21 EXP 1 1 V V
@ -141,8 +141,8 @@
169 COUNTA 0 30 V R
183 PRODUCT 0 30 V R
184 FACT 1 1 V V
191 DPRODUCT 3 3 V R R R
192 ISNONTEXT 1 1 V V
189 DPRODUCT 3 3 V R R R
190 ISNONTEXT 1 1 V V
193 STDEVP 1 30 V R
194 VARP 1 30 V R
195 DSTDEVP 3 3 V R R R
@ -184,6 +184,8 @@
244 INFO 1 1 V V
# New Built-In Sheet Functions in BIFF4
14 FIXED 2 3 V V V V x
204 USDOLLAR 1 2 V V V x
215 DBCS 1 1 V V x
216 RANK 2 3 V V R V
247 DB 4 5 V V V V V V
252 FREQUENCY 2 2 A R R

Some files were not shown because too many files have changed in this diff Show More