From fd95f8dfcb827aea1dbc6bbd6dc437c2b022c18a Mon Sep 17 00:00:00 2001
From: "(no author)" <(no author)@unknown>
Date: Sun, 2 Nov 2003 11:20:31 +0000
Subject: [PATCH] This commit was manufactured by cvs2svn to create tag
'REL_2_0_RC1'.
git-svn-id: https://svn.apache.org/repos/asf/jakarta/poi/tags/REL_2_0_RC1@353435 13f79535-47bb-0310-9956-ffa450edef68
---
.classpath | 10 -
.cvsignore | 3 +
.project | 17 -
build.xml | 91 ++--
src/documentation/content/xdocs/book.xml | 2 +-
src/documentation/content/xdocs/changes.xml | 129 ------
.../xdocs/dtd/book-cocoon-v10.dtd | 0
.../{ => content}/xdocs/dtd/changes-v11.dtd | 0
.../{ => content}/xdocs/dtd/document-v11.dtd | 0
.../{ => content}/xdocs/dtd/faq-v11.dtd | 0
.../xdocs/dtd/javadoc-v04draft.dtd | 0
.../xdocs/dtd/specification-v11.dtd | 0
.../{ => content}/xdocs/dtd/todo-v11.dtd | 0
.../content/xdocs/howtobuild.xml | 4 +
.../content/xdocs/hssf/chart.xml | 5 +-
.../content/xdocs/hssf/quick-guide.xml | 10 +-
src/documentation/content/xdocs/index.xml | 10 +-
src/documentation/content/xdocs/site.xml | 4 +-
src/documentation/content/xdocs/status.xml | 284 +++++++-----
src/documentation/content/xdocs/tabs.xml | 6 +-
.../content/xdocs/trans/de/book.xml | 2 +-
.../content/xdocs/trans/es/book.xml | 2 +-
.../content/xdocs/trans/es/changes.xml | 106 -----
.../resources/images/group-logo.gif | Bin 8146 -> 5258 bytes
src/documentation/skinconf.xml | 18 +-
.../usermodel/examples/ReadWriteWorkbook.java | 2 +
src/java/org/apache/poi/hpsf/ClassID.java | 101 ++++-
src/java/org/apache/poi/hpsf/TypeReader.java | 74 ++--
src/java/org/apache/poi/hpsf/Variant.java | 108 +++--
.../apache/poi/hssf/dev/FormulaViewer.java | 7 +-
.../apache/poi/hssf/model/FormulaParser.java | 107 +++--
src/java/org/apache/poi/hssf/model/Sheet.java | 300 ++++++++-----
.../org/apache/poi/hssf/model/Workbook.java | 170 +++----
.../poi/hssf/model/WorkbookRecordList.java | 6 +-
.../apache/poi/hssf/record/BoolErrRecord.java | 10 +-
.../poi/hssf/record/BottomMarginRecord.java | 188 +++++++-
.../poi/hssf/record/BoundSheetRecord.java | 12 +
.../poi/hssf/record/ContinueRecord.java | 10 +
.../poi/hssf/record/ExtSSTInfoSubRecord.java | 6 +-
.../apache/poi/hssf/record/ExtSSTRecord.java | 67 ++-
.../poi/hssf/record/ExternSheetRecord.java | 231 +++++++++-
.../apache/poi/hssf/record/FormulaRecord.java | 14 +-
.../apache/poi/hssf/record/LabelRecord.java | 34 +-
.../apache/poi/hssf/record/NameRecord.java | 76 +++-
.../poi/hssf/record/PasswordRecord.java | 10 +
.../apache/poi/hssf/record/ProtectRecord.java | 10 +-
.../poi/hssf/record/ProtectionRev4Record.java | 14 +-
.../org/apache/poi/hssf/record/Record.java | 16 -
.../poi/hssf/record/RecordProcessor.java | 5 +
.../poi/hssf/record/SSTDeserializer.java | 89 ++--
.../org/apache/poi/hssf/record/SSTRecord.java | 70 ++-
.../hssf/record/SSTRecordSizeCalculator.java | 4 +-
.../apache/poi/hssf/record/SSTSerializer.java | 44 +-
.../apache/poi/hssf/record/StringRecord.java | 5 +
.../apache/poi/hssf/record/StyleRecord.java | 45 +-
.../apache/poi/hssf/record/UnknownRecord.java | 13 +-
.../aggregates/FormulaRecordAggregate.java | 41 +-
.../record/formula/AbstractFunctionPtg.java | 12 +-
.../poi/hssf/record/formula/AddPtg.java | 4 +-
.../poi/hssf/record/formula/Area3DPtg.java | 5 +-
.../poi/hssf/record/formula/AreaPtg.java | 5 +-
.../poi/hssf/record/formula/AttrPtg.java | 10 +-
.../poi/hssf/record/formula/BoolPtg.java | 4 +-
.../poi/hssf/record/formula/ConcatPtg.java | 4 +-
.../poi/hssf/record/formula/DividePtg.java | 6 +-
.../poi/hssf/record/formula/EqualPtg.java | 6 +-
.../poi/hssf/record/formula/ExpPtg.java | 9 +-
.../poi/hssf/record/formula/FuncPtg.java | 3 +-
.../poi/hssf/record/formula/FuncVarPtg.java | 1 +
.../hssf/record/formula/GreaterEqualPtg.java | 8 +-
.../hssf/record/formula/GreaterThanPtg.java | 6 +-
.../poi/hssf/record/formula/IntPtg.java | 4 +-
.../poi/hssf/record/formula/LessEqualPtg.java | 8 +-
.../poi/hssf/record/formula/LessThanPtg.java | 7 +-
.../poi/hssf/record/formula/MemErrPtg.java | 4 +-
.../poi/hssf/record/formula/MemFuncPtg.java | 4 +-
.../hssf/record/formula/MissingArgPtg.java | 6 +-
.../poi/hssf/record/formula/MultiplyPtg.java | 10 +-
.../poi/hssf/record/formula/NamePtg.java | 50 ++-
.../poi/hssf/record/formula/NameXPtg.java | 7 +-
.../poi/hssf/record/formula/NotEqualPtg.java | 8 +-
.../poi/hssf/record/formula/NumberPtg.java | 5 +-
.../hssf/record/formula/ParenthesisPtg.java | 5 +-
.../poi/hssf/record/formula/PowerPtg.java | 6 +-
.../apache/poi/hssf/record/formula/Ptg.java | 18 +-
.../poi/hssf/record/formula/Ref3DPtg.java | 7 +-
.../poi/hssf/record/formula/ReferencePtg.java | 5 +-
.../poi/hssf/record/formula/StringPtg.java | 60 ++-
.../poi/hssf/record/formula/SubtractPtg.java | 4 +-
.../hssf/record/formula/UnaryMinusPtg.java | 127 ++++++
.../poi/hssf/record/formula/UnaryPlusPtg.java | 127 ++++++
.../poi/hssf/record/formula/UnionPtg.java | 4 +-
.../poi/hssf/record/formula/UnknownPtg.java | 4 +-
.../apache/poi/hssf/usermodel/HSSFCell.java | 9 +-
.../apache/poi/hssf/usermodel/HSSFFont.java | 2 +-
.../apache/poi/hssf/usermodel/HSSFName.java | 4 +-
.../poi/hssf/usermodel/HSSFPalette.java | 2 +-
.../apache/poi/hssf/usermodel/HSSFSheet.java | 140 +++++-
.../poi/hssf/usermodel/HSSFWorkbook.java | 26 +-
.../poi/poifs/filesystem/DirectoryEntry.java | 17 +
.../poi/poifs/filesystem/DirectoryNode.java | 21 +
.../poi/poifs/filesystem/POIFSFileSystem.java | 2 +
.../apache/poi/poifs/property/Property.java | 35 +-
.../poi/poifs/storage/DocumentBlock.java | 3 +-
.../poi/poifs/storage/HeaderBlockReader.java | 3 +-
.../poi/poifs/storage/RawDataBlock.java | 3 +-
src/java/org/apache/poi/util/HexDump.java | 85 +++-
src/java/org/apache/poi/util/HexRead.java | 226 +++++++++-
src/java/org/apache/poi/util/IOUtils.java | 99 +++++
.../org/apache/poi/util/LittleEndian.java | 30 +-
src/java/org/apache/poi/util/StringUtil.java | 364 ++++++++++++++-
.../org/apache/poi/util/SystemOutLogger.java | 19 +-
.../org/apache/poi/hpsf/basic/POIFile.java | 15 +-
.../org/apache/poi/hpsf/basic/TestBasic.java | 188 ++++----
.../apache/poi/hpsf/basic/TestClassID.java | 171 ++++++++
.../poi/hpsf/basic/TestEmptyProperties.java | 189 ++++++++
.../apache/poi/hpsf/basic/TestUnicode.java | 81 ++--
.../org/apache/poi/hpsf/basic/Util.java | 143 +++---
.../org/apache/poi/hpsf/data/TestCorel.shw | Bin 0 -> 76800 bytes
.../org/apache/poi/hssf/data/12561-1.xls | Bin 0 -> 32768 bytes
.../org/apache/poi/hssf/data/12561-2.xls | Bin 0 -> 50176 bytes
.../org/apache/poi/hssf/data/12843-1.xls | Bin 0 -> 302080 bytes
.../org/apache/poi/hssf/data/12843-2.xls | Bin 0 -> 48128 bytes
.../org/apache/poi/hssf/data/13224.xls | Bin 0 -> 13824 bytes
.../org/apache/poi/hssf/data/13796.xls | Bin 0 -> 49152 bytes
.../org/apache/poi/hssf/data/14330-1.xls | Bin 0 -> 48640 bytes
.../org/apache/poi/hssf/data/14330-2.xls | Bin 0 -> 13824 bytes
.../org/apache/poi/hssf/data/14460.xls | Bin 0 -> 18432 bytes
.../org/apache/poi/hssf/data/15228.xls | Bin 0 -> 692224 bytes
.../org/apache/poi/hssf/data/15375.xls | Bin 0 -> 28160 bytes
.../org/apache/poi/hssf/data/15556.xls | Bin 0 -> 309760 bytes
.../org/apache/poi/hssf/data/19599-1.xls | Bin 0 -> 128512 bytes
.../org/apache/poi/hssf/data/19599-2.xls | Bin 0 -> 44544 bytes
.../org/apache/poi/hssf/data/22742.xls | Bin 0 -> 53248 bytes
.../org/apache/poi/hssf/data/24215.xls | Bin 0 -> 17408 bytes
.../poi/hssf/data/EmbeddedChartHeaderTest.xls | Bin 0 -> 15360 bytes
.../org/apache/poi/hssf/data/SquareMacro.xls | Bin 0 -> 25600 bytes
.../apache/poi/hssf/data/blankworkbook.xls | Bin 0 -> 13824 bytes
.../org/apache/poi/hssf/model/SheetTest.java | 33 +-
.../poi/hssf/model/TestFormulaParser.java | 33 +-
.../poi/hssf/record/TestBoundSheetRecord.java | 20 +
.../poi/hssf/record/TestSSTDeserializer.java | 10 +-
.../apache/poi/hssf/record/TestSSTRecord.java | 4 +-
.../apache/poi/hssf/usermodel/TestBugs.java | 413 ++++++++++++++++++
.../poi/hssf/usermodel/TestCloneSheet.java | 2 +-
.../poi/hssf/usermodel/TestFormulas.java | 72 ++-
.../poi/hssf/usermodel/TestHSSFCell.java | 4 +-
.../hssf/usermodel/TestHSSFHeaderFooter.java | 126 ++++++
.../poi/hssf/usermodel/TestHSSFSheet.java | 147 ++++++-
.../hssf/usermodel/TestSheetShiftRows.java | 13 +
.../poi/hssf/usermodel/TestWorkbook.java | 2 +
.../poi/poifs/filesystem/SlowInputStream.java | 76 ++++
.../poi/poifs/filesystem/TestDocument.java | 2 +-
.../poifs/property/TestDocumentProperty.java | 3 +
.../poi/poifs/property/TestRootProperty.java | 5 +-
.../org/apache/poi/util/TestHexDump.java | 3 +
156 files changed, 4655 insertions(+), 1345 deletions(-)
delete mode 100644 .classpath
delete mode 100644 .project
delete mode 100644 src/documentation/content/xdocs/changes.xml
rename src/documentation/{ => content}/xdocs/dtd/book-cocoon-v10.dtd (100%)
mode change 100755 => 100644
rename src/documentation/{ => content}/xdocs/dtd/changes-v11.dtd (100%)
rename src/documentation/{ => content}/xdocs/dtd/document-v11.dtd (100%)
rename src/documentation/{ => content}/xdocs/dtd/faq-v11.dtd (100%)
rename src/documentation/{ => content}/xdocs/dtd/javadoc-v04draft.dtd (100%)
mode change 100755 => 100644
rename src/documentation/{ => content}/xdocs/dtd/specification-v11.dtd (100%)
rename src/documentation/{ => content}/xdocs/dtd/todo-v11.dtd (100%)
delete mode 100644 src/documentation/content/xdocs/trans/es/changes.xml
create mode 100644 src/java/org/apache/poi/hssf/record/formula/UnaryMinusPtg.java
create mode 100644 src/java/org/apache/poi/hssf/record/formula/UnaryPlusPtg.java
create mode 100644 src/java/org/apache/poi/util/IOUtils.java
create mode 100644 src/testcases/org/apache/poi/hpsf/basic/TestClassID.java
create mode 100644 src/testcases/org/apache/poi/hpsf/basic/TestEmptyProperties.java
create mode 100755 src/testcases/org/apache/poi/hpsf/data/TestCorel.shw
create mode 100755 src/testcases/org/apache/poi/hssf/data/12561-1.xls
create mode 100755 src/testcases/org/apache/poi/hssf/data/12561-2.xls
create mode 100644 src/testcases/org/apache/poi/hssf/data/12843-1.xls
create mode 100644 src/testcases/org/apache/poi/hssf/data/12843-2.xls
create mode 100755 src/testcases/org/apache/poi/hssf/data/13224.xls
create mode 100644 src/testcases/org/apache/poi/hssf/data/13796.xls
create mode 100644 src/testcases/org/apache/poi/hssf/data/14330-1.xls
create mode 100644 src/testcases/org/apache/poi/hssf/data/14330-2.xls
create mode 100644 src/testcases/org/apache/poi/hssf/data/14460.xls
create mode 100644 src/testcases/org/apache/poi/hssf/data/15228.xls
create mode 100644 src/testcases/org/apache/poi/hssf/data/15375.xls
create mode 100644 src/testcases/org/apache/poi/hssf/data/15556.xls
create mode 100644 src/testcases/org/apache/poi/hssf/data/19599-1.xls
create mode 100644 src/testcases/org/apache/poi/hssf/data/19599-2.xls
create mode 100644 src/testcases/org/apache/poi/hssf/data/22742.xls
create mode 100644 src/testcases/org/apache/poi/hssf/data/24215.xls
create mode 100644 src/testcases/org/apache/poi/hssf/data/EmbeddedChartHeaderTest.xls
create mode 100644 src/testcases/org/apache/poi/hssf/data/SquareMacro.xls
create mode 100644 src/testcases/org/apache/poi/hssf/data/blankworkbook.xls
create mode 100644 src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java
create mode 100644 src/testcases/org/apache/poi/hssf/usermodel/TestHSSFHeaderFooter.java
create mode 100644 src/testcases/org/apache/poi/poifs/filesystem/SlowInputStream.java
diff --git a/.classpath b/.classpath
deleted file mode 100644
index 75589e24b1..0000000000
--- a/.classpath
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
[P] simple counted array. How long is this? How is it to be * interpreted?
*/ - public final static int VT_VECTOR = 0x1000; + public static final int VT_VECTOR = 0x1000; /** *[V] SAFEARRAY*. How * long is this? How is it to be interpreted?
*/ - public final static int VT_ARRAY = 0x2000; + public static final int VT_ARRAY = 0x2000; /** *[V] void* for local use. How long is this? How is it to be * interpreted?
*/ - public final static int VT_BYREF = 0x4000; + public static final int VT_BYREF = 0x4000; - public final static int VT_RESERVED = 0x8000; + /** + *FIXME: Document this!
+ */ + public static final int VT_RESERVED = 0x8000; - public final static int VT_ILLEGAL = 0xFFFF; + /** + *FIXME: Document this!
+ */ + public static final int VT_ILLEGAL = 0xFFFF; - public final static int VT_ILLEGALMASKED = 0xFFF; + /** + *FIXME: Document this!
+ */ + public static final int VT_ILLEGALMASKED = 0xFFF; - public final static int VT_TYPEMASK = 0xFFF; + /** + *FIXME: Document this!
+ */ + public static final int VT_TYPEMASK = 0xFFF; -} +} \ No newline at end of file diff --git a/src/java/org/apache/poi/hssf/dev/FormulaViewer.java b/src/java/org/apache/poi/hssf/dev/FormulaViewer.java index 1e7fd95965..3443fda1a6 100644 --- a/src/java/org/apache/poi/hssf/dev/FormulaViewer.java +++ b/src/java/org/apache/poi/hssf/dev/FormulaViewer.java @@ -77,7 +77,6 @@ import org.apache.poi.hssf.record.*; import org.apache.poi.hssf.record.formula.*; import org.apache.poi.hssf.model.*; import org.apache.poi.hssf.usermodel.*; -import org.apache.poi.hssf.util.SheetReferences; /** * FormulaViewer - finds formulas in a BIFF8 file and attempts to read them/display @@ -144,7 +143,7 @@ public class FormulaViewer StringBuffer buf = new StringBuffer(); if (token instanceof ExpPtg) return; - buf.append(name=((OperationPtg) token).toFormulaString((SheetReferences)null)); + buf.append(name=((OperationPtg) token).toFormulaString((Workbook)null)); buf.append(sep); switch (token.getPtgClass()) { case Ptg.CLASS_REF : @@ -213,7 +212,7 @@ public class FormulaViewer StringBuffer buf = new StringBuffer(); for (int i=0;i* contains the elements of "info" in the SST's array field
- * WE HAVE VERY LITTLE INFORMATION ON HOW TO IMPLEMENT THIS RECORD! (EXTSSST)
* @author Andrew C. Oliver (acoliver at apache dot org) * @version 2.0-pre * @see org.apache.poi.hssf.record.ExtSSTRecord @@ -74,6 +73,7 @@ import org.apache.poi.util.LittleEndian; public class ExtSSTInfoSubRecord extends Record { + public static final int INFO_SIZE = 8; public final static short sid = 0xFFF; // only here for conformance, doesn't really have an sid private int field_1_stream_pos; // stream pointer to the SST record @@ -114,7 +114,7 @@ public class ExtSSTInfoSubRecord field_1_stream_pos = pos; } - public void setBucketSSTOffset(short offset) + public void setBucketRecordOffset(short offset) { field_2_bucket_sst_offset = offset; } @@ -159,6 +159,6 @@ public class ExtSSTInfoSubRecord public short getSid() { - return this.sid; + return sid; } } diff --git a/src/java/org/apache/poi/hssf/record/ExtSSTRecord.java b/src/java/org/apache/poi/hssf/record/ExtSSTRecord.java index 7a8e2391e9..9a85e5966d 100644 --- a/src/java/org/apache/poi/hssf/record/ExtSSTRecord.java +++ b/src/java/org/apache/poi/hssf/record/ExtSSTRecord.java @@ -61,13 +61,13 @@ import java.util.ArrayList; /** * Title: Extended Static String Table
- * Description: I really don't understand this thing... its supposed to be "a hash - * table for optimizing external copy operations" -- - *
- * This sounds like a job for Marc "BitMaster" Johnson aka the - * "Hawaiian Master Chef".
+ * Description: This record is used for a quick lookup into the SST record. This + * record breaks the SST table into a set of buckets. The offsets + * to these buckets within the SST record are kept as well as the + * position relative to the start of the SST record. * REFERENCE: PG 313 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)
* @author Andrew C. Oliver (acoliver at apache dot org)
+ * @author Jason Height (jheight at apache dot org)
* @version 2.0-pre
* @see org.apache.poi.hssf.record.ExtSSTInfoSubRecord
*/
@@ -75,10 +75,15 @@ import java.util.ArrayList;
public class ExtSSTRecord
extends Record
{
+ public static final int DEFAULT_BUCKET_SIZE = 8;
+ //Cant seem to find this documented but from the biffviewer it is clear that
+ //Excel only records the indexes for the first 128 buckets.
+ public static final int MAX_BUCKETS = 128;
public final static short sid = 0xff;
- private short field_1_strings_per_bucket;
+ private short field_1_strings_per_bucket = DEFAULT_BUCKET_SIZE;
private ArrayList field_2_sst_info;
+
public ExtSSTRecord()
{
field_2_sst_info = new ArrayList();
@@ -119,12 +124,11 @@ public class ExtSSTRecord
}
}
- // this probably doesn't work but we don't really care at this point
protected void fillFields(byte [] data, short size, int offset)
{
field_2_sst_info = new ArrayList();
field_1_strings_per_bucket = LittleEndian.getShort(data, 0 + offset);
- for (int k = 2; k < ((data.length - offset) - size); k += 8)
+ for (int k = 2; k < (size-offset); k += 8)
{
byte[] tempdata = new byte[ 8 + offset ];
@@ -189,26 +193,55 @@ public class ExtSSTRecord
public int serialize(int offset, byte [] data)
{
LittleEndian.putShort(data, 0 + offset, sid);
-
-// LittleEndian.putShort(data,2,(short)(2 + (getNumInfoRecords() *8)));
- LittleEndian.putShort(data, 2 + offset, ( short ) (2 + (0x3fa - 2)));
- int pos = 4;
+ LittleEndian.putShort(data, 2 + offset, (short)(getRecordSize() - 4));
+ LittleEndian.putShort(data, 4 + offset, field_1_strings_per_bucket);
+ int pos = 6;
for (int k = 0; k < getNumInfoRecords(); k++)
{
- System.arraycopy(getInfoRecordAt(k).serialize(), 0, data,
- pos + offset, 8);
+ ExtSSTInfoSubRecord rec = getInfoRecordAt(k);
+ pos += rec.serialize(pos + offset, data);
}
- return getRecordSize();
+ return pos;
}
+ /** Returns the size of this record */
public int getRecordSize()
{
- return 6 + 0x3fa - 2;
+ return 6 + 8*getNumInfoRecords();
+ }
+
+ public static final int getNumberOfInfoRecsForStrings(int numStrings) {
+ int infoRecs = (numStrings / DEFAULT_BUCKET_SIZE);
+ if ((numStrings % DEFAULT_BUCKET_SIZE) != 0)
+ infoRecs ++;
+ //Excel seems to max out after 128 info records.
+ //This isnt really documented anywhere...
+ if (infoRecs > MAX_BUCKETS)
+ infoRecs = MAX_BUCKETS;
+ return infoRecs;
+ }
+
+ /** Given a number of strings (in the sst), returns the size of the extsst record*/
+ public static final int getRecordSizeForStrings(int numStrings) {
+ return 4 + 2 + (getNumberOfInfoRecsForStrings(numStrings) * 8);
}
public short getSid()
{
- return this.sid;
+ return sid;
}
+
+ public void setBucketOffsets( int[] bucketAbsoluteOffsets, int[] bucketRelativeOffsets )
+ {
+ this.field_2_sst_info = new ArrayList(bucketAbsoluteOffsets.length);
+ for ( int i = 0; i < bucketAbsoluteOffsets.length; i++ )
+ {
+ ExtSSTInfoSubRecord r = new ExtSSTInfoSubRecord();
+ r.setBucketRecordOffset((short)bucketRelativeOffsets[i]);
+ r.setStreamPos(bucketAbsoluteOffsets[i]);
+ field_2_sst_info.add(r);
+ }
+ }
+
}
diff --git a/src/java/org/apache/poi/hssf/record/ExternSheetRecord.java b/src/java/org/apache/poi/hssf/record/ExternSheetRecord.java
index 761d400522..048fb443ff 100644
--- a/src/java/org/apache/poi/hssf/record/ExternSheetRecord.java
+++ b/src/java/org/apache/poi/hssf/record/ExternSheetRecord.java
@@ -1 +1,230 @@
-/* ==================================================================== * The Apache Software License, Version 1.1 * * Copyright (c) 2003 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Apache" and "Apache Software Foundation" and * "Apache POI" must not be used to endorse or promote products * derived from this software without prior written permission. For * written permission, please contact apache@apache.org. * * 5. Products derived from this software may not be called "Apache", * "Apache POI", nor may "Apache" appear in their name, without * prior written permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see *
* Description: A List of Inndexes to SupBook
* REFERENCE:
* @author Libin Roman (Vista Portal LDT. Developer) * @version 1.0-pre */public class ExternSheetRecord extends Record { public final static short sid = 0x17; private short field_1_number_of_REF_sturcutres; private ArrayList field_2_REF_structures; public ExternSheetRecord() { field_2_REF_structures = new ArrayList(); } /** * Constructs a Extern Sheet record and sets its fields appropriately. * * @param id id must be 0x16 or an exception will be throw upon validation * @param size the size of the data area of the record * @param data data of the record (should not contain sid/len) */ public ExternSheetRecord(short id, short size, byte[] data) { super(id, size, data); } /** * Constructs a Extern Sheet record and sets its fields appropriately. * * @param id id must be 0x16 or an exception will be throw upon validation * @param size the size of the data area of the record * @param data data of the record (should not contain sid/len) * @param offset of the record's data */ public ExternSheetRecord(short id, short size, byte[] data, int offset) { super(id, size, data, offset); } /** * called by constructor, should throw runtime exception in the event of a * record passed with a differing ID. * * @param id alleged id for this record */ protected void validateSid(short id) { if (id != sid) { throw new RecordFormatException("NOT An ExternSheet RECORD"); } } /** * called by the constructor, should set class level fields. Should throw * runtime exception for bad/icomplete data. * * @param data raw data * @param size size of data * @param offset of the record's data (provided a big array of the file) */ protected void fillFields(byte [] data, short size, int offset) { field_2_REF_structures = new ArrayList(); field_1_number_of_REF_sturcutres = LittleEndian.getShort(data, 0 + offset); int pos = 2 + offset; for (int i = 0 ; i < field_1_number_of_REF_sturcutres ; ++i) { ExternSheetSubRecord rec = new ExternSheetSubRecord((short)0, (short)6 , data , pos); pos += 6; field_2_REF_structures.add( rec); } } /** * sets the number of the REF structors , that is in Excel file * @param numStruct number of REF structs */ public void setNumOfREFStructures(short numStruct) { field_1_number_of_REF_sturcutres = numStruct; } /** * return the number of the REF structors , that is in Excel file * @return number of REF structs */ public short getNumOfREFStructures() { return field_1_number_of_REF_sturcutres; } /** * adds REF struct (ExternSheetSubRecord) * @param rec REF struct */ public void addREFRecord(ExternSheetSubRecord rec) { field_2_REF_structures.add(rec); } /** returns the number of REF Records, which is in model * @return number of REF records */ public int getNumOfREFRecords() { return field_2_REF_structures.size(); } /** returns the REF record (ExternSheetSubRecord) * @param elem index to place * @return REF record */ public ExternSheetSubRecord getREFRecordAt(int elem) { ExternSheetSubRecord result = ( ExternSheetSubRecord ) field_2_REF_structures.get(elem); return result; } public String toString() { StringBuffer buffer = new StringBuffer(); buffer.append("[EXTERNSHEET]\n"); buffer.append(" numOfRefs = ").append(getNumOfREFStructures()).append("\n"); for (int k=0; k < this.getNumOfREFRecords(); k++) { buffer.append("refrec #").append(k).append('\n'); buffer.append(getREFRecordAt(k).toString()); buffer.append("----refrec #").append(k).append('\n'); } buffer.append("[/EXTERNSHEET]\n"); return buffer.toString(); } /** * called by the class that is responsible for writing this sucker. * Subclasses should implement this so that their data is passed back in a * byte array. * * @param offset to begin writing at * @param data byte array containing instance data * @return number of bytes written */ public int serialize(int offset, byte [] data) { LittleEndian.putShort(data, 0 + offset, sid); LittleEndian.putShort(data, 2 + offset,(short)(2 + (getNumOfREFRecords() *6))); LittleEndian.putShort(data, 4 + offset, getNumOfREFStructures()); int pos = 6 ; for (int k = 0; k < getNumOfREFRecords(); k++) { ExternSheetSubRecord record = getREFRecordAt(k); System.arraycopy(record.serialize(), 0, data, pos + offset, 6); pos +=6; } return getRecordSize(); } public int getRecordSize() { return 4 + 2 + getNumOfREFRecords() * 6; } /** * return the non static version of the id for this record. */ public short getSid() { return this.sid; }}
\ No newline at end of file
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2002 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache POI" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache POI", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ *
+ * Description: A List of Inndexes to SupBook
+ * REFERENCE:
+ * @author Libin Roman (Vista Portal LDT. Developer) + * @version 1.0-pre + */ + +public class ExternSheetRecord extends Record { + public final static short sid = 0x17; + private short field_1_number_of_REF_sturcutres; + private ArrayList field_2_REF_structures; + + public ExternSheetRecord() { + field_2_REF_structures = new ArrayList(); + } + + /** + * Constructs a Extern Sheet record and sets its fields appropriately. + * + * @param id id must be 0x16 or an exception will be throw upon validation + * @param size the size of the data area of the record + * @param data data of the record (should not contain sid/len) + */ + + public ExternSheetRecord(short id, short size, byte[] data) { + super(id, size, data); + } + + /** + * Constructs a Extern Sheet record and sets its fields appropriately. + * + * @param id id must be 0x16 or an exception will be throw upon validation + * @param size the size of the data area of the record + * @param data data of the record (should not contain sid/len) + * @param offset of the record's data + */ + public ExternSheetRecord(short id, short size, byte[] data, int offset) { + super(id, size, data, offset); + } + + /** + * called by constructor, should throw runtime exception in the event of a + * record passed with a differing ID. + * + * @param id alleged id for this record + */ + protected void validateSid(short id) { + if (id != sid) { + throw new RecordFormatException("NOT An ExternSheet RECORD"); + } + } + + /** + * called by the constructor, should set class level fields. Should throw + * runtime exception for bad/icomplete data. + * + * @param data raw data + * @param size size of data + * @param offset of the record's data (provided a big array of the file) + */ + protected void fillFields(byte [] data, short size, int offset) { + field_2_REF_structures = new ArrayList(); + + field_1_number_of_REF_sturcutres = LittleEndian.getShort(data, 0 + offset); + + int pos = 2 + offset; + for (int i = 0 ; i < field_1_number_of_REF_sturcutres ; ++i) { + ExternSheetSubRecord rec = new ExternSheetSubRecord((short)0, (short)6 , data , pos); + + pos += 6; + + field_2_REF_structures.add( rec); + } + } + + /** + * sets the number of the REF structors , that is in Excel file + * @param numStruct number of REF structs + */ + public void setNumOfREFStructures(short numStruct) { + field_1_number_of_REF_sturcutres = numStruct; + } + + /** + * return the number of the REF structors , that is in Excel file + * @return number of REF structs + */ + public short getNumOfREFStructures() { + return field_1_number_of_REF_sturcutres; + } + + /** + * adds REF struct (ExternSheetSubRecord) + * @param rec REF struct + */ + public void addREFRecord(ExternSheetSubRecord rec) { + field_2_REF_structures.add(rec); + } + + /** returns the number of REF Records, which is in model + * @return number of REF records + */ + public int getNumOfREFRecords() { + return field_2_REF_structures.size(); + } + + /** returns the REF record (ExternSheetSubRecord) + * @param elem index to place + * @return REF record + */ + public ExternSheetSubRecord getREFRecordAt(int elem) { + ExternSheetSubRecord result = ( ExternSheetSubRecord ) field_2_REF_structures.get(elem); + + return result; + } + + public String toString() { + StringBuffer buffer = new StringBuffer(); + + buffer.append("[EXTERNSHEET]\n"); + buffer.append(" numOfRefs = ").append(getNumOfREFStructures()).append("\n"); + for (int k=0; k < this.getNumOfREFRecords(); k++) { + buffer.append("refrec #").append(k).append('\n'); + buffer.append(getREFRecordAt(k).toString()); + buffer.append("----refrec #").append(k).append('\n'); + } + buffer.append("[/EXTERNSHEET]\n"); + + + return buffer.toString(); + } + + /** + * called by the class that is responsible for writing this sucker. + * Subclasses should implement this so that their data is passed back in a + * byte array. + * + * @param offset to begin writing at + * @param data byte array containing instance data + * @return number of bytes written + */ + public int serialize(int offset, byte [] data) { + LittleEndian.putShort(data, 0 + offset, sid); + LittleEndian.putShort(data, 2 + offset,(short)(2 + (getNumOfREFRecords() *6))); + + LittleEndian.putShort(data, 4 + offset, getNumOfREFStructures()); + + int pos = 6 ; + + for (int k = 0; k < getNumOfREFRecords(); k++) { + ExternSheetSubRecord record = getREFRecordAt(k); + System.arraycopy(record.serialize(), 0, data, pos + offset, 6); + + pos +=6; + } + return getRecordSize(); + } + + public int getRecordSize() { + return 4 + 2 + getNumOfREFRecords() * 6; + } + + /** + * return the non static version of the id for this record. + */ + public short getSid() { + return this.sid; + } +} diff --git a/src/java/org/apache/poi/hssf/record/FormulaRecord.java b/src/java/org/apache/poi/hssf/record/FormulaRecord.java index ad926be474..050558739b 100644 --- a/src/java/org/apache/poi/hssf/record/FormulaRecord.java +++ b/src/java/org/apache/poi/hssf/record/FormulaRecord.java @@ -557,8 +557,13 @@ public class FormulaRecord .append("\n"); buffer.append(" .xf = ") .append(Integer.toHexString(getXFIndex())).append("\n"); - buffer.append(" .value = ").append(getValue()) - .append("\n"); + if (Double.isNaN(this.getValue()) && value_data != null) + buffer.append(" .value (NaN) = ") + .append(org.apache.poi.util.HexDump.dump(value_data,0,0)) + .append("\n"); + else + buffer.append(" .value = ").append(getValue()) + .append("\n"); buffer.append(" .options = ").append(getOptions()) .append("\n"); buffer.append(" .zero = ").append(field_6_zero) @@ -607,9 +612,10 @@ public 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(); - rec.field_8_parsed_expr.set(i, ptg); + Ptg ptg = (Ptg)((Ptg)field_8_parsed_expr.get(i)).clone(); + rec.field_8_parsed_expr.add(i, ptg); } + rec.value_data = value_data; rec.all_data = all_data; return rec; } diff --git a/src/java/org/apache/poi/hssf/record/LabelRecord.java b/src/java/org/apache/poi/hssf/record/LabelRecord.java index 558584ba95..8755a062ab 100644 --- a/src/java/org/apache/poi/hssf/record/LabelRecord.java +++ b/src/java/org/apache/poi/hssf/record/LabelRecord.java @@ -150,15 +150,16 @@ public class LabelRecord field_3_xf_index = LittleEndian.getShort(data, 4 + offset); field_4_string_len = LittleEndian.getShort(data, 6 + offset); field_5_unicode_flag = data[ 8 + offset ]; - if (isUnCompressedUnicode()) - { - field_6_value = StringUtil.getFromUnicode(data, 8 + offset, + if (field_4_string_len > 0) { + if (isUnCompressedUnicode()) { + field_6_value = StringUtil.getFromUnicode(data, 9 + offset, field_4_string_len); } - else - { - field_6_value = StringUtil.getFromCompressedUnicode(data, 9 + offset, getStringLength()); + else { + field_6_value = StringUtil.getFromCompressedUnicode(data, 9 + offset, + getStringLength()); } + } else field_6_value = null; } /* READ ONLY ACCESS... THIS IS FOR COMPATIBILITY ONLY...USE LABELSST! @@ -237,6 +238,27 @@ public class LabelRecord return this.sid; } + public String toString() + { + StringBuffer buffer = new StringBuffer(); + buffer.append("[LABEL]\n"); + buffer.append(" .row = ") + .append(Integer.toHexString(getRow())).append("\n"); + buffer.append(" .column = ") + .append(Integer.toHexString(getColumn())).append("\n"); + buffer.append(" .xfindex = ") + .append(Integer.toHexString(getXFIndex())).append("\n"); + buffer.append(" .string_len = ") + .append(Integer.toHexString(field_4_string_len)).append("\n"); + buffer.append(" .unicode_flag = ") + .append(Integer.toHexString(field_5_unicode_flag)).append("\n"); + buffer.append(" .value = ") + .append(getValue()).append("\n"); + buffer.append("[/LABEL]\n"); + return buffer.toString(); + } + + public boolean isBefore(CellValueRecordInterface i) { if (this.getRow() > i.getRow()) diff --git a/src/java/org/apache/poi/hssf/record/NameRecord.java b/src/java/org/apache/poi/hssf/record/NameRecord.java index 09bf2a416d..b91c829b87 100644 --- a/src/java/org/apache/poi/hssf/record/NameRecord.java +++ b/src/java/org/apache/poi/hssf/record/NameRecord.java @@ -58,11 +58,11 @@ package org.apache.poi.hssf.record; import java.util.List; import java.util.Stack; +import org.apache.poi.hssf.model.Workbook; import org.apache.poi.hssf.record.formula.Area3DPtg; import org.apache.poi.hssf.record.formula.Ptg; import org.apache.poi.hssf.record.formula.Ref3DPtg; import org.apache.poi.hssf.util.RangeAddress; -import org.apache.poi.hssf.util.SheetReferences; import org.apache.poi.util.HexDump; import org.apache.poi.util.LittleEndian; import org.apache.poi.util.StringUtil; @@ -127,6 +127,14 @@ public class NameRecord extends Record { */ public final static byte BUILTIN_SHEET_TITLE = (byte)12; + public static final short OPT_HIDDEN_NAME = (short) 0x0001; + public static final short OPT_FUNCTION_NAME = (short) 0x0002; + public static final short OPT_COMMAND_NAME = (short) 0x0004; + public static final short OPT_MACRO = (short) 0x0008; + public static final short OPT_COMPLEX = (short) 0x0010; + public static final short OPT_BUILTIN = (short) 0x0020; + public static final short OPT_BINDATA = (short) 0x1000; + private short field_1_option_flag; private byte field_2_keyboard_shortcut; @@ -192,7 +200,7 @@ public class NameRecord extends Record { { this(); this.field_12_builtIn_name = builtin; - this.setOptionFlag((short)(this.getOptionFlag() | (short)0x20)); + this.setOptionFlag((short)(this.getOptionFlag() | OPT_BUILTIN)); this.setNameTextLength((byte)1); this.setEqualsToIndexToSheet(index); //the extern sheets are set through references @@ -252,13 +260,22 @@ public class NameRecord extends Record { /** * Convenience method to retrieve the index the name refers to. - * @see getEqualsToIndexToSheet() + * @see #getEqualsToIndexToSheet() * @return short */ public short getIndexToSheet() { return getEqualsToIndexToSheet(); } + /** + * @return function group + * @see FnGroupCountRecord + */ + public byte getFnGroup() { + int masked = field_1_option_flag & 0x0fc0; + return (byte) (masked >> 4); + } + public void setEqualsToIndexToSheet(short value) { field_6_equals_to_index_to_sheet = value; @@ -409,11 +426,47 @@ public class NameRecord extends Record { return field_11_compressed_unicode_flag; } + /** + * @return true if name is hidden + */ + public boolean isHiddenName() { + return (field_1_option_flag & OPT_HIDDEN_NAME) != 0; + } + + /** + * @return true if name is a function + */ + public boolean isFunctionName() { + return (field_1_option_flag & OPT_FUNCTION_NAME) != 0; + } + + /** + * @return true if name is a command + */ + public boolean isCommandName() { + return (field_1_option_flag & OPT_COMMAND_NAME) != 0; + } + + /** + * @return true if function macro or command macro + */ + public boolean isMacro() { + return (field_1_option_flag & OPT_MACRO) != 0; + } + + /** + * @return true if array formula or user defined + */ + public boolean isComplexFunction() { + return (field_1_option_flag & OPT_COMPLEX) != 0; + } + + /**Convenience Function to determine if the name is a built-in name */ public boolean isBuiltInName() { - return ((this.getOptionFlag() & (short)0x20) != 0); + return ((this.getOptionFlag() & OPT_BUILTIN) != 0); } @@ -511,7 +564,7 @@ public class NameRecord extends Record { data[18 + offset] = getCompressedUnicodeFlag(); /* temp: gjs - if ( ( field_1_option_flag & (short) 0x20 ) != 0 ) + if (isBuiltInName()) { LittleEndian.putShort( data, 2 + offset, (short) ( 16 + field_13_raw_name_definition.length ) ); @@ -647,16 +700,16 @@ public class NameRecord extends Record { /** gets the reference , the area only (range) * @return area reference */ - public String getAreaReference(SheetReferences refs){ + public String getAreaReference(Workbook book){ if (field_13_name_definition == null) return "#REF!"; Ptg ptg = (Ptg) field_13_name_definition.peek(); String result = ""; if (ptg.getClass() == Area3DPtg.class){ - result = ptg.toFormulaString(refs); + result = ptg.toFormulaString(book); } else if (ptg.getClass() == Ref3DPtg.class){ - result = ptg.toFormulaString(refs); + result = ptg.toFormulaString(book); } return result; @@ -727,7 +780,7 @@ public class NameRecord extends Record { /* temp: gjs - if ( ( field_1_option_flag & (short)0x20 ) != 0 ) { + if (isBuiltInName()) { // DEBUG // System.out.println( "Built-in name" ); @@ -794,6 +847,8 @@ public class NameRecord extends Record { pos += ptg.getSize(); sizeCounter += ptg.getSize(); stack.push(ptg); + field_13_raw_name_definition=new byte[size]; + System.arraycopy(data,offset,field_13_raw_name_definition,0,size); } } catch (java.lang.UnsupportedOperationException uoe) { System.err.println("[WARNING] Unknown Ptg " @@ -880,7 +935,7 @@ public class NameRecord extends Record { .append("\n"); buffer.append(" .unused = ").append( field_5_index_to_sheet ) .append("\n"); - buffer.append(" .( 0 = Global name, otherwise index to sheet (one-based) ) = ").append( field_6_equals_to_index_to_sheet ) + buffer.append(" .index to sheet (1-based, 0=Global) = ").append( field_6_equals_to_index_to_sheet ) .append("\n"); buffer.append(" .Length of menu text (character count) = ").append( field_7_length_custom_menu ) .append("\n"); @@ -906,6 +961,7 @@ public class NameRecord extends Record { .append("\n"); buffer.append(" .Status bar text (Unicode string without length field) = ").append( field_17_status_bar_text ) .append("\n"); + buffer.append(org.apache.poi.util.HexDump.dump(this.field_13_raw_name_definition,0,0)); buffer.append("[/NAME]\n"); return buffer.toString(); diff --git a/src/java/org/apache/poi/hssf/record/PasswordRecord.java b/src/java/org/apache/poi/hssf/record/PasswordRecord.java index 9feb6a2cbd..ba9cbfc5f0 100644 --- a/src/java/org/apache/poi/hssf/record/PasswordRecord.java +++ b/src/java/org/apache/poi/hssf/record/PasswordRecord.java @@ -166,4 +166,14 @@ public class PasswordRecord { return this.sid; } + + /** + * Clone this record. + */ + public Object clone() { + PasswordRecord clone = new PasswordRecord(); + clone.setPassword(field_1_password); + return clone; + } + } diff --git a/src/java/org/apache/poi/hssf/record/ProtectRecord.java b/src/java/org/apache/poi/hssf/record/ProtectRecord.java index 66978f9bf4..a633756d51 100644 --- a/src/java/org/apache/poi/hssf/record/ProtectRecord.java +++ b/src/java/org/apache/poi/hssf/record/ProtectRecord.java @@ -139,9 +139,9 @@ public class ProtectRecord * @return whether to protect the sheet or not */ - public short getProtect() + public boolean getProtect() { - return field_1_protect; + return (field_1_protect == 1); } public String toString() @@ -149,8 +149,8 @@ public class ProtectRecord StringBuffer buffer = new StringBuffer(); buffer.append("[PROTECT]\n"); - buffer.append(" .protected = ") - .append(Integer.toHexString(getProtect())).append("\n"); + buffer.append(" .protect = ").append(getProtect()) + .append("\n"); buffer.append("[/PROTECT]\n"); return buffer.toString(); } @@ -160,7 +160,7 @@ public class ProtectRecord LittleEndian.putShort(data, 0 + offset, sid); LittleEndian.putShort(data, 2 + offset, (( short ) 0x02)); // 2 bytes (6 total) - LittleEndian.putShort(data, 4 + offset, getProtect()); + LittleEndian.putShort(data, 4 + offset, field_1_protect); return getRecordSize(); } diff --git a/src/java/org/apache/poi/hssf/record/ProtectionRev4Record.java b/src/java/org/apache/poi/hssf/record/ProtectionRev4Record.java index e385a4adfc..be64938126 100644 --- a/src/java/org/apache/poi/hssf/record/ProtectionRev4Record.java +++ b/src/java/org/apache/poi/hssf/record/ProtectionRev4Record.java @@ -139,18 +139,18 @@ public class ProtectionRev4Record * @return whether to protect the workbook or not */ - public short getProtect() - { - return field_1_protect; - } + public boolean getProtect() + { + return (field_1_protect == 1); + } public String toString() { StringBuffer buffer = new StringBuffer(); buffer.append("[PROT4REV]\n"); - buffer.append(" .rowheight = ") - .append(Integer.toHexString(getProtect())).append("\n"); + buffer.append(" .protect = ").append(getProtect()) + .append("\n"); buffer.append("[/PROT4REV]\n"); return buffer.toString(); } @@ -160,7 +160,7 @@ public class ProtectionRev4Record LittleEndian.putShort(data, 0 + offset, sid); LittleEndian.putShort(data, 2 + offset, (( short ) 0x02)); // 2 bytes (6 total) - LittleEndian.putShort(data, 4 + offset, getProtect()); + LittleEndian.putShort(data, 4 + offset, field_1_protect); return getRecordSize(); } diff --git a/src/java/org/apache/poi/hssf/record/Record.java b/src/java/org/apache/poi/hssf/record/Record.java index 7783026054..bd4e73789f 100644 --- a/src/java/org/apache/poi/hssf/record/Record.java +++ b/src/java/org/apache/poi/hssf/record/Record.java @@ -70,16 +70,6 @@ package org.apache.poi.hssf.record; public abstract class Record { - /** - * The static ID, subclasses should override this value with the id for the - * record type they handle. - */ - - public short sid = 0; - private short id = 0; - private short size = 0; - private byte[] data = null; - /** * instantiates a blank record strictly for ID matching */ @@ -98,9 +88,6 @@ public abstract class Record public Record(short id, short size, byte [] data) { - this.id = id; - this.size = size; - this.data = data; validateSid(id); fillFields(data, size); } @@ -115,9 +102,6 @@ public abstract class Record public Record(short id, short size, byte [] data, int offset) { - this.id = id; - this.size = size; - this.data = data; validateSid(id); fillFields(data, size, offset); } diff --git a/src/java/org/apache/poi/hssf/record/RecordProcessor.java b/src/java/org/apache/poi/hssf/record/RecordProcessor.java index c8d659c259..ba86f678f8 100644 --- a/src/java/org/apache/poi/hssf/record/RecordProcessor.java +++ b/src/java/org/apache/poi/hssf/record/RecordProcessor.java @@ -156,5 +156,10 @@ class RecordProcessor recordOffset += amount; available -= amount; } + + public int getRecordOffset() + { + return recordOffset; + } } diff --git a/src/java/org/apache/poi/hssf/record/SSTDeserializer.java b/src/java/org/apache/poi/hssf/record/SSTDeserializer.java index dcf4e50b93..40fd4b02e2 100644 --- a/src/java/org/apache/poi/hssf/record/SSTDeserializer.java +++ b/src/java/org/apache/poi/hssf/record/SSTDeserializer.java @@ -62,13 +62,14 @@ import org.apache.poi.util.LittleEndianConsts; * Handles the task of deserializing a SST string. The two main entry points are * * @author Glen Stampoultzis (glens at apache.org) + * @author Jason Height (jheight at apache.org) */ class SSTDeserializer { private BinaryTree strings; - /** this is the number of characters we expect in the first sub-record in a subsequent continuation record */ - private int continuationExpectedChars; + /** this is the number of characters that have been read prior to the continuation */ + private int continuationReadChars; /** this is the string we were working on before hitting the end of the current record. This string is NOT finished. */ private String unfinishedString; /** this is true if the string uses wide characters */ @@ -82,6 +83,7 @@ class SSTDeserializer /** Number of characters in current string */ private int charCount; private int extensionLength; + private int continueSkipBytes = 0; public SSTDeserializer( BinaryTree strings ) @@ -93,13 +95,14 @@ class SSTDeserializer private void initVars() { runCount = 0; - continuationExpectedChars = 0; + continuationReadChars = 0; unfinishedString = ""; // bytesInCurrentSegment = 0; // stringDataOffset = 0; wideChar = false; richText = false; extendedText = false; + continueSkipBytes = 0; } /** @@ -107,14 +110,15 @@ class SSTDeserializer * strings may span across multiple continuations. Read the SST record * carefully before beginning to hack. */ - public void manufactureStrings( final byte[] data, final int initialOffset, short dataSize ) + public void manufactureStrings( final byte[] data, final int initialOffset) { initVars(); int offset = initialOffset; - while ( ( offset - initialOffset ) < dataSize ) + final int dataSize = data.length; + while ( offset < dataSize ) { - int remaining = dataSize - offset + initialOffset; + int remaining = dataSize - offset; if ( ( remaining > 0 ) && ( remaining < LittleEndianConsts.SHORT_SIZE ) ) { @@ -122,26 +126,31 @@ class SSTDeserializer } if ( remaining == LittleEndianConsts.SHORT_SIZE ) { - setContinuationExpectedChars( LittleEndian.getUShort( data, offset ) ); + //JMH Dont know about this + setContinuationCharsRead( 0 );//LittleEndian.getUShort( data, offset ) ); unfinishedString = ""; break; } charCount = LittleEndian.getUShort( data, offset ); + int charsRead = charCount; readStringHeader( data, offset ); boolean stringContinuesOverContinuation = remaining < totalStringSize(); if ( stringContinuesOverContinuation ) { - int remainingBytes = ( initialOffset + dataSize ) - offset - stringHeaderOverhead(); - setContinuationExpectedChars( charCount - calculateCharCount( remainingBytes ) ); - charCount -= getContinuationExpectedChars(); + int remainingBytes = dataSize - offset - stringHeaderOverhead(); + //Only read the size of the string or whatever is left before the + //continuation + charsRead = Math.min(charsRead, calculateCharCount( remainingBytes )); + setContinuationCharsRead( charsRead ); + if (charsRead == charCount) { + //Since all of the characters will have been read, but the entire string (including formatting runs etc) + //hasnt, Compute the number of bytes to skip when the continue record starts + continueSkipBytes = offsetForContinuedRecord(0) - (remainingBytes - calculateByteCount(charsRead)); + } } - else - { - setContinuationExpectedChars( 0 ); - } - processString( data, offset, charCount ); + processString( data, offset, charsRead ); offset += totalStringSize(); - if ( getContinuationExpectedChars() != 0 ) + if ( stringContinuesOverContinuation ) { break; } @@ -222,6 +231,7 @@ class SSTDeserializer UnicodeString string = new UnicodeString( UnicodeString.sid, (short) unicodeStringBuffer.length, unicodeStringBuffer ); + setContinuationCharsRead( calculateCharCount(bytesRead)); if ( isStringFinished() ) { @@ -238,7 +248,7 @@ class SSTDeserializer private boolean isStringFinished() { - return getContinuationExpectedChars() == 0; + return getContinuationCharsRead() == charCount; } /** @@ -301,8 +311,9 @@ class SSTDeserializer { if ( isStringFinished() ) { + final int offset = continueSkipBytes; initVars(); - manufactureStrings( record, 0, (short) record.length ); + manufactureStrings( record, offset); } else { @@ -330,13 +341,12 @@ class SSTDeserializer */ private void readStringRemainder( final byte[] record ) { - int stringRemainderSizeInBytes = calculateByteCount( getContinuationExpectedChars() ); -// stringDataOffset = LittleEndianConsts.BYTE_SIZE; + int stringRemainderSizeInBytes = calculateByteCount( charCount-getContinuationCharsRead() ); byte[] unicodeStringData = new byte[SSTRecord.STRING_MINIMAL_OVERHEAD - + calculateByteCount( getContinuationExpectedChars() )]; + + stringRemainderSizeInBytes]; // write the string length - LittleEndian.putShort( unicodeStringData, 0, (short) getContinuationExpectedChars() ); + LittleEndian.putShort( unicodeStringData, 0, (short) (charCount-getContinuationCharsRead()) ); // write the options flag unicodeStringData[LittleEndianConsts.SHORT_SIZE] = createOptionByte( wideChar, richText, extendedText ); @@ -345,7 +355,7 @@ class SSTDeserializer // past all the overhead of the str_data array arraycopy( record, LittleEndianConsts.BYTE_SIZE, unicodeStringData, SSTRecord.STRING_MINIMAL_OVERHEAD, - unicodeStringData.length - SSTRecord.STRING_MINIMAL_OVERHEAD ); + stringRemainderSizeInBytes ); // use special constructor to create the final string UnicodeString string = new UnicodeString( UnicodeString.sid, @@ -356,7 +366,7 @@ class SSTDeserializer addToStringTable( strings, integer, string ); int newOffset = offsetForContinuedRecord( stringRemainderSizeInBytes ); - manufactureStrings( record, newOffset, (short) ( record.length - newOffset ) ); + manufactureStrings( record, newOffset); } /** @@ -388,8 +398,12 @@ class SSTDeserializer private int offsetForContinuedRecord( int stringRemainderSizeInBytes ) { - return stringRemainderSizeInBytes + LittleEndianConsts.BYTE_SIZE - + runCount * LittleEndianConsts.INT_SIZE + extensionLength; + int offset = stringRemainderSizeInBytes + runCount * LittleEndianConsts.INT_SIZE + extensionLength; + if (stringRemainderSizeInBytes != 0) + //If a portion of the string remains then the wideChar options byte is repeated, + //so need to skip this. + offset += + LittleEndianConsts.BYTE_SIZE; + return offset; } private byte createOptionByte( boolean wideChar, boolean richText, boolean farEast ) @@ -409,17 +423,22 @@ class SSTDeserializer int dataLengthInBytes = record.length - LittleEndianConsts.BYTE_SIZE; byte[] unicodeStringData = new byte[record.length + LittleEndianConsts.SHORT_SIZE]; - LittleEndian.putShort( unicodeStringData, (byte) 0, (short) calculateCharCount( dataLengthInBytes ) ); + int charsRead = calculateCharCount( dataLengthInBytes ); + LittleEndian.putShort( unicodeStringData, (byte) 0, (short) charsRead ); arraycopy( record, 0, unicodeStringData, LittleEndianConsts.SHORT_SIZE, record.length ); - UnicodeString ucs = new UnicodeString( UnicodeString.sid, (short) unicodeStringData.length, unicodeStringData ); + UnicodeString ucs = new UnicodeString( UnicodeString.sid, (short) unicodeStringData.length, unicodeStringData, unfinishedString); - unfinishedString = unfinishedString + ucs.getString(); - setContinuationExpectedChars( getContinuationExpectedChars() - calculateCharCount( dataLengthInBytes ) ); + unfinishedString = ucs.getString(); + setContinuationCharsRead( getContinuationCharsRead() + charsRead ); + if (getContinuationCharsRead() == charCount) { + Integer integer = new Integer( strings.size() ); + addToStringTable( strings, integer, ucs ); + } } private boolean stringSpansContinuation( int continuationSizeInBytes ) { - return calculateByteCount( getContinuationExpectedChars() ) > continuationSizeInBytes; + return calculateByteCount( charCount - getContinuationCharsRead() ) > continuationSizeInBytes; } /** @@ -427,14 +446,14 @@ class SSTDeserializer * sub-record in a subsequent continuation record */ - int getContinuationExpectedChars() + int getContinuationCharsRead() { - return continuationExpectedChars; + return continuationReadChars; } - private void setContinuationExpectedChars( final int count ) + private void setContinuationCharsRead( final int count ) { - continuationExpectedChars = count; + continuationReadChars = count; } private int calculateByteCount( final int character_count ) diff --git a/src/java/org/apache/poi/hssf/record/SSTRecord.java b/src/java/org/apache/poi/hssf/record/SSTRecord.java index a3f0807021..7f703e7cd2 100644 --- a/src/java/org/apache/poi/hssf/record/SSTRecord.java +++ b/src/java/org/apache/poi/hssf/record/SSTRecord.java @@ -60,7 +60,6 @@ import org.apache.poi.util.LittleEndianConsts; import java.util.Iterator; import java.util.List; -import java.util.ArrayList; /** * Title: Static String Table Record @@ -73,7 +72,7 @@ import java.util.ArrayList; * @author Andrew C. Oliver (acoliver at apache dot org) * @author Marc Johnson (mjohnson at apache dot org) * @author Glen Stampoultzis (glens at apache.org) - * @version 2.0-pre + * * @see org.apache.poi.hssf.record.LabelSSTRecord * @see org.apache.poi.hssf.record.ContinueRecord */ @@ -112,10 +111,14 @@ public class SSTRecord private List _record_lengths = null; private SSTDeserializer deserializer; + /** Offsets from the beginning of the SST record (even across continuations) */ + int[] bucketAbsoluteOffsets; + /** Offsets relative the start of the current SST or continue record */ + int[] bucketRelativeOffsets; + /** * default constructor */ - public SSTRecord() { field_1_num_strings = 0; @@ -220,7 +223,7 @@ public class SSTRecord field_1_num_strings++; String str = ( string == null ) ? "" : string; - int rval = -1; + int rval; UnicodeString ucs = new UnicodeString(); ucs.setString( str ); @@ -334,7 +337,7 @@ public class SSTRecord for ( int k = 0; k < field_3_strings.size(); k++ ) { buffer.append( " .string_" + k + " = " ) - .append( ( (UnicodeString) field_3_strings + .append( ( field_3_strings .get( new Integer( k ) ) ).toString() ).append( "\n" ); } buffer.append( "[/SST]\n" ); @@ -394,7 +397,7 @@ public class SSTRecord * The data consists of sets of string data. This string data is * arranged as follows: *
- *
+ *
*
+ *
* short string_length; // length of string data
* byte string_flag; // flag specifying special string
* // handling
@@ -407,7 +410,7 @@ public class SSTRecord
* // array is run_count)
* byte[] extension; // optional extension (length of array
* // is extend_length)
- *
* The string_flag is bit mapped as follows: *
@@ -479,7 +482,7 @@ public class SSTRecord field_2_num_unique_strings = LittleEndian.getInt( data, 4 + offset ); field_3_strings = new BinaryTree(); deserializer = new SSTDeserializer(field_3_strings); - deserializer.manufactureStrings( data, 8 + offset, (short)(size - 8) ); + deserializer.manufactureStrings( data, 8 + offset); } @@ -507,14 +510,22 @@ public class SSTRecord * Subclasses should implement this so that their data is passed back in a * byte array. * - * @return byte array containing instance data + * @return size */ public int serialize( int offset, byte[] data ) { SSTSerializer serializer = new SSTSerializer( _record_lengths, field_3_strings, getNumStrings(), getNumUniqueStrings() ); - return serializer.serialize( getRecordSize(), offset, data ); + int bytes = serializer.serialize( getRecordSize(), offset, data ); + bucketAbsoluteOffsets = serializer.getBucketAbsoluteOffsets(); + bucketRelativeOffsets = serializer.getBucketRelativeOffsets(); +// for ( int i = 0; i < bucketAbsoluteOffsets.length; i++ ) +// { +// System.out.println( "bucketAbsoluteOffset = " + bucketAbsoluteOffsets[i] ); +// System.out.println( "bucketRelativeOffset = " + bucketRelativeOffsets[i] ); +// } + return bytes; } @@ -538,6 +549,45 @@ public class SSTRecord { deserializer.processContinueRecord( record ); } + + /** + * Creates an extended string record based on the current contents of + * the current SST record. The offset within the stream to the SST record + * is required because the extended string record points directly to the + * strings in the SST record. + *
+ * NOTE: THIS FUNCTION MUST ONLY BE CALLED AFTER THE SST RECORD HAS BEEN + * SERIALIZED. + * + * @param sstOffset The offset in the stream to the start of the + * SST record. + * @return The new SST record. + */ + public ExtSSTRecord createExtSSTRecord(int sstOffset) + { + if (bucketAbsoluteOffsets == null || bucketAbsoluteOffsets == null) + throw new IllegalStateException("SST record has not yet been serialized."); + + ExtSSTRecord extSST = new ExtSSTRecord(); + extSST.setNumStringsPerBucket((short)8); + int[] absoluteOffsets = (int[]) bucketAbsoluteOffsets.clone(); + int[] relativeOffsets = (int[]) bucketRelativeOffsets.clone(); + for ( int i = 0; i < absoluteOffsets.length; i++ ) + absoluteOffsets[i] += sstOffset; + extSST.setBucketOffsets(absoluteOffsets, relativeOffsets); + return extSST; + } + + /** + * Calculates the size in bytes of the EXTSST record as it would be if the + * record was serialized. + * + * @return The size of the ExtSST record in bytes. + */ + public int calcExtSSTRecordSize() + { + return ExtSSTRecord.getRecordSizeForStrings(field_3_strings.size()); + } } diff --git a/src/java/org/apache/poi/hssf/record/SSTRecordSizeCalculator.java b/src/java/org/apache/poi/hssf/record/SSTRecordSizeCalculator.java index fbdfba50f3..15a52f9807 100644 --- a/src/java/org/apache/poi/hssf/record/SSTRecordSizeCalculator.java +++ b/src/java/org/apache/poi/hssf/record/SSTRecordSizeCalculator.java @@ -61,7 +61,9 @@ import java.util.List; import java.util.Map; /** - * Used to calculate the record sizes for a particular record. + * Used to calculate the record sizes for a particular record. This kind of + * sucks because it's similar to the SST serialization code. In general + * the SST serialization code needs to be rewritten. * * @author Glen Stampoultzis (glens at apache.org) */ diff --git a/src/java/org/apache/poi/hssf/record/SSTSerializer.java b/src/java/org/apache/poi/hssf/record/SSTSerializer.java index 8239eeb8b4..f4538bb704 100644 --- a/src/java/org/apache/poi/hssf/record/SSTSerializer.java +++ b/src/java/org/apache/poi/hssf/record/SSTSerializer.java @@ -77,6 +77,12 @@ class SSTSerializer private int numUniqueStrings; private SSTRecordHeader sstRecordHeader; + /** Offsets from the beginning of the SST record (even across continuations) */ + int[] bucketAbsoluteOffsets; + /** Offsets relative the start of the current SST or continue record */ + int[] bucketRelativeOffsets; + int startOfSST, startOfRecord; + public SSTSerializer( List recordLengths, BinaryTree strings, int numStrings, int numUniqueStrings ) { this.recordLengths = recordLengths; @@ -84,6 +90,10 @@ class SSTSerializer this.numStrings = numStrings; this.numUniqueStrings = numUniqueStrings; this.sstRecordHeader = new SSTRecordHeader( numStrings, numUniqueStrings ); + + int infoRecs = ExtSSTRecord.getNumberOfInfoRecsForStrings(strings.size()); + this.bucketAbsoluteOffsets = new int[infoRecs]; + this.bucketRelativeOffsets = new int[infoRecs]; } /** @@ -133,7 +143,6 @@ class SSTSerializer /** * This case is chosen when an SST record does not span over to a continue record. - * */ private void serializeSingleSSTRecord( byte[] data, int offset, int record_length_index ) { @@ -144,6 +153,15 @@ class SSTSerializer for ( int k = 0; k < strings.size(); k++ ) { + if (k % ExtSSTRecord.DEFAULT_BUCKET_SIZE == 0) + { + int index = k/ExtSSTRecord.DEFAULT_BUCKET_SIZE; + if (index < ExtSSTRecord.MAX_BUCKETS) { + //Excel only indexes the first 128 buckets. + bucketAbsoluteOffsets[index] = pos; + bucketRelativeOffsets[index] = pos; + } + } System.arraycopy( getUnicodeString( k ).serialize(), 0, data, pos + offset, getUnicodeString( k ).getRecordSize() ); pos += getUnicodeString( k ).getRecordSize(); } @@ -157,6 +175,8 @@ class SSTSerializer private void serializeLargeRecord( int record_size, int record_length_index, byte[] buffer, int offset ) { + startOfSST = offset; + byte[] stringReminant = null; int stringIndex = 0; boolean lastneedcontinue = false; @@ -170,6 +190,7 @@ class SSTSerializer recordLength, numStrings, numUniqueStrings ); // write the appropriate header + startOfRecord = offset + totalWritten; recordProcessor.writeRecordHeader( offset, totalWritten, recordLength, first_record ); first_record = false; @@ -189,6 +210,17 @@ class SSTSerializer { UnicodeString unistr = getUnicodeString( stringIndex ); + if (stringIndex % ExtSSTRecord.DEFAULT_BUCKET_SIZE == 0) + { + int index = stringIndex / ExtSSTRecord.DEFAULT_BUCKET_SIZE; + if (index < ExtSSTRecord.MAX_BUCKETS) { + bucketAbsoluteOffsets[index] = offset + totalWritten + + recordProcessor.getRecordOffset() - startOfSST; + bucketRelativeOffsets[index] = offset + totalWritten + + recordProcessor.getRecordOffset() - startOfRecord; + } + } + if ( unistr.getRecordSize() <= recordProcessor.getAvailable() ) { recordProcessor.writeWholeString( unistr, offset, totalWritten ); @@ -235,4 +267,14 @@ class SSTSerializer { return recordLengths; } + + public int[] getBucketAbsoluteOffsets() + { + return bucketAbsoluteOffsets; + } + + public int[] getBucketRelativeOffsets() + { + return bucketRelativeOffsets; + } } diff --git a/src/java/org/apache/poi/hssf/record/StringRecord.java b/src/java/org/apache/poi/hssf/record/StringRecord.java index ed157bb52a..914a92d8e3 100644 --- a/src/java/org/apache/poi/hssf/record/StringRecord.java +++ b/src/java/org/apache/poi/hssf/record/StringRecord.java @@ -138,6 +138,11 @@ public class StringRecord } } + public boolean isInValueSection() + { + return true; + } + private int getStringLength() { return field_1_string_length; diff --git a/src/java/org/apache/poi/hssf/record/StyleRecord.java b/src/java/org/apache/poi/hssf/record/StyleRecord.java index c4f8ee35cc..d6bb482e5c 100644 --- a/src/java/org/apache/poi/hssf/record/StyleRecord.java +++ b/src/java/org/apache/poi/hssf/record/StyleRecord.java @@ -57,12 +57,14 @@ package org.apache.poi.hssf.record; import org.apache.poi.util.LittleEndian; import org.apache.poi.util.StringUtil; +import org.apache.poi.util.BitField; /** * Title: Style Record
* Description: Describes a builtin to the gui or user defined style
* REFERENCE: PG 390 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)
* @author Andrew C. Oliver (acoliver at apache dot org) + * @author aviks : string fixes for UserDefined Style * @version 2.0-pre */ @@ -81,8 +83,10 @@ public class StyleRecord private byte field_3_outline_style_level; // only for user defined styles - private byte field_2_name_length; - private String field_3_name; + private short field_2_name_length; //OO doc says 16 bit length, so we believe + private byte field_3_string_options; + private BitField fHighByte; + private String field_4_name; public StyleRecord() { @@ -125,17 +129,24 @@ public class StyleRecord protected void fillFields(byte [] data, short size, int offset) { + fHighByte = new BitField(0x01); //have to init here, since we are being called + //from super, and class level init hasnt been done. field_1_xf_index = LittleEndian.getShort(data, 0 + offset); - if (getType() == 1) + if (getType() == STYLE_BUILT_IN) { field_2_builtin_style = data[ 2 + offset ]; field_3_outline_style_level = data[ 3 + offset ]; } - else if (getType() == 0) + else if (getType() == STYLE_USER_DEFINED) { - field_2_name_length = data[ 2 + offset ]; - field_3_name = StringUtil.getFromCompressedUnicode(data, 3 + offset, - LittleEndian.ubyteToInt(field_2_name_length)); + field_2_name_length = LittleEndian.getShort(data, 2 + offset ); + field_3_string_options = data[4+offset]; + + if (fHighByte.isSet(field_3_string_options)) { + field_4_name= StringUtil.getFromUnicode(data,offset+5,field_2_name_length); + }else { + field_4_name=StringUtil.getFromCompressedUnicode(data,offset+5,field_2_name_length); + } } // todo sanity check exception to make sure we're one or the other @@ -199,7 +210,8 @@ public class StyleRecord public void setName(String name) { - field_3_name = name; + field_4_name = name; + //TODO set name length and string options } // end user defined @@ -273,7 +285,7 @@ public class StyleRecord * @see #getName() */ - public byte getNameLength() + public short getNameLength() { return field_2_name_length; } @@ -286,7 +298,7 @@ public class StyleRecord public String getName() { - return field_3_name; + return field_4_name; } // end user defined @@ -361,7 +373,7 @@ public class StyleRecord else { LittleEndian.putShort(data, 2 + offset, - (( short ) (0x03 + getNameLength()))); + (( short ) (getRecordSize()-4))); } LittleEndian.putShort(data, 4 + offset, getIndex()); if (getType() == STYLE_BUILT_IN) @@ -371,8 +383,9 @@ public class StyleRecord } else { - data[ 6 + offset ] = getNameLength(); - StringUtil.putCompressedUnicode(getName(), data, 7 + offset); + LittleEndian.putShort(data, 6 + offset , getNameLength()); + data[8+offset]=this.field_3_string_options; + StringUtil.putCompressedUnicode(getName(), data, 9 + offset); } return getRecordSize(); } @@ -387,7 +400,11 @@ public class StyleRecord } else { - retval = 7 + getNameLength(); + if (fHighByte.isSet(field_3_string_options)) { + retval= 9+2*getNameLength(); + }else { + retval = 9 + getNameLength(); + } } return retval; } diff --git a/src/java/org/apache/poi/hssf/record/UnknownRecord.java b/src/java/org/apache/poi/hssf/record/UnknownRecord.java index 36b0595498..b88d22f455 100644 --- a/src/java/org/apache/poi/hssf/record/UnknownRecord.java +++ b/src/java/org/apache/poi/hssf/record/UnknownRecord.java @@ -65,16 +65,14 @@ import org.apache.poi.util.LittleEndian; * Company: SuperLink Software, Inc.
* @author Andrew C. Oliver (acoliver at apache dot org)
* @author Jason Height (jheight at chariot dot net dot au)
- * @version 2.0-pre
+ * @author Glen Stampoultzis (glens at apache.org)
*/
public class UnknownRecord
extends Record
{
- private short sid = 0;
- private short size = 0;
- private byte[] thedata = null;
- int offset = 0;
+ private short sid = 0;
+ private byte[] thedata = null;
public UnknownRecord()
{
@@ -91,7 +89,6 @@ public class UnknownRecord
public UnknownRecord(short id, short size, byte [] data)
{
sid = id;
- size = size;
thedata = data;
}
@@ -127,7 +124,7 @@ public class UnknownRecord
protected void fillFields(byte [] data, short sid)
{
- sid = sid;
+ this.sid = sid;
thedata = data;
}
@@ -179,9 +176,7 @@ public class UnknownRecord
/** Unlike the other Record.clone methods this is a shallow clone*/
public Object clone() {
UnknownRecord rec = new UnknownRecord();
- rec.offset = offset;
rec.sid = sid;
- rec.size = size;
rec.thedata = thedata;
return rec;
}
diff --git a/src/java/org/apache/poi/hssf/record/aggregates/FormulaRecordAggregate.java b/src/java/org/apache/poi/hssf/record/aggregates/FormulaRecordAggregate.java
index 7d5b0b048d..761d821dcf 100644
--- a/src/java/org/apache/poi/hssf/record/aggregates/FormulaRecordAggregate.java
+++ b/src/java/org/apache/poi/hssf/record/aggregates/FormulaRecordAggregate.java
@@ -82,6 +82,19 @@ public class FormulaRecordAggregate
this.stringRecord = stringRecord;
}
+ /**
+ * Used only in the clone
+ * @param formulaRecord
+ * @param stringRecord
+ * @param sharedRecord
+ */
+ public FormulaRecordAggregate( FormulaRecord formulaRecord, StringRecord stringRecord, SharedFormulaRecord sharedRecord)
+ {
+ this.formulaRecord = formulaRecord;
+ this.stringRecord = stringRecord;
+ this.sharedFormulaRecord = sharedRecord;
+ }
+
protected void validateSid( short id )
@@ -106,14 +119,14 @@ public class FormulaRecordAggregate
{
int pos = offset;
pos += formulaRecord.serialize(pos, data);
- if (stringRecord != null)
- {
- pos += stringRecord.serialize(pos, data);
- }
if (this.getSharedFormulaRecord() != null)
{
pos += getSharedFormulaRecord().serialize(pos, data);
}
+ if (stringRecord != null)
+ {
+ pos += stringRecord.serialize(pos, data);
+ }
return pos - offset;
}
@@ -221,7 +234,10 @@ public class FormulaRecordAggregate
* @see java.lang.Object#clone()
*/
public Object clone() {
- return new FormulaRecordAggregate((FormulaRecord) this.formulaRecord.clone(), (StringRecord) this.stringRecord.clone());
+ StringRecord clonedString = (stringRecord == null) ? null : (StringRecord)stringRecord.clone();
+ SharedFormulaRecord clonedShared = (sharedFormulaRecord == null) ? null : (SharedFormulaRecord)sharedFormulaRecord.clone();
+
+ return new FormulaRecordAggregate((FormulaRecord) this.formulaRecord.clone(), clonedString, clonedShared);
}
@@ -241,4 +257,19 @@ public class FormulaRecordAggregate
this.sharedFormulaRecord = sharedFormulaRecord;
}
+ /*
+ * Setting to true so that this value does not abort the whole ValueAggregation
+ * (non-Javadoc)
+ * @see org.apache.poi.hssf.record.Record#isInValueSection()
+ */
+ public boolean isInValueSection() {
+
+ return true;
+ }
+
+ public String getStringValue() {
+ if(stringRecord==null) return null;
+ return stringRecord.getString();
+ }
+
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/AbstractFunctionPtg.java b/src/java/org/apache/poi/hssf/record/formula/AbstractFunctionPtg.java
index da08a6dc3d..cd2660219e 100644
--- a/src/java/org/apache/poi/hssf/record/formula/AbstractFunctionPtg.java
+++ b/src/java/org/apache/poi/hssf/record/formula/AbstractFunctionPtg.java
@@ -54,9 +54,8 @@
package org.apache.poi.hssf.record.formula;
import org.apache.poi.util.BinaryTree;
-import org.apache.poi.hssf.util.SheetReferences;
+import org.apache.poi.hssf.model.Workbook;
-import java.util.Stack;
/**
* This class provides the base functionality for Excel sheet functions
@@ -69,7 +68,7 @@ public abstract class AbstractFunctionPtg extends OperationPtg {
//constant used allow a ptgAttr to be mapped properly for its functionPtg
public static final String ATTR_NAME = "specialflag";
-
+ public static final short INDEX_EXTERNAL = 255;
private static BinaryTree map = produceHash();
protected static Object[][] functionData = produceFunctionData();
@@ -104,7 +103,7 @@ public abstract class AbstractFunctionPtg extends OperationPtg {
return lookupName(field_2_fnc_index);
}
- public String toFormulaString(SheetReferences refs) {
+ public String toFormulaString(Workbook book) {
return getName();
}
@@ -140,7 +139,9 @@ public abstract class AbstractFunctionPtg extends OperationPtg {
}
protected short lookupIndex(String name) {
- return (short)((Integer)map.getKeyForValue(name)).intValue();
+ Integer index = (Integer) map.getKeyForValue(name);
+ if (index != null) return index.shortValue();
+ return INDEX_EXTERNAL;
}
/**
@@ -389,6 +390,7 @@ public abstract class AbstractFunctionPtg extends OperationPtg {
dmap.put(new Integer(252),"FREQUENCY");
dmap.put(new Integer(253),"ADDTOOLBAR");
dmap.put(new Integer(254),"DELETETOOLBAR");
+ dmap.put(new Integer(255),"externalflag");
dmap.put(new Integer(256),"RESETTOOLBAR");
dmap.put(new Integer(257),"EVALUATE");
dmap.put(new Integer(258),"GETTOOLBAR");
diff --git a/src/java/org/apache/poi/hssf/record/formula/AddPtg.java b/src/java/org/apache/poi/hssf/record/formula/AddPtg.java
index ead8840677..3a519dceb4 100644
--- a/src/java/org/apache/poi/hssf/record/formula/AddPtg.java
+++ b/src/java/org/apache/poi/hssf/record/formula/AddPtg.java
@@ -62,7 +62,7 @@ package org.apache.poi.hssf.record.formula;
import java.util.List;
-import org.apache.poi.hssf.util.SheetReferences;
+import org.apache.poi.hssf.model.Workbook;
/**
* Addition operator PTG the "+" binomial operator. If you need more
@@ -113,7 +113,7 @@ public class AddPtg
}
/** Implementation of method from Ptg */
- public String toFormulaString(SheetReferences refs)
+ public String toFormulaString(Workbook book)
{
return "+";
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/Area3DPtg.java b/src/java/org/apache/poi/hssf/record/formula/Area3DPtg.java
index 1e425669db..59c405c1e6 100644
--- a/src/java/org/apache/poi/hssf/record/formula/Area3DPtg.java
+++ b/src/java/org/apache/poi/hssf/record/formula/Area3DPtg.java
@@ -291,8 +291,9 @@ public class Area3DPtg extends Ptg
}
- public String toFormulaString( SheetReferences refs )
+ public String toFormulaString(Workbook book)
{
+ SheetReferences refs = book == null ? null : book.getSheetReferences();
StringBuffer retval = new StringBuffer();
if ( refs != null )
{
@@ -318,6 +319,7 @@ public class Area3DPtg extends Ptg
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;
}
@@ -351,4 +353,3 @@ public class Area3DPtg extends Ptg
}
-
diff --git a/src/java/org/apache/poi/hssf/record/formula/AreaPtg.java b/src/java/org/apache/poi/hssf/record/formula/AreaPtg.java
index 87ebb2c769..3189a2c856 100644
--- a/src/java/org/apache/poi/hssf/record/formula/AreaPtg.java
+++ b/src/java/org/apache/poi/hssf/record/formula/AreaPtg.java
@@ -65,7 +65,7 @@ import org.apache.poi.util.BitField;
import org.apache.poi.hssf.util.AreaReference;
import org.apache.poi.hssf.util.CellReference;
-import org.apache.poi.hssf.util.SheetReferences;
+import org.apache.poi.hssf.model.Workbook;
/**
* Specifies a rectangular area of cells A1:A4 for instance.
@@ -305,7 +305,7 @@ public class AreaPtg
field_4_last_column = column;
}
- public String toFormulaString(SheetReferences refs)
+ public String toFormulaString(Workbook book)
{
return (new CellReference(getFirstRow(),getFirstColumn(),!isFirstRowRelative(),!isFirstColRelative())).toString() + ":" +
(new CellReference(getLastRow(),getLastColumn(),!isLastRowRelative(),!isLastColRelative())).toString();
@@ -321,6 +321,7 @@ public class AreaPtg
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;
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/AttrPtg.java b/src/java/org/apache/poi/hssf/record/formula/AttrPtg.java
index d389094d7e..ebbfcba877 100644
--- a/src/java/org/apache/poi/hssf/record/formula/AttrPtg.java
+++ b/src/java/org/apache/poi/hssf/record/formula/AttrPtg.java
@@ -60,7 +60,7 @@
*/
package org.apache.poi.hssf.record.formula;
-import org.apache.poi.hssf.util.SheetReferences;
+import org.apache.poi.hssf.model.Workbook;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.BitField;
@@ -207,11 +207,11 @@ public class AttrPtg
if(space.isSet(field_1_options)) {
return operands[ 0 ];
} else if (optiIf.isSet(field_1_options)) {
- return toFormulaString((SheetReferences)null) + "(" + operands[ 0 ] +")";
+ return toFormulaString((Workbook)null) + "(" + operands[ 0 ] +")";
} else if (optGoto.isSet(field_1_options)) {
- return toFormulaString((SheetReferences)null) + operands[0]; //goto isn't a real formula element should not show up
+ return toFormulaString((Workbook)null) + operands[0]; //goto isn't a real formula element should not show up
} else {
- return toFormulaString((SheetReferences)null) + "(" + operands[ 0 ] + ")";
+ return toFormulaString((Workbook)null) + "(" + operands[ 0 ] + ")";
}
}
@@ -226,7 +226,7 @@ public class AttrPtg
return -1;
}
- public String toFormulaString(SheetReferences refs) {
+ public String toFormulaString(Workbook book) {
if(semiVolatile.isSet(field_1_options)) {
return "ATTR(semiVolatile)";
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/BoolPtg.java b/src/java/org/apache/poi/hssf/record/formula/BoolPtg.java
index 954eb0f80c..84ad7cfca5 100644
--- a/src/java/org/apache/poi/hssf/record/formula/BoolPtg.java
+++ b/src/java/org/apache/poi/hssf/record/formula/BoolPtg.java
@@ -60,7 +60,7 @@
package org.apache.poi.hssf.record.formula;
import org.apache.poi.util.LittleEndian;
-import org.apache.poi.hssf.util.SheetReferences;
+import org.apache.poi.hssf.model.Workbook;
/**
* Boolean (boolean)
@@ -114,7 +114,7 @@ public class BoolPtg
return SIZE;
}
- public String toFormulaString(SheetReferences refs)
+ public String toFormulaString(Workbook book)
{
return field_1_value ? "TRUE" : "FALSE";
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/ConcatPtg.java b/src/java/org/apache/poi/hssf/record/formula/ConcatPtg.java
index bed92e461a..e7249bfbc1 100644
--- a/src/java/org/apache/poi/hssf/record/formula/ConcatPtg.java
+++ b/src/java/org/apache/poi/hssf/record/formula/ConcatPtg.java
@@ -62,7 +62,7 @@ package org.apache.poi.hssf.record.formula;
import java.util.List;
-import org.apache.poi.hssf.util.SheetReferences;
+import org.apache.poi.hssf.model.Workbook;
/**
*
@@ -108,7 +108,7 @@ public class ConcatPtg
return 2;
}
- public String toFormulaString(SheetReferences refs)
+ public String toFormulaString(Workbook book)
{
return CONCAT;
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/DividePtg.java b/src/java/org/apache/poi/hssf/record/formula/DividePtg.java
index 124f25edef..6bb0d9420a 100644
--- a/src/java/org/apache/poi/hssf/record/formula/DividePtg.java
+++ b/src/java/org/apache/poi/hssf/record/formula/DividePtg.java
@@ -62,7 +62,7 @@ package org.apache.poi.hssf.record.formula;
import java.util.List;
-import org.apache.poi.hssf.util.SheetReferences;
+import org.apache.poi.hssf.model.Workbook;
/**
* This PTG implements the standard binomial divide "/"
@@ -108,7 +108,7 @@ public class DividePtg
return 2;
}
- public String toFormulaString(SheetReferences refs)
+ public String toFormulaString(Workbook book)
{
return "/";
}
@@ -117,7 +117,7 @@ public class DividePtg
StringBuffer buffer = new StringBuffer();
buffer.append(operands[ 0 ]);
- buffer.append(toFormulaString((SheetReferences)null));
+ buffer.append(toFormulaString((Workbook)null));
buffer.append(operands[ 1 ]);
return buffer.toString();
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/EqualPtg.java b/src/java/org/apache/poi/hssf/record/formula/EqualPtg.java
index 1ddff9ac64..12438a3397 100644
--- a/src/java/org/apache/poi/hssf/record/formula/EqualPtg.java
+++ b/src/java/org/apache/poi/hssf/record/formula/EqualPtg.java
@@ -62,7 +62,7 @@ package org.apache.poi.hssf.record.formula;
import java.util.List;
-import org.apache.poi.hssf.util.SheetReferences;
+import org.apache.poi.hssf.model.Workbook;
/**
*
@@ -107,7 +107,7 @@ public class EqualPtg
return 2;
}
- public String toFormulaString(SheetReferences refs)
+ public String toFormulaString(Workbook book)
{
return "=";
}
@@ -117,7 +117,7 @@ public class EqualPtg
buffer.append(operands[ 0 ]);
- buffer.append(toFormulaString((SheetReferences)null));
+ buffer.append(toFormulaString((Workbook)null));
buffer.append(operands[ 1 ]);
return buffer.toString();
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/ExpPtg.java b/src/java/org/apache/poi/hssf/record/formula/ExpPtg.java
index 576bce3316..d70e57968f 100644
--- a/src/java/org/apache/poi/hssf/record/formula/ExpPtg.java
+++ b/src/java/org/apache/poi/hssf/record/formula/ExpPtg.java
@@ -60,7 +60,7 @@
*/
package org.apache.poi.hssf.record.formula;
-import org.apache.poi.hssf.util.SheetReferences;
+import org.apache.poi.hssf.model.Workbook;
/**
*
@@ -102,7 +102,7 @@ public class ExpPtg
return SIZE;
}
- public String toFormulaString(SheetReferences refs)
+ public String toFormulaString(Workbook book)
{
return "NO IDEA SHARED FORMULA EXP PTG";
}
@@ -110,7 +110,10 @@ public class ExpPtg
public byte getDefaultOperandClass() {return Ptg.CLASS_VALUE;}
public Object clone() {
- throw new RuntimeException("NO IDEA SHARED FORMULA EXP PTG");
+ //can't clone one that doesnt have data can we??
+ if (this.existing == null) throw new RuntimeException("NO IDEA SHARED FORMULA EXP PTG");
+
+ return new ExpPtg(this.existing, 0);
}
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/FuncPtg.java b/src/java/org/apache/poi/hssf/record/formula/FuncPtg.java
index 1c230c95a4..713d200b2d 100644
--- a/src/java/org/apache/poi/hssf/record/formula/FuncPtg.java
+++ b/src/java/org/apache/poi/hssf/record/formula/FuncPtg.java
@@ -63,7 +63,8 @@ public class FuncPtg extends AbstractFunctionPtg{
FuncPtg ptg = new FuncPtg();
//ptg.field_1_num_args = field_1_num_args;
ptg.field_2_fnc_index = field_2_fnc_index;
- return ptg;
+ ptg.setClass(ptgClass);
+ return ptg;
}
public int getSize() {
diff --git a/src/java/org/apache/poi/hssf/record/formula/FuncVarPtg.java b/src/java/org/apache/poi/hssf/record/formula/FuncVarPtg.java
index f333ba694e..6bf4d7f540 100644
--- a/src/java/org/apache/poi/hssf/record/formula/FuncVarPtg.java
+++ b/src/java/org/apache/poi/hssf/record/formula/FuncVarPtg.java
@@ -52,6 +52,7 @@ public class FuncVarPtg extends AbstractFunctionPtg{
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;
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/GreaterEqualPtg.java b/src/java/org/apache/poi/hssf/record/formula/GreaterEqualPtg.java
index de0b6238d9..b387a5e842 100755
--- a/src/java/org/apache/poi/hssf/record/formula/GreaterEqualPtg.java
+++ b/src/java/org/apache/poi/hssf/record/formula/GreaterEqualPtg.java
@@ -54,7 +54,7 @@
package org.apache.poi.hssf.record.formula;
-import org.apache.poi.hssf.util.SheetReferences;
+import org.apache.poi.hssf.model.Workbook;
/**
* PTG class to implement greater or equal to
@@ -66,7 +66,7 @@ public class GreaterEqualPtg
public final static int SIZE = 1;
public final static byte sid = 0x0c;
- /** Creates new AddPtg */
+ /** Creates new GreaterEqualPtg */
public GreaterEqualPtg()
{
@@ -98,7 +98,7 @@ public class GreaterEqualPtg
return 2;
}
- public String toFormulaString(SheetReferences refs)
+ public String toFormulaString(Workbook book)
{
return ">=";
}
@@ -108,7 +108,7 @@ public class GreaterEqualPtg
buffer.append(operands[ 0 ]);
- buffer.append(toFormulaString((SheetReferences)null));
+ buffer.append(toFormulaString((Workbook)null));
buffer.append(operands[ 1 ]);
return buffer.toString();
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/GreaterThanPtg.java b/src/java/org/apache/poi/hssf/record/formula/GreaterThanPtg.java
index 5f7d6450e0..04fbcac2ef 100644
--- a/src/java/org/apache/poi/hssf/record/formula/GreaterThanPtg.java
+++ b/src/java/org/apache/poi/hssf/record/formula/GreaterThanPtg.java
@@ -61,7 +61,7 @@ package org.apache.poi.hssf.record.formula;
import java.util.List;
-import org.apache.poi.hssf.util.SheetReferences;
+import org.apache.poi.hssf.model.Workbook;
/**
* Greater than operator PTG ">"
@@ -133,7 +133,7 @@ public class GreaterThanPtg
* Implementation of method from Ptg
* @param refs the Sheet References
*/
- public String toFormulaString(SheetReferences refs)
+ public String toFormulaString(Workbook book)
{
return this.GREATERTHAN;
}
@@ -171,5 +171,3 @@ public class GreaterThanPtg
return new GreaterThanPtg();
}
}
-
-
diff --git a/src/java/org/apache/poi/hssf/record/formula/IntPtg.java b/src/java/org/apache/poi/hssf/record/formula/IntPtg.java
index 200f5dc651..e06f1ecd25 100644
--- a/src/java/org/apache/poi/hssf/record/formula/IntPtg.java
+++ b/src/java/org/apache/poi/hssf/record/formula/IntPtg.java
@@ -61,7 +61,7 @@
package org.apache.poi.hssf.record.formula;
import org.apache.poi.util.LittleEndian;
-import org.apache.poi.hssf.util.SheetReferences;
+import org.apache.poi.hssf.model.Workbook;
/**
* Integer (short intger)
@@ -116,7 +116,7 @@ public class IntPtg
return SIZE;
}
- public String toFormulaString(SheetReferences refs)
+ public String toFormulaString(Workbook book)
{
return "" + getValue();
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/LessEqualPtg.java b/src/java/org/apache/poi/hssf/record/formula/LessEqualPtg.java
index 0c8165fb7c..c1c7570029 100755
--- a/src/java/org/apache/poi/hssf/record/formula/LessEqualPtg.java
+++ b/src/java/org/apache/poi/hssf/record/formula/LessEqualPtg.java
@@ -53,7 +53,7 @@
*/
package org.apache.poi.hssf.record.formula;
-import org.apache.poi.hssf.util.SheetReferences;
+import org.apache.poi.hssf.model.Workbook;
/**
@@ -67,7 +67,7 @@ public class LessEqualPtg
public final static int SIZE = 1;
public final static byte sid = 0x0a;
- /** Creates new AddPtg */
+ /** Creates new LessEqualPtg */
public LessEqualPtg()
{
@@ -99,7 +99,7 @@ public class LessEqualPtg
return 2;
}
- public String toFormulaString(SheetReferences refs)
+ public String toFormulaString(Workbook book)
{
return "<=";
}
@@ -109,7 +109,7 @@ public class LessEqualPtg
buffer.append(operands[ 0 ]);
- buffer.append(toFormulaString((SheetReferences)null));
+ buffer.append(toFormulaString((Workbook)null));
buffer.append(operands[ 1 ]);
return buffer.toString();
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/LessThanPtg.java b/src/java/org/apache/poi/hssf/record/formula/LessThanPtg.java
index cab99be9c3..a856b93bde 100644
--- a/src/java/org/apache/poi/hssf/record/formula/LessThanPtg.java
+++ b/src/java/org/apache/poi/hssf/record/formula/LessThanPtg.java
@@ -63,7 +63,7 @@ package org.apache.poi.hssf.record.formula;
import java.util.List;
//POI
-import org.apache.poi.hssf.util.SheetReferences;
+import org.apache.poi.hssf.model.Workbook;
/**
* Less than operator PTG "<". The SID is taken from the
@@ -142,7 +142,7 @@ public class LessThanPtg
* Implementation of method from Ptg
* @param refs the Sheet References
*/
- public String toFormulaString(SheetReferences refs)
+ public String toFormulaString(Workbook book)
{
return this.LESSTHAN;
}
@@ -180,6 +180,3 @@ public class LessThanPtg
}
}
-
-
-
diff --git a/src/java/org/apache/poi/hssf/record/formula/MemErrPtg.java b/src/java/org/apache/poi/hssf/record/formula/MemErrPtg.java
index c48ad8c3b1..31a1bcafec 100644
--- a/src/java/org/apache/poi/hssf/record/formula/MemErrPtg.java
+++ b/src/java/org/apache/poi/hssf/record/formula/MemErrPtg.java
@@ -61,7 +61,7 @@
package org.apache.poi.hssf.record.formula;
import org.apache.poi.util.LittleEndian;
-import org.apache.poi.hssf.util.SheetReferences;
+import org.apache.poi.hssf.model.Workbook;
/**
*
@@ -118,7 +118,7 @@ public class MemErrPtg
return SIZE;
}
- public String toFormulaString(SheetReferences refs)
+ public String toFormulaString(Workbook book)
{
return "ERR#";
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/MemFuncPtg.java b/src/java/org/apache/poi/hssf/record/formula/MemFuncPtg.java
index 2d422b1c7e..a8b63609c4 100644
--- a/src/java/org/apache/poi/hssf/record/formula/MemFuncPtg.java
+++ b/src/java/org/apache/poi/hssf/record/formula/MemFuncPtg.java
@@ -60,7 +60,7 @@
package org.apache.poi.hssf.record.formula;
import org.apache.poi.util.LittleEndian;
-import org.apache.poi.hssf.util.SheetReferences;
+import org.apache.poi.hssf.model.Workbook;
/**
* @author Glen Stampoultzis (glens at apache.org)
@@ -96,7 +96,7 @@ public class MemFuncPtg extends ControlPtg
LittleEndian.putShort( array, offset + 1, (short)field_1_len_ref_subexpression );
}
- public String toFormulaString( SheetReferences refs )
+ public String toFormulaString(Workbook book)
{
return "";
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/MissingArgPtg.java b/src/java/org/apache/poi/hssf/record/formula/MissingArgPtg.java
index 3f88ded3b8..c65ab41f3d 100644
--- a/src/java/org/apache/poi/hssf/record/formula/MissingArgPtg.java
+++ b/src/java/org/apache/poi/hssf/record/formula/MissingArgPtg.java
@@ -54,7 +54,7 @@
package org.apache.poi.hssf.record.formula;
-import org.apache.poi.hssf.util.SheetReferences;
+import org.apache.poi.hssf.model.Workbook;
/**
* Missing Function Arguments
@@ -91,7 +91,7 @@ public class MissingArgPtg
}
- public String toFormulaString(SheetReferences refs)
+ public String toFormulaString(Workbook book)
{
return " ";
}
@@ -103,5 +103,3 @@ public class MissingArgPtg
}
}
-
-
diff --git a/src/java/org/apache/poi/hssf/record/formula/MultiplyPtg.java b/src/java/org/apache/poi/hssf/record/formula/MultiplyPtg.java
index 143702ce16..6b33e619b6 100644
--- a/src/java/org/apache/poi/hssf/record/formula/MultiplyPtg.java
+++ b/src/java/org/apache/poi/hssf/record/formula/MultiplyPtg.java
@@ -61,7 +61,7 @@
package org.apache.poi.hssf.record.formula;
import java.util.List;
-import org.apache.poi.hssf.util.SheetReferences;
+import org.apache.poi.hssf.model.Workbook;
/**
* Implements the standard mathmatical multiplication - *
@@ -114,7 +114,7 @@ public class MultiplyPtg
}
- public String toFormulaString(SheetReferences refs)
+ public String toFormulaString(Workbook book)
{
return "*";
}
@@ -123,9 +123,9 @@ public class MultiplyPtg
{
StringBuffer buffer = new StringBuffer();
- buffer.append(operands[ 0 ].toFormulaString((SheetReferences)null));
+ buffer.append(operands[ 0 ].toFormulaString((Workbook)null));
buffer.append("*");
- buffer.append(operands[ 1 ].toFormulaString((SheetReferences)null));
+ buffer.append(operands[ 1 ].toFormulaString((Workbook)null));
return buffer.toString();
}
@@ -133,7 +133,7 @@ public class MultiplyPtg
StringBuffer buffer = new StringBuffer();
buffer.append(operands[ 0 ]);
- buffer.append(toFormulaString((SheetReferences)null));
+ buffer.append(toFormulaString((Workbook)null));
buffer.append(operands[ 1 ]);
return buffer.toString();
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/NamePtg.java b/src/java/org/apache/poi/hssf/record/formula/NamePtg.java
index c926d511a1..6cdee6af03 100644
--- a/src/java/org/apache/poi/hssf/record/formula/NamePtg.java
+++ b/src/java/org/apache/poi/hssf/record/formula/NamePtg.java
@@ -61,7 +61,8 @@
package org.apache.poi.hssf.record.formula;
import org.apache.poi.util.LittleEndian;
-import org.apache.poi.hssf.util.SheetReferences;
+import org.apache.poi.hssf.model.Workbook;
+import org.apache.poi.hssf.record.NameRecord;
/**
*
@@ -73,10 +74,10 @@ public class NamePtg
extends Ptg
{
public final static short sid = 0x23;
- private final static int SIZE = 7;
- private short field_1_ixti; // unknown function
- private short field_2_label_index;
- private short field_3_zero; // reserved must be 0
+ private final static int SIZE = 5;
+ private short field_1_label_index;
+ private short field_2_zero; // reserved must be 0
+ boolean xtra=false;
private NamePtg() {
@@ -85,9 +86,22 @@ public class NamePtg
/** Creates new NamePtg */
- public NamePtg(String name)
+ public NamePtg(String name, Workbook book)
{
- //TODO
+ final short n = (short) (book.getNumNames() + 1);
+ NameRecord rec;
+ for (short i = 1; i < n; i++) {
+ rec = book.getNameRecord(i - 1);
+ if (name.equals(rec.getNameText())) {
+ field_1_label_index = i;
+ return;
+ }
+ }
+ rec = new NameRecord();
+ rec.setNameText(name);
+ rec.setNameTextLength((byte) name.length());
+ book.addName(rec);
+ field_1_label_index = n;
}
/** Creates new NamePtg */
@@ -95,13 +109,17 @@ public class NamePtg
public NamePtg(byte [] data, int offset)
{
offset++;
- field_1_ixti = LittleEndian.getShort(data, offset);
- field_2_label_index = LittleEndian.getShort(data, offset + 2);
- field_3_zero = LittleEndian.getShort(data, offset + 4);
+ //field_1_ixti = LittleEndian.getShort(data, offset);
+ field_1_label_index = LittleEndian.getShort(data, offset );
+ field_2_zero = LittleEndian.getShort(data, offset + 2);
+ //if (data[offset+6]==0) xtra=true;
}
public void writeBytes(byte [] array, int offset)
{
+ array[offset+0]= (byte) (sid + ptgClass);
+ LittleEndian.putShort(array,offset+1,field_1_label_index);
+ LittleEndian.putShort(array,offset+3, field_2_zero);
}
public int getSize()
@@ -109,18 +127,18 @@ public class NamePtg
return SIZE;
}
- public String toFormulaString(SheetReferences refs)
+ public String toFormulaString(Workbook book)
{
- return "NO IDEA - NAME";
+ NameRecord rec = book.getNameRecord(field_1_label_index - 1);
+ return rec.getNameText();
}
- public byte getDefaultOperandClass() {return Ptg.CLASS_VALUE;}
+ public byte getDefaultOperandClass() {return Ptg.CLASS_REF;}
public Object clone() {
NamePtg ptg = new NamePtg();
- ptg.field_1_ixti = field_1_ixti;
- ptg.field_2_label_index = field_2_label_index;
- ptg.field_3_zero = field_3_zero;
+ ptg.field_1_label_index = field_1_label_index;
+ ptg.field_2_zero = field_2_zero;
return ptg;
}
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/NameXPtg.java b/src/java/org/apache/poi/hssf/record/formula/NameXPtg.java
index b913f438a4..9b6225d809 100644
--- a/src/java/org/apache/poi/hssf/record/formula/NameXPtg.java
+++ b/src/java/org/apache/poi/hssf/record/formula/NameXPtg.java
@@ -61,7 +61,7 @@
package org.apache.poi.hssf.record.formula;
import org.apache.poi.util.LittleEndian;
-import org.apache.poi.hssf.util.SheetReferences;
+import org.apache.poi.hssf.model.Workbook;
/**
*
@@ -102,7 +102,7 @@ public class NameXPtg extends Ptg
public void writeBytes(byte [] array, int offset)
{
- array[ offset + 0 ] = sid;
+ array[ offset + 0 ] = (byte)(sid + ptgClass);
LittleEndian.putShort(array, offset + 1, field_1_ixals);
LittleEndian.putShort(array,offset+3, field_2_ilbl);
LittleEndian.putShort(array, offset + 5, field_3_reserved);
@@ -113,7 +113,7 @@ public class NameXPtg extends Ptg
return SIZE;
}
- public String toFormulaString(SheetReferences refs)
+ public String toFormulaString(Workbook book)
{
return "NO IDEA - NAME";
}
@@ -125,6 +125,7 @@ public class NameXPtg extends Ptg
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;
}
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/NotEqualPtg.java b/src/java/org/apache/poi/hssf/record/formula/NotEqualPtg.java
index c43c196789..b12b16ae97 100755
--- a/src/java/org/apache/poi/hssf/record/formula/NotEqualPtg.java
+++ b/src/java/org/apache/poi/hssf/record/formula/NotEqualPtg.java
@@ -56,7 +56,7 @@ package org.apache.poi.hssf.record.formula;
import java.util.List;
-import org.apache.poi.hssf.util.SheetReferences;
+import org.apache.poi.hssf.model.Workbook;
/**
* Ptg class to implement not equal
@@ -69,7 +69,7 @@ public class NotEqualPtg
public final static int SIZE = 1;
public final static byte sid = 0x0e;
- /** Creates new AddPtg */
+ /** Creates new NotEqualPtg */
public NotEqualPtg()
{
@@ -101,7 +101,7 @@ public class NotEqualPtg
return 2;
}
- public String toFormulaString(SheetReferences refs)
+ public String toFormulaString(Workbook book)
{
return "<>";
}
@@ -111,7 +111,7 @@ public class NotEqualPtg
buffer.append(operands[ 0 ]);
- buffer.append(toFormulaString((SheetReferences)null));
+ buffer.append(toFormulaString((Workbook)null));
buffer.append(operands[ 1 ]);
return buffer.toString();
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/NumberPtg.java b/src/java/org/apache/poi/hssf/record/formula/NumberPtg.java
index e071420bc5..b43c5536eb 100644
--- a/src/java/org/apache/poi/hssf/record/formula/NumberPtg.java
+++ b/src/java/org/apache/poi/hssf/record/formula/NumberPtg.java
@@ -55,7 +55,7 @@
package org.apache.poi.hssf.record.formula;
import org.apache.poi.util.LittleEndian;
-import org.apache.poi.hssf.util.SheetReferences;
+import org.apache.poi.hssf.model.Workbook;
/**
* Number
* Stores a floating point value in a formula
@@ -113,7 +113,7 @@ public class NumberPtg
return SIZE;
}
- public String toFormulaString(SheetReferences refs)
+ public String toFormulaString(Workbook book)
{
return "" + getValue();
}
@@ -125,4 +125,3 @@ public class NumberPtg
return ptg;
}
}
-
diff --git a/src/java/org/apache/poi/hssf/record/formula/ParenthesisPtg.java b/src/java/org/apache/poi/hssf/record/formula/ParenthesisPtg.java
index c2118f151f..2abff9e73a 100644
--- a/src/java/org/apache/poi/hssf/record/formula/ParenthesisPtg.java
+++ b/src/java/org/apache/poi/hssf/record/formula/ParenthesisPtg.java
@@ -57,7 +57,7 @@ package org.apache.poi.hssf.record.formula;
import java.util.List;
-import org.apache.poi.hssf.util.SheetReferences;
+import org.apache.poi.hssf.model.Workbook;
/**
* While formula tokens are stored in RPN order and thus do not need parenthesis for
@@ -107,7 +107,7 @@ public class ParenthesisPtg
return 1;
}
- public String toFormulaString(SheetReferences refs)
+ public String toFormulaString(Workbook book)
{
return "()";
}
@@ -124,4 +124,3 @@ public class ParenthesisPtg
}
}
-
diff --git a/src/java/org/apache/poi/hssf/record/formula/PowerPtg.java b/src/java/org/apache/poi/hssf/record/formula/PowerPtg.java
index ca7fa64863..161918abef 100644
--- a/src/java/org/apache/poi/hssf/record/formula/PowerPtg.java
+++ b/src/java/org/apache/poi/hssf/record/formula/PowerPtg.java
@@ -62,7 +62,7 @@ package org.apache.poi.hssf.record.formula;
import java.util.List;
-import org.apache.poi.hssf.util.SheetReferences;
+import org.apache.poi.hssf.model.Workbook;
/**
*
@@ -108,7 +108,7 @@ public class PowerPtg
return 2;
}
- public String toFormulaString(SheetReferences refs)
+ public String toFormulaString(Workbook book)
{
return "^";
}
@@ -118,7 +118,7 @@ public class PowerPtg
buffer.append(operands[ 0 ]);
- buffer.append(toFormulaString((SheetReferences)null));
+ buffer.append(toFormulaString((Workbook)null));
buffer.append(operands[ 1 ]);
return buffer.toString();
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/Ptg.java b/src/java/org/apache/poi/hssf/record/formula/Ptg.java
index 3787d0056e..cdf584ed1a 100644
--- a/src/java/org/apache/poi/hssf/record/formula/Ptg.java
+++ b/src/java/org/apache/poi/hssf/record/formula/Ptg.java
@@ -63,7 +63,7 @@ package org.apache.poi.hssf.record.formula;
import java.util.List;
import java.util.ArrayList;
-import org.apache.poi.hssf.util.SheetReferences;
+import org.apache.poi.hssf.model.Workbook;
/**
*
@@ -307,6 +307,12 @@ public abstract class Ptg
case MissingArgPtg.sid:
retval = new MissingArgPtg(data,offset);
break;
+ case UnaryPlusPtg.sid:
+ retval=new UnaryPlusPtg(data,offset);
+ break;
+ case UnaryMinusPtg.sid:
+ retval=new UnaryMinusPtg(data,offset);
+ break;
default :
@@ -341,7 +347,7 @@ public abstract class Ptg
/**
* return a string representation of this token alone
*/
- public abstract String toFormulaString(SheetReferences refs);
+ public abstract String toFormulaString(Workbook book);
/**
* dump a debug representation (hexdump) to a string
*/
@@ -357,6 +363,14 @@ public abstract class Ptg
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;
diff --git a/src/java/org/apache/poi/hssf/record/formula/Ref3DPtg.java b/src/java/org/apache/poi/hssf/record/formula/Ref3DPtg.java
index 0d842955b9..4e175e85be 100644
--- a/src/java/org/apache/poi/hssf/record/formula/Ref3DPtg.java
+++ b/src/java/org/apache/poi/hssf/record/formula/Ref3DPtg.java
@@ -61,6 +61,7 @@ import org.apache.poi.util.LittleEndian;
import org.apache.poi.hssf.util.RangeAddress;
import org.apache.poi.hssf.util.CellReference;
import org.apache.poi.hssf.util.SheetReferences;
+import org.apache.poi.hssf.model.Workbook;
import org.apache.poi.util.BitField;
import org.apache.poi.hssf.model.Workbook;
@@ -104,7 +105,7 @@ public class Ref3DPtg extends Ptg {
public String toString() {
StringBuffer buffer = new StringBuffer();
- buffer.append("Ref3dPrg\n");
+ 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");
@@ -193,8 +194,9 @@ public class Ref3DPtg extends Ptg {
}
- public String toFormulaString(SheetReferences refs) {
+ public String toFormulaString(Workbook book) {
StringBuffer retval = new StringBuffer();
+ SheetReferences refs = book == null ? null : book.getSheetReferences();
if (refs != null) {
retval.append(refs.getSheetName((int)this.field_1_index_extern_sheet));
retval.append('!');
@@ -210,6 +212,7 @@ public class Ref3DPtg extends Ptg {
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;
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/ReferencePtg.java b/src/java/org/apache/poi/hssf/record/formula/ReferencePtg.java
index 90f7d899c8..4c14aaf55f 100644
--- a/src/java/org/apache/poi/hssf/record/formula/ReferencePtg.java
+++ b/src/java/org/apache/poi/hssf/record/formula/ReferencePtg.java
@@ -64,7 +64,7 @@ import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.BitField;
import org.apache.poi.hssf.util.CellReference;
-import org.apache.poi.hssf.util.SheetReferences;
+import org.apache.poi.hssf.model.Workbook;
/**
* ReferencePtg - handles references (such as A1, A2, IA4)
@@ -179,7 +179,7 @@ public class ReferencePtg extends Ptg
return SIZE;
}
- public String toFormulaString(SheetReferences refs)
+ public String toFormulaString(Workbook book)
{
//TODO -- should we store a cellreference instance in this ptg?? but .. memory is an issue, i believe!
return (new CellReference(getRow(),getColumn(),!isRowRelative(),!isColRelative())).toString();
@@ -193,6 +193,7 @@ public class ReferencePtg extends Ptg
ReferencePtg ptg = new ReferencePtg();
ptg.field_1_row = field_1_row;
ptg.field_2_col = field_2_col;
+ ptg.setClass(ptgClass);
return ptg;
}
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/StringPtg.java b/src/java/org/apache/poi/hssf/record/formula/StringPtg.java
index 022fffd83c..1ad2789d47 100644
--- a/src/java/org/apache/poi/hssf/record/formula/StringPtg.java
+++ b/src/java/org/apache/poi/hssf/record/formula/StringPtg.java
@@ -55,8 +55,9 @@
package org.apache.poi.hssf.record.formula;
import org.apache.poi.util.LittleEndian;
-
-import org.apache.poi.hssf.util.SheetReferences;
+import org.apache.poi.util.BitField;
+import org.apache.poi.hssf.model.Workbook;
+import org.apache.poi.util.StringUtil;
/**
* Number
@@ -70,7 +71,12 @@ public class StringPtg
{
public final static int SIZE = 9;
public final static byte sid = 0x17;
- private String field_1_value;
+ //NOTE: OO doc says 16bit lenght, but BiffViewer says 8
+ // Book says something totally different, so dont look there!
+ byte field_1_length;
+ byte field_2_options;
+ BitField fHighByte = new BitField(0x01);
+ private String field_3_string;
private StringPtg() {
//Required for clone methods
@@ -79,7 +85,16 @@ public class StringPtg
/** Create a StringPtg from a byte array read from disk */
public StringPtg(byte [] data, int offset)
{
- setValue(new String(data, offset+3, data[offset+1] + 256*data[offset+2]));
+ offset++;
+ field_1_length = data[offset];
+ field_2_options = data[offset+1];
+ if (fHighByte.isSet(field_2_options)) {
+ field_3_string= StringUtil.getFromUnicode(data,offset+2,field_1_length);
+ }else {
+ field_3_string=StringUtil.getFromCompressedUnicode(data,offset+2,field_1_length);
+ }
+
+ //setValue(new String(data, offset+3, data[offset+1] + 256*data[offset+2]));
}
/** Create a StringPtg from a string representation of the number
@@ -88,35 +103,49 @@ public class StringPtg
* @param value : String representation of a floating point number
*/
public StringPtg(String value) {
- setValue(value);
+ if (value.length() >255) {
+ throw new IllegalArgumentException("String literals in formulas cant be bigger than 255 characters ASCII");
+ }
+ this.field_2_options=0;
+ this.fHighByte.setBoolean(field_2_options, false);
+ this.field_3_string=value;
+ this.field_1_length=(byte)value.length(); //for the moment, we support only ASCII strings in formulas we create
}
-
+ /*
public void setValue(String value)
{
field_1_value = value;
- }
+ }*/
public String getValue()
{
- return field_1_value;
+ return field_3_string;
}
public void writeBytes(byte [] array, int offset)
{
array[ offset + 0 ] = sid;
- array[ offset + 1 ] = (byte)(getValue().length() % 256);
- array[ offset + 2 ] = (byte)(getValue().length() / 256);
- System.arraycopy(getValue().getBytes(), 0, array, offset + 3, getValue().length());
+ array[ offset + 1 ] = field_1_length;
+ array[ offset + 2 ] = field_2_options;
+ if (fHighByte.isSet(field_2_options)) {
+ StringUtil.putUncompressedUnicode(getValue(),array,offset+3);
+ }else {
+ StringUtil.putCompressedUnicode(getValue(),array,offset+3);
+ }
}
public int getSize()
{
- return field_1_value.length() + 3;
+ if (fHighByte.isSet(field_2_options)) {
+ return 2*field_1_length+3;
+ }else {
+ return field_1_length+3;
+ }
}
- public String toFormulaString(SheetReferences refs)
+ public String toFormulaString(Workbook book)
{
return "\""+getValue()+"\"";
}
@@ -126,9 +155,10 @@ public class StringPtg
public Object clone() {
StringPtg ptg = new StringPtg();
- ptg.field_1_value = field_1_value;
+ ptg.field_1_length = field_1_length;
+ ptg.field_2_options=field_2_options;
+ ptg.field_3_string=field_3_string;
return ptg;
}
}
-
diff --git a/src/java/org/apache/poi/hssf/record/formula/SubtractPtg.java b/src/java/org/apache/poi/hssf/record/formula/SubtractPtg.java
index 2c5588f3dd..cd9fa5fd78 100644
--- a/src/java/org/apache/poi/hssf/record/formula/SubtractPtg.java
+++ b/src/java/org/apache/poi/hssf/record/formula/SubtractPtg.java
@@ -61,7 +61,7 @@
package org.apache.poi.hssf.record.formula;
import java.util.List;
-import org.apache.poi.hssf.util.SheetReferences;
+import org.apache.poi.hssf.model.Workbook;
/**
*
@@ -105,7 +105,7 @@ public class SubtractPtg
return 2;
}
- public String toFormulaString(SheetReferences refs)
+ public String toFormulaString(Workbook book)
{
return "-";
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/UnaryMinusPtg.java b/src/java/org/apache/poi/hssf/record/formula/UnaryMinusPtg.java
new file mode 100644
index 0000000000..bb60dd09bc
--- /dev/null
+++ b/src/java/org/apache/poi/hssf/record/formula/UnaryMinusPtg.java
@@ -0,0 +1,127 @@
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2003 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache POI" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache POI", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ *
+ * TODO: MODE , this is only row specific + * @param startRow + * @param endRow + * @param n + * @param isRow + */ + protected void shiftMerged(int startRow, int endRow, int n, boolean isRow) { + List shiftedRegions = new ArrayList(); + //move merged regions completely if they fall within the new region boundaries when they are shifted + for (int i = 0; i < this.getNumMergedRegions(); i++) { + Region merged = this.getMergedRegionAt(i); + + boolean inStart = (merged.getRowFrom() >= startRow || merged.getRowTo() >= startRow); + boolean inEnd = (merged.getRowTo() <= endRow || merged.getRowFrom() <= endRow); + + //dont check if it's not within the shifted area + if (! (inStart && inEnd)) continue; + + //only shift if the region outside the shifted rows is not merged too + if (!merged.contains(startRow-1, (short)0) && !merged.contains(endRow+1, (short)0)){ + merged.setRowFrom(merged.getRowFrom()+n); + merged.setRowTo(merged.getRowTo()+n); + //have to remove/add it back + shiftedRegions.add(merged); + this.removeMergedRegion(i); + i = i -1; // we have to back up now since we removed one + + } + + } + + //readd so it doesn't get shifted again + Iterator iterator = shiftedRegions.iterator(); + while (iterator.hasNext()) { + Region region = (Region)iterator.next(); + + this.addMergedRegion(region); + } + + } + /** * Shifts rows between startRow and endRow n number of rows. * If you use a negative number, it will shift rows up. @@ -894,19 +962,25 @@ public class HSSFSheet * * Calls shiftRows(startRow, endRow, n, false, false); * + *
+ * Additionally shifts merged regions that are completely defined in these + * rows (ie. merged 2 cells on a row to be shifted). * @param startRow the row to start shifting * @param endRow the row to end shifting * @param n the number of rows to shift */ public void shiftRows( int startRow, int endRow, int n ) { - shiftRows(startRow, endRow, n, false, false); + shiftRows(startRow, endRow, n, false, false); } /** * Shifts rows between startRow and endRow n number of rows. * If you use a negative number, it will shift rows up. * Code ensures that rows don't wrap around - * + * + *
+ * Additionally shifts merged regions that are completely defined in these
+ * rows (ie. merged 2 cells on a row to be shifted).
* @param startRow the row to start shifting
* @param endRow the row to end shifting
* @param n the number of rows to shift
@@ -928,6 +1002,9 @@ public class HSSFSheet
e = startRow;
inc = -1;
}
+
+ shiftMerged(startRow, endRow, n, true);
+
for ( int rowNum = s; rowNum >= startRow && rowNum <= endRow && rowNum >= 0 && rowNum < 65536; rowNum += inc )
{
HSSFRow row = getRow( rowNum );
@@ -937,6 +1014,9 @@ public class HSSFSheet
HSSFCell cell;
+
+
+
// Removes the cells before over writting them.
for ( short col = row2Replace.getFirstCellNum(); col <= row2Replace.getLastCellNum(); col++ )
{
@@ -1021,5 +1101,51 @@ public class HSSFSheet
getSheet().createSplitPane( xSplitPos, ySplitPos, topRow, leftmostColumn, activePane );
}
+ /**
+ * Sets whether the gridlines are shown in a viewer.
+ * @param show whether to show gridlines or not
+ */
+ public void setDisplayGridlines(boolean show) {
+ sheet.setDisplayGridlines(show);
+ }
+ /**
+ * Returns if gridlines are displayed.
+ * @return whether gridlines are displayed
+ */
+ public boolean isDisplayGridlines() {
+ return sheet.isDisplayGridlines();
+ }
+
+ /**
+ * Sets whether the formulas are shown in a viewer.
+ * @param show whether to show formulas or not
+ */
+ public void setDisplayFormulas(boolean show) {
+ sheet.setDisplayFormulas(show);
+ }
+
+ /**
+ * Returns if formulas are displayed.
+ * @return whether formulas are displayed
+ */
+ public boolean isDisplayFormulas() {
+ return sheet.isDisplayFormulas();
+ }
+
+ /**
+ * Sets whether the RowColHeadings are shown in a viewer.
+ * @param show whether to show RowColHeadings or not
+ */
+ public void setDisplayRowColHeadings(boolean show) {
+ sheet.setDisplayRowColHeadings(show);
+ }
+
+ /**
+ * Returns if RowColHeadings are displayed.
+ * @return whether RowColHeadings are displayed
+ */
+ public boolean isDisplayRowColHeadings() {
+ return sheet.isDisplayRowColHeadings();
+ }
}
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java b/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java
index 8420aa63b0..c1bfbd3182 100644
--- a/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java
+++ b/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java
@@ -147,6 +147,14 @@ public class HSSFWorkbook
* memory.
*/
private POIFSFileSystem poifs;
+
+ /**
+ * Used to keep track of the data formatter so that all
+ * createDataFormatter calls return the same one for a given
+ * book. This ensures that updates from one places is visible
+ * someplace else.
+ */
+ private HSSFDataFormat formatter;
private static POILogger log = POILogFactory.getLogger(HSSFWorkbook.class);
@@ -273,7 +281,9 @@ public class HSSFWorkbook
/**
- * set the sheet name.
+ * set the sheet name.
+ * Will throw IllegalArgumentException if the name is greater than 31 chars
+ * or contains /\?*[]
* @param sheet number (0 based)
* @param sheet name
*/
@@ -374,7 +384,11 @@ public class HSSFWorkbook
windowTwo.setPaged(sheets.size() == 1);
sheets.add(clonedSheet);
- workbook.setSheetName(sheets.size()-1, srcName+"[1]");
+ if (srcName.length()<28) {
+ workbook.setSheetName(sheets.size()-1, srcName+"(2)");
+ }else {
+ workbook.setSheetName(sheets.size()-1,srcName.substring(0,28)+"(2)");
+ }
return clonedSheet;
}
return null;
@@ -890,7 +904,7 @@ public class HSSFWorkbook
if (name == null) return null;
//adding one here because 0 indicates a global named region; doesnt make sense for print areas
- return name.getAreaReference(workbook.getSheetReferences());
+ return name.getAreaReference(workbook);
}
/**
@@ -945,13 +959,15 @@ public class HSSFWorkbook
}
/**
- * Creates an instance of HSSFDataFormat.
+ * Returns the instance of HSSFDataFormat for this workbook.
* @return the HSSFDataFormat object
* @see org.apache.poi.hssf.record.FormatRecord
* @see org.apache.poi.hssf.record.Record
*/
public HSSFDataFormat createDataFormat() {
- return new HSSFDataFormat(workbook);
+ if (formatter == null)
+ formatter = new HSSFDataFormat(workbook);
+ return formatter;
}
/** remove the named range by his name
diff --git a/src/java/org/apache/poi/poifs/filesystem/DirectoryEntry.java b/src/java/org/apache/poi/poifs/filesystem/DirectoryEntry.java
index 135a2ba4e2..a85e7e9cb8 100644
--- a/src/java/org/apache/poi/poifs/filesystem/DirectoryEntry.java
+++ b/src/java/org/apache/poi/poifs/filesystem/DirectoryEntry.java
@@ -59,6 +59,8 @@ import java.io.*;
import java.util.*;
+import org.apache.poi.hpsf.ClassID;
+
/**
* This interface defines methods specific to Directory objects
* managed by a Filesystem instance.
@@ -160,5 +162,20 @@ public interface DirectoryEntry
public DirectoryEntry createDirectory(final String name)
throws IOException;
+
+ /**
+ * Gets the storage clsid of the directory entry
+ *
+ * @return storage Class ID
+ */
+ public ClassID getStorageClsid();
+
+ /**
+ * Sets the storage clsid for the directory entry
+ *
+ * @param clsidStorage storage Class ID
+ */
+ public void setStorageClsid(ClassID clsidStorage);
+
} // end public interface DirectoryEntry
diff --git a/src/java/org/apache/poi/poifs/filesystem/DirectoryNode.java b/src/java/org/apache/poi/poifs/filesystem/DirectoryNode.java
index d7c670c252..feeb74771d 100644
--- a/src/java/org/apache/poi/poifs/filesystem/DirectoryNode.java
+++ b/src/java/org/apache/poi/poifs/filesystem/DirectoryNode.java
@@ -59,6 +59,7 @@ import java.io.*;
import java.util.*;
+import org.apache.poi.hpsf.ClassID;
import org.apache.poi.poifs.dev.POIFSViewable;
import org.apache.poi.poifs.property.DirectoryProperty;
import org.apache.poi.poifs.property.DocumentProperty;
@@ -346,6 +347,26 @@ public class DirectoryNode
return rval;
}
+ /**
+ * Gets the storage clsid of the directory entry
+ *
+ * @return storage Class ID
+ */
+ public ClassID getStorageClsid()
+ {
+ return getProperty().getStorageClsid();
+ }
+
+ /**
+ * Sets the storage clsid for the directory entry
+ *
+ * @param clsidStorage storage Class ID
+ */
+ public void setStorageClsid(ClassID clsidStorage)
+ {
+ getProperty().setStorageClsid(clsidStorage);
+ }
+
/* ********** END implementation of DirectoryEntry ********** */
/* ********** START implementation of Entry ********** */
diff --git a/src/java/org/apache/poi/poifs/filesystem/POIFSFileSystem.java b/src/java/org/apache/poi/poifs/filesystem/POIFSFileSystem.java
index 3d173aa46e..3a62e3e1f0 100644
--- a/src/java/org/apache/poi/poifs/filesystem/POIFSFileSystem.java
+++ b/src/java/org/apache/poi/poifs/filesystem/POIFSFileSystem.java
@@ -423,6 +423,8 @@ public class POIFSFileSystem
DirectoryNode new_dir =
( DirectoryNode ) parent.createDirectory(name);
+ new_dir.setStorageClsid( property.getStorageClsid() );
+
processProperties(
small_blocks, big_blocks,
(( DirectoryProperty ) property).getChildren(), new_dir);
diff --git a/src/java/org/apache/poi/poifs/property/Property.java b/src/java/org/apache/poi/poifs/property/Property.java
index 6811a72508..c09c25619b 100644
--- a/src/java/org/apache/poi/poifs/property/Property.java
+++ b/src/java/org/apache/poi/poifs/property/Property.java
@@ -59,6 +59,8 @@ import java.io.*;
import java.util.*;
+import org.apache.poi.hpsf.ClassID;
+
import org.apache.poi.poifs.common.POIFSConstants;
import org.apache.poi.poifs.dev.POIFSViewable;
import org.apache.poi.util.ByteField;
@@ -87,6 +89,8 @@ public abstract class Property
static final private int _previous_property_offset = 0x44;
static final private int _next_property_offset = 0x48;
static final private int _child_property_offset = 0x4C;
+ static final private int _storage_clsid_offset = 0x50;
+ static final private int _user_flags_offset = 0x60;
static final private int _seconds_1_offset = 0x64;
static final private int _days_1_offset = 0x68;
static final private int _seconds_2_offset = 0x6C;
@@ -107,6 +111,8 @@ public abstract class Property
private IntegerField _previous_property;
private IntegerField _next_property;
private IntegerField _child_property;
+ private ClassID _storage_clsid;
+ private IntegerField _user_flags;
private IntegerField _seconds_1;
private IntegerField _days_1;
private IntegerField _seconds_2;
@@ -136,6 +142,8 @@ public abstract class Property
_NO_INDEX, _raw_data);
_child_property = new IntegerField(_child_property_offset,
_NO_INDEX, _raw_data);
+ _storage_clsid = new ClassID(_raw_data,_storage_clsid_offset);
+ _user_flags = new IntegerField(_user_flags_offset, 0, _raw_data);
_seconds_1 = new IntegerField(_seconds_1_offset, 0,
_raw_data);
_days_1 = new IntegerField(_days_1_offset, 0, _raw_data);
@@ -173,6 +181,8 @@ public abstract class Property
_raw_data);
_child_property = new IntegerField(_child_property_offset,
_raw_data);
+ _storage_clsid = new ClassID(_raw_data,_storage_clsid_offset);
+ _user_flags = new IntegerField(_user_flags_offset, 0, _raw_data);
_seconds_1 = new IntegerField(_seconds_1_offset, _raw_data);
_days_1 = new IntegerField(_days_1_offset, _raw_data);
_seconds_2 = new IntegerField(_seconds_2_offset, _raw_data);
@@ -295,12 +305,21 @@ public abstract class Property
abstract public boolean isDirectory();
+ /**
+ * Sets the storage clsid, which is the Class ID of a COM object which
+ * reads and writes this stream
+ * @return storage Class ID for this property stream
+ */
+ public ClassID getStorageClsid()
+ {
+ return _storage_clsid;
+ }
+
/**
* Set the name; silently truncates the name if it's too long.
*
* @param name the new name
*/
-
protected final void setName(final String name)
{
char[] char_array = name.toCharArray();
@@ -327,6 +346,20 @@ public abstract class Property
* LittleEndianConsts.SHORT_SIZE), _raw_data);
}
+ /**
+ * Sets the storage class ID for this property stream. This is the Class ID
+ * of the COM object which can read and write this property stream
+ * @param clsidStorage Storage Class ID
+ */
+ public void setStorageClsid( ClassID clsidStorage)
+ {
+ _storage_clsid = clsidStorage;
+ if( clsidStorage == null) {
+ Arrays.fill( _raw_data, _storage_clsid_offset, _storage_clsid_offset + ClassID.LENGTH, (byte) 0);
+ } else {
+ clsidStorage.write( _raw_data, _storage_clsid_offset);
+ }
+ }
/**
* Set the property type. Makes no attempt to validate the value.
*
diff --git a/src/java/org/apache/poi/poifs/storage/DocumentBlock.java b/src/java/org/apache/poi/poifs/storage/DocumentBlock.java
index f6d0d92b4d..7af3487faa 100644
--- a/src/java/org/apache/poi/poifs/storage/DocumentBlock.java
+++ b/src/java/org/apache/poi/poifs/storage/DocumentBlock.java
@@ -62,6 +62,7 @@ import java.io.OutputStream;
import java.util.Arrays;
import org.apache.poi.poifs.common.POIFSConstants;
+import org.apache.poi.util.IOUtils;
import org.apache.poi.util.IntegerField;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.LittleEndianConsts;
@@ -106,7 +107,7 @@ public class DocumentBlock
throws IOException
{
this();
- int count = stream.read(_data);
+ int count = IOUtils.readFully(stream, _data);
_bytes_read = (count == -1) ? 0
: count;
diff --git a/src/java/org/apache/poi/poifs/storage/HeaderBlockReader.java b/src/java/org/apache/poi/poifs/storage/HeaderBlockReader.java
index 015d455d22..ad77368512 100644
--- a/src/java/org/apache/poi/poifs/storage/HeaderBlockReader.java
+++ b/src/java/org/apache/poi/poifs/storage/HeaderBlockReader.java
@@ -60,6 +60,7 @@ import java.io.*;
import java.util.*;
import org.apache.poi.poifs.common.POIFSConstants;
+import org.apache.poi.util.IOUtils;
import org.apache.poi.util.IntegerField;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.LittleEndianConsts;
@@ -104,7 +105,7 @@ public class HeaderBlockReader
throws IOException
{
_data = new byte[ POIFSConstants.BIG_BLOCK_SIZE ];
- int byte_count = stream.read(_data);
+ int byte_count = IOUtils.readFully(stream, _data);
if (byte_count != POIFSConstants.BIG_BLOCK_SIZE)
{
diff --git a/src/java/org/apache/poi/poifs/storage/RawDataBlock.java b/src/java/org/apache/poi/poifs/storage/RawDataBlock.java
index 862fd8ca25..863b6108e7 100644
--- a/src/java/org/apache/poi/poifs/storage/RawDataBlock.java
+++ b/src/java/org/apache/poi/poifs/storage/RawDataBlock.java
@@ -56,6 +56,7 @@
package org.apache.poi.poifs.storage;
import org.apache.poi.poifs.common.POIFSConstants;
+import org.apache.poi.util.IOUtils;
import java.io.*;
@@ -84,7 +85,7 @@ public class RawDataBlock
throws IOException
{
_data = new byte[ POIFSConstants.BIG_BLOCK_SIZE ];
- int count = stream.read(_data);
+ int count = IOUtils.readFully(stream, _data);
if (count == -1)
{
diff --git a/src/java/org/apache/poi/util/HexDump.java b/src/java/org/apache/poi/util/HexDump.java
index bc846459d1..74198bc525 100644
--- a/src/java/org/apache/poi/util/HexDump.java
+++ b/src/java/org/apache/poi/util/HexDump.java
@@ -67,6 +67,20 @@ import java.io.*;
public class HexDump
{
+ public static final String EOL =
+ System.getProperty("line.separator");
+// private static final StringBuffer _lbuffer = new StringBuffer(8);
+// private static final StringBuffer _cbuffer = new StringBuffer(2);
+ private static final char _hexcodes[] =
+ {
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D',
+ 'E', 'F'
+ };
+ private static final int _shifts[] =
+ {
+ 28, 24, 20, 16, 12, 8, 4, 0
+ };
+
// all static methods, so no need for a public constructor
private HexDump()
@@ -95,12 +109,14 @@ public class HexDump
throws IOException, ArrayIndexOutOfBoundsException,
IllegalArgumentException
{
- if ((index < 0) || (index >= data.length))
+ if ((index < 0) || (data.length != 0 && index >= data.length))
{
throw new ArrayIndexOutOfBoundsException(
"illegal index: " + index + " into array of length "
+ data.length);
}
+ if (data.length == 0)
+ return; // nothing more to do.
if (stream == null)
{
throw new IllegalArgumentException("cannot write to nullstream");
@@ -241,39 +257,26 @@ public class HexDump
}
- public static final String EOL =
- System.getProperty("line.separator");
- private static final StringBuffer _lbuffer = new StringBuffer(8);
- private static final StringBuffer _cbuffer = new StringBuffer(2);
- private static final char _hexcodes[] =
- {
- '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D',
- 'E', 'F'
- };
- private static final int _shifts[] =
- {
- 28, 24, 20, 16, 12, 8, 4, 0
- };
-
private static String dump(final long value)
{
- _lbuffer.setLength(0);
+ StringBuffer buf = new StringBuffer();
+ buf.setLength(0);
for (int j = 0; j < 8; j++)
{
- _lbuffer
- .append(_hexcodes[ (( int ) (value >> _shifts[ j ])) & 15 ]);
+ buf.append( _hexcodes[ (( int ) (value >> _shifts[ j ])) & 15 ]);
}
- return _lbuffer.toString();
+ return buf.toString();
}
private static String dump(final byte value)
{
- _cbuffer.setLength(0);
+ StringBuffer buf = new StringBuffer();
+ buf.setLength(0);
for (int j = 0; j < 2; j++)
{
- _cbuffer.append(_hexcodes[ (value >> _shifts[ j + 6 ]) & 15 ]);
+ buf.append(_hexcodes[ (value >> _shifts[ j + 6 ]) & 15 ]);
}
- return _cbuffer.toString();
+ return buf.toString();
}
/**
@@ -294,6 +297,7 @@ public class HexDump
retVal.append(']');
return retVal.toString();
}
+
/**
* Converts the parameter to a hex value.
*
@@ -337,4 +341,41 @@ public class HexDump
}
return result.toString();
}
+
+ /**
+ * Dumps bytesToDump bytes to an output stream.
+ *
+ * @param in The stream to read from
+ * @param out The output stream
+ * @param start The index to use as the starting position for the left hand side label
+ * @param bytesToDump The number of bytes to output. Use -1 to read until the end of file.
+ */
+ public static void dump( InputStream in, PrintStream out, int start, int bytesToDump ) throws IOException
+ {
+ ByteArrayOutputStream buf = new ByteArrayOutputStream();
+ if (bytesToDump == -1)
+ {
+ int c = in.read();
+ while (c != -1)
+ {
+ buf.write(c);
+ c = in.read();
+ }
+ }
+ else
+ {
+ int bytesRemaining = bytesToDump;
+ while (bytesRemaining-- > 0)
+ {
+ int c = in.read();
+ if (c == -1)
+ break;
+ else
+ buf.write(c);
+ }
+ }
+
+ byte[] data = buf.toByteArray();
+ dump(data, 0, out, start, data.length);
+ }
}
diff --git a/src/java/org/apache/poi/util/HexRead.java b/src/java/org/apache/poi/util/HexRead.java
index 0be7930a7b..6c5eceb125 100644
--- a/src/java/org/apache/poi/util/HexRead.java
+++ b/src/java/org/apache/poi/util/HexRead.java
@@ -1 +1,225 @@
-/* ==================================================================== * The Apache Software License, Version 1.1 * * Copyright (c) 2003 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Apache" and "Apache Software Foundation" and * "Apache POI" must not be used to endorse or promote products * derived from this software without prior written permission. For * written permission, please contact apache@apache.org. * * 5. Products derived from this software may not be called "Apache", * "Apache POI", nor may "Apache" appear in their name, without * prior written permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see *
* [sectioname] ** * @see #readData(String) */ public static byte[] readData(String filename, String section) throws IOException { File file = new File( filename ); FileInputStream stream = new FileInputStream( file ); try { StringBuffer sectionText = new StringBuffer(); boolean inSection = false; int c = stream.read(); while (c != -1) { switch(c) { case '[': inSection = true; break; case '\n': case '\r': inSection = false; sectionText = new StringBuffer(); break; case ']': inSection = false; if (sectionText.toString().equals(section)) return readData(stream, '['); sectionText = new StringBuffer(); break; default: if (inSection) sectionText.append((char)c); } c = stream.read(); } } finally { stream.close(); } throw new IOException("Section '" + section + "' not found"); } static private byte[] readData( FileInputStream stream, int eofChar ) throws IOException { int characterCount = 0; byte b = (byte) 0; List bytes = new ArrayList(); boolean done = false; while ( !done ) { int count = stream.read(); char baseChar = 'a'; if ( count == eofChar) break; switch ( count ) { case '#': readToEOL(stream); break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': b <<= 4; b += (byte) ( count - '0' ); characterCount++; if ( characterCount == 2 ) { bytes.add( new Byte( b ) ); characterCount = 0; b = (byte) 0; } break; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': baseChar = 'A'; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': b <<= 4; b += (byte) ( count + 10 - baseChar ); characterCount++; if ( characterCount == 2 ) { bytes.add( new Byte( b ) ); characterCount = 0; b = (byte) 0; } break; case -1: done = true; break; default : break; } } Byte[] polished = (Byte[]) bytes.toArray( new Byte[0] ); byte[] rval = new byte[polished.length]; for ( int j = 0; j < polished.length; j++ ) { rval[j] = polished[j].byteValue(); } return rval; } static private void readToEOL( InputStream stream ) throws IOException { int c = stream.read(); while ( c != -1 && c != '\n' && c != '\r') { c = stream.read(); } }} \ No newline at end of file +/* ==================================================================== + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2002 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Apache" and "Apache Software Foundation" and + * "Apache POI" must not be used to endorse or promote products + * derived from this software without prior written permission. For + * written permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", + * "Apache POI", nor may "Apache" appear in their name, without + * prior written permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + *
+ * [sectioname] + *+ * + * @see #readData(String) + */ + public static byte[] readData( String filename, String section ) throws IOException + { + File file = new File( filename ); + FileInputStream stream = new FileInputStream( file ); + try + { + StringBuffer sectionText = new StringBuffer(); + boolean inSection = false; + int c = stream.read(); + while ( c != -1 ) + { + switch ( c ) + { + case '[': + inSection = true; + break; + case '\n': + case '\r': + inSection = false; + sectionText = new StringBuffer(); + break; + case ']': + inSection = false; + if ( sectionText.toString().equals( section ) ) return readData( stream, '[' ); + sectionText = new StringBuffer(); + break; + default: + if ( inSection ) sectionText.append( (char) c ); + } + c = stream.read(); + } + } + finally + { + stream.close(); + } + throw new IOException( "Section '" + section + "' not found" ); + } + + static public byte[] readData( InputStream stream, int eofChar ) throws IOException + { + int characterCount = 0; + byte b = (byte) 0; + List bytes = new ArrayList(); + boolean done = false; + while ( !done ) + { + int count = stream.read(); + char baseChar = 'a'; + if ( count == eofChar ) break; + switch ( count ) + { + case '#': + readToEOL( stream ); + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + b <<= 4; + b += (byte) ( count - '0' ); + characterCount++; + if ( characterCount == 2 ) + { + bytes.add( new Byte( b ) ); + characterCount = 0; + b = (byte) 0; + } + break; + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + baseChar = 'A'; + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + b <<= 4; + b += (byte) ( count + 10 - baseChar ); + characterCount++; + if ( characterCount == 2 ) + { + bytes.add( new Byte( b ) ); + characterCount = 0; + b = (byte) 0; + } + break; + case -1: + done = true; + break; + default : + break; + } + } + Byte[] polished = (Byte[]) bytes.toArray( new Byte[0] ); + byte[] rval = new byte[polished.length]; + for ( int j = 0; j < polished.length; j++ ) + { + rval[j] = polished[j].byteValue(); + } + return rval; + } + + static public byte[] readFromString(String data) throws IOException + { + return readData(new ByteArrayInputStream( data.getBytes() ), -1); + } + + static private void readToEOL( InputStream stream ) throws IOException + { + int c = stream.read(); + while ( c != -1 && c != '\n' && c != '\r' ) + { + c = stream.read(); + } + } +} \ No newline at end of file diff --git a/src/java/org/apache/poi/util/IOUtils.java b/src/java/org/apache/poi/util/IOUtils.java new file mode 100644 index 0000000000..06089b00d7 --- /dev/null +++ b/src/java/org/apache/poi/util/IOUtils.java @@ -0,0 +1,99 @@ + +/* ==================================================================== + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2002 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Apache" and "Apache Software Foundation" and + * "Apache POI" must not be used to endorse or promote products + * derived from this software without prior written permission. For + * written permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", + * "Apache POI", nor may "Apache" appear in their name, without + * prior written permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + *
+ * If the end of file is reached before any bytes are read, returns -1. + * Otherwise, returns the number of bytes read. + */ + public static int readFully(InputStream in, byte[] b, int off, int len) + throws IOException + { + int total = 0; + for (;;) { + int got = in.read(b, off + total, len - total); + if (got < 0) { + return (total == 0) ? -1 : total; + } else { + total += got; + if (total == len) + return total; + } + } + } +} + diff --git a/src/java/org/apache/poi/util/LittleEndian.java b/src/java/org/apache/poi/util/LittleEndian.java index 0f525c156d..4c4b51a011 100644 --- a/src/java/org/apache/poi/util/LittleEndian.java +++ b/src/java/org/apache/poi/util/LittleEndian.java @@ -475,23 +475,10 @@ public class LittleEndian return getLong(readFromStream(stream, LONG_SIZE)); } - - private final static byte[] _short_buffer = new byte[SHORT_SIZE]; - private final static byte[] _int_buffer = new byte[INT_SIZE]; - private final static byte[] _long_buffer = new byte[LONG_SIZE]; - - /** * Read the appropriate number of bytes from the stream and return them to * the caller.
* - * It should be noted that, in an attempt to improve system performance and - * to prevent a transient explosion of discarded byte arrays to be garbage - * collected, static byte arrays are employed for the standard cases of - * reading a short, an int, or a long.
- * - * THIS INTRODUCES A RISK FOR THREADED OPERATIONS!
- *
* However, for the purposes of the POI project, this risk is deemed
* negligible. It is, however, so noted.
*
@@ -510,23 +497,8 @@ public class LittleEndian
public static byte[] readFromStream(final InputStream stream,
final int size)
throws IOException, BufferUnderrunException {
- byte[] buffer = null;
+ byte[] buffer = new byte[size];
- switch (size) {
-
- case SHORT_SIZE:
- buffer = _short_buffer;
- break;
- case INT_SIZE:
- buffer = _int_buffer;
- break;
- case LONG_SIZE:
- buffer = _long_buffer;
- break;
- default:
- buffer = new byte[size];
- break;
- }
int count = stream.read(buffer);
if (count == -1) {
diff --git a/src/java/org/apache/poi/util/StringUtil.java b/src/java/org/apache/poi/util/StringUtil.java
index 845854e599..a2ef1247da 100644
--- a/src/java/org/apache/poi/util/StringUtil.java
+++ b/src/java/org/apache/poi/util/StringUtil.java
@@ -1 +1,363 @@
-/* * ==================================================================== * The Apache Software License, Version 1.1 * * Copyright (c) 2003 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Apache" and "Apache Software Foundation" and * "Apache POI" must not be used to endorse or promote products * derived from this software without prior written permission. For * written permission, please contact apache@apache.org. * * 5. Products derived from this software may not be called "Apache", * "Apache POI", nor may "Apache" appear in their name, without * prior written permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see *
+ * message. * * @author Marc Johnson (mjohnson at apache dot org) * @author Glen Stampoultzis (glens at apache.org) * @author Nicola Ken Barozzi (nicolaken at apache.org) */ - public class SystemOutLogger extends POILogger { private String cat; @@ -88,19 +87,27 @@ public class SystemOutLogger extends POILogger public void log(final int level, final Object obj1) { - System.out.println("["+cat+"] "+obj1); + if (check(level)) + System.out.println("["+cat+"] "+obj1); } /** * Check if a logger is enabled to log at the specified level * * @param level One of DEBUG, INFO, WARN, ERROR, FATAL - * @param obj1 The logger to check. + * @see #DEBUG + * @see #INFO + * @see #WARN + * @see #ERROR + * @see #FATAL */ - public boolean check(final int level) { - return true; + int currentLevel = Integer.parseInt(System.getProperty("poi.log.level", WARN + "")); + if (level >= currentLevel) + return true; + else + return false; } diff --git a/src/testcases/org/apache/poi/hpsf/basic/POIFile.java b/src/testcases/org/apache/poi/hpsf/basic/POIFile.java index 9786f35866..288242f1c4 100644 --- a/src/testcases/org/apache/poi/hpsf/basic/POIFile.java +++ b/src/testcases/org/apache/poi/hpsf/basic/POIFile.java @@ -53,7 +53,8 @@ */ package org.apache.poi.hpsf.basic; -import org.apache.poi.poifs.filesystem.*; + +import org.apache.poi.poifs.filesystem.POIFSDocumentPath; @@ -73,32 +74,32 @@ public class POIFile public void setName(final String name) { - this.name = name; + this.name = name; } public String getName() { - return name; + return name; } public void setPath(final POIFSDocumentPath path) { - this.path = path; + this.path = path; } public POIFSDocumentPath getPath() { - return path; + return path; } public void setBytes(final byte[] bytes) { - this.bytes = bytes; + this.bytes = bytes; } public byte[] getBytes() { - return bytes; + return bytes; } } diff --git a/src/testcases/org/apache/poi/hpsf/basic/TestBasic.java b/src/testcases/org/apache/poi/hpsf/basic/TestBasic.java index 474489b638..0357c5a233 100644 --- a/src/testcases/org/apache/poi/hpsf/basic/TestBasic.java +++ b/src/testcases/org/apache/poi/hpsf/basic/TestBasic.java @@ -54,10 +54,23 @@ package org.apache.poi.hpsf.basic; -import java.io.*; -import java.util.*; -import junit.framework.*; -import org.apache.poi.hpsf.*; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; + +import junit.framework.Assert; +import junit.framework.TestCase; + +import org.apache.poi.hpsf.DocumentSummaryInformation; +import org.apache.poi.hpsf.HPSFException; +import org.apache.poi.hpsf.MarkUnsupportedException; +import org.apache.poi.hpsf.NoPropertySetStreamException; +import org.apache.poi.hpsf.PropertySet; +import org.apache.poi.hpsf.PropertySetFactory; +import org.apache.poi.hpsf.SummaryInformation; +import org.apache.poi.hpsf.UnexpectedPropertySetTypeException; @@ -71,37 +84,37 @@ import org.apache.poi.hpsf.*; public class TestBasic extends TestCase { - final static String POI_FS = "TestGermanWord90.doc"; - final static String[] POI_FILES = new String[] - { - "\005SummaryInformation", - "\005DocumentSummaryInformation", - "WordDocument", - "\001CompObj", - "1Table" - }; - final static int BYTE_ORDER = 0xfffe; - final static int FORMAT = 0x0000; - final static int OS_VERSION = 0x00020A04; - final static byte[] CLASS_ID = - { - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 - }; - final static int[] SECTION_COUNT = + static final String POI_FS = "TestGermanWord90.doc"; + static final String[] POI_FILES = new String[] + { + "\005SummaryInformation", + "\005DocumentSummaryInformation", + "WordDocument", + "\001CompObj", + "1Table" + }; + static final int BYTE_ORDER = 0xfffe; + static final int FORMAT = 0x0000; + static final int OS_VERSION = 0x00020A04; + static final byte[] CLASS_ID = + { + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 + }; + static final int[] SECTION_COUNT = {1, 2}; - final static boolean[] IS_SUMMARY_INFORMATION = + static final boolean[] IS_SUMMARY_INFORMATION = {true, false}; - final static boolean[] IS_DOCUMENT_SUMMARY_INFORMATION = - {false, true}; + static final boolean[] IS_DOCUMENT_SUMMARY_INFORMATION = + {false, true}; POIFile[] poiFiles; - public TestBasic(String name) + public TestBasic(final String name) { super(name); } @@ -113,11 +126,11 @@ public class TestBasic extends TestCase */ public void setUp() throws FileNotFoundException, IOException { - final File dataDir = - new File(System.getProperty("HPSF.testdata.path")); - final File data = new File(dataDir, POI_FS); + final File dataDir = + new File(System.getProperty("HPSF.testdata.path")); + final File data = new File(dataDir, POI_FS); - poiFiles = Util.readPOIFiles(data); + poiFiles = Util.readPOIFiles(data); } @@ -128,9 +141,9 @@ public class TestBasic extends TestCase */ public void testReadFiles() throws IOException { - String[] expected = POI_FILES; - for (int i = 0; i < expected.length; i++) - Assert.assertEquals(poiFiles[i].getName(), expected[i]); + String[] expected = POI_FILES; + for (int i = 0; i < expected.length; i++) + Assert.assertEquals(poiFiles[i].getName(), expected[i]); } @@ -146,37 +159,37 @@ public class TestBasic extends TestCase */ public void testCreatePropertySets() throws IOException { - Class[] expected = new Class[] - { - SummaryInformation.class, - DocumentSummaryInformation.class, - NoPropertySetStreamException.class, - NoPropertySetStreamException.class, - NoPropertySetStreamException.class - }; - for (int i = 0; i < expected.length; i++) - { - InputStream in = new ByteArrayInputStream(poiFiles[i].getBytes()); - Object o; - try - { - o = PropertySetFactory.create(in); - } - catch (NoPropertySetStreamException ex) - { - o = ex; - } - catch (UnexpectedPropertySetTypeException ex) - { - o = ex; - } - catch (MarkUnsupportedException ex) - { - o = ex; - } - in.close(); - Assert.assertEquals(o.getClass(), expected[i]); - } + Class[] expected = new Class[] + { + SummaryInformation.class, + DocumentSummaryInformation.class, + NoPropertySetStreamException.class, + NoPropertySetStreamException.class, + NoPropertySetStreamException.class + }; + for (int i = 0; i < expected.length; i++) + { + InputStream in = new ByteArrayInputStream(poiFiles[i].getBytes()); + Object o; + try + { + o = PropertySetFactory.create(in); + } + catch (NoPropertySetStreamException ex) + { + o = ex; + } + catch (UnexpectedPropertySetTypeException ex) + { + o = ex; + } + catch (MarkUnsupportedException ex) + { + o = ex; + } + in.close(); + Assert.assertEquals(o.getClass(), expected[i]); + } } @@ -188,25 +201,24 @@ public class TestBasic extends TestCase */ public void testPropertySetMethods() throws IOException, HPSFException { - String[] expected = POI_FILES; - /* Loop over the two property sets. */ - for (int i = 0; i < 2; i++) - { - byte[] b = poiFiles[i].getBytes(); - PropertySet ps = - PropertySetFactory.create(new ByteArrayInputStream(b)); - Assert.assertEquals(ps.getByteOrder(), BYTE_ORDER); - Assert.assertEquals(ps.getFormat(), FORMAT); - Assert.assertEquals(ps.getOSVersion(), OS_VERSION); - Assert.assertEquals(new String(ps.getClassID().getBytes()), - new String(CLASS_ID)); - Assert.assertEquals(ps.getSectionCount(), SECTION_COUNT[i]); - Assert.assertEquals(ps.isSummaryInformation(), - IS_SUMMARY_INFORMATION[i]); - Assert.assertEquals(ps.isDocumentSummaryInformation(), - IS_DOCUMENT_SUMMARY_INFORMATION[i]); - } + /* Loop over the two property sets. */ + for (int i = 0; i < 2; i++) + { + byte[] b = poiFiles[i].getBytes(); + PropertySet ps = + PropertySetFactory.create(new ByteArrayInputStream(b)); + Assert.assertEquals(ps.getByteOrder(), BYTE_ORDER); + Assert.assertEquals(ps.getFormat(), FORMAT); + Assert.assertEquals(ps.getOSVersion(), OS_VERSION); + Assert.assertEquals(new String(ps.getClassID().getBytes()), + new String(CLASS_ID)); + Assert.assertEquals(ps.getSectionCount(), SECTION_COUNT[i]); + Assert.assertEquals(ps.isSummaryInformation(), + IS_SUMMARY_INFORMATION[i]); + Assert.assertEquals(ps.isDocumentSummaryInformation(), + IS_DOCUMENT_SUMMARY_INFORMATION[i]); + } } @@ -214,11 +226,11 @@ public class TestBasic extends TestCase /** *
Runs the test cases stand-alone.
*/ - public static void main(String[] args) throws Throwable + public static void main(final String[] args) throws Throwable { - System.setProperty("HPSF.testdata.path", - "./src/testcases/org/apache/poi/hpsf/data"); - junit.textui.TestRunner.run(TestBasic.class); + System.setProperty("HPSF.testdata.path", + "./src/testcases/org/apache/poi/hpsf/data"); + junit.textui.TestRunner.run(TestBasic.class); } } diff --git a/src/testcases/org/apache/poi/hpsf/basic/TestClassID.java b/src/testcases/org/apache/poi/hpsf/basic/TestClassID.java new file mode 100644 index 0000000000..c36f8161ec --- /dev/null +++ b/src/testcases/org/apache/poi/hpsf/basic/TestClassID.java @@ -0,0 +1,171 @@ +/* ==================================================================== + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2003 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Apache" and "Apache Software Foundation" and + * "Apache POI" must not be used to endorse or promote products + * derived from this software without prior written permission. For + * written permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", + * "Apache POI", nor may "Apache" appear in their name, without + * prior written permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + *Tests ClassID structure.
+ * + * @author Michael Zalewski (zalewski@optonline.net) + */ +public class TestClassID extends TestCase +{ + /** + *Constructor
+ * + * @param name the test case's name + */ + public TestClassID(final String name) + { + super(name); + } + + /** + * Various tests of overridden .equals() + */ + public void testEquals() + { + ClassID clsidTest1 = new ClassID( + new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 + , 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 } + , 0 + ); + ClassID clsidTest2 = new ClassID( + new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 + , 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 } + , 0 + ); + ClassID clsidTest3 = new ClassID( + new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 + , 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x11 } + , 0 + ); + Assert.assertEquals( clsidTest1, clsidTest1); + Assert.assertEquals( clsidTest1, clsidTest2); + Assert.assertFalse( clsidTest1.equals( clsidTest3)); + Assert.assertFalse( clsidTest1.equals( null)); + } + /** + * Try to write to a buffer that is too small. This should + * throw an Exception + */ + public void testWriteArrayStoreException() + { + ClassID clsidTest = new ClassID( + new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 + , 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 } + , 0 + ); + boolean bExceptionOccurred = false; + try { + clsidTest.write( new byte[ 15], 0); + } catch( Exception e) { + bExceptionOccurred = true; + } + Assert.assertTrue( bExceptionOccurred); + + bExceptionOccurred = false; + try { + clsidTest.write( new byte[ 16], 1); + } catch( Exception e) { + bExceptionOccurred = true; + } + Assert.assertTrue( bExceptionOccurred); + + // These should work without throwing an Exception + bExceptionOccurred = false; + try { + clsidTest.write( new byte[ 16], 0); + clsidTest.write( new byte[ 17], 1); + } catch( Exception e) { + bExceptionOccurred = true; + } + Assert.assertFalse( bExceptionOccurred); + } + /** + *Tests the {@link PropertySet} methods. The test file has two + * property set: the first one is a {@link SummaryInformation}, + * the second one is a {@link DocumentSummaryInformation}.
+ */ + public void testClassID() + { + ClassID clsidTest = new ClassID( + new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 + , 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 } + , 0 + ); + Assert.assertEquals( + clsidTest.toString().toUpperCase() + , "{04030201-0605-0807-090A-0B0C0D0E0F10}" + ); + } + + + + /** + *Runs the test cases stand-alone.
+ */ + public static void main(final String[] args) + { + System.setProperty("HPSF.testdata.path", + "./src/testcases/org/apache/poi/hpsf/data"); + junit.textui.TestRunner.run(TestClassID.class); + } + +} diff --git a/src/testcases/org/apache/poi/hpsf/basic/TestEmptyProperties.java b/src/testcases/org/apache/poi/hpsf/basic/TestEmptyProperties.java new file mode 100644 index 0000000000..fbe9fbf7f9 --- /dev/null +++ b/src/testcases/org/apache/poi/hpsf/basic/TestEmptyProperties.java @@ -0,0 +1,189 @@ +package org.apache.poi.hpsf.basic; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; + +import junit.framework.Assert; +import junit.framework.TestCase; + +import org.apache.poi.hpsf.HPSFException; +import org.apache.poi.hpsf.MarkUnsupportedException; +import org.apache.poi.hpsf.NoPropertySetStreamException; +import org.apache.poi.hpsf.PropertySet; +import org.apache.poi.hpsf.PropertySetFactory; +import org.apache.poi.hpsf.SummaryInformation; +import org.apache.poi.hpsf.UnexpectedPropertySetTypeException; + +/** + *Test case for OLE2 files with empty properties. An empty property's type + * is {@link Variant.VT_EMPTY}.
+ * + * @author Rainer Klute <klute@rainer-klute.de> + * @since 2003-07-25 + * @version $Id$ + */ +public class TestEmptyProperties extends TestCase +{ + + /** + *This test file's summary information stream contains some empty + * properties.
+ */ + static final String POI_FS = "TestCorel.shw"; + + static final String[] POI_FILES = new String[] + { + "PerfectOffice_MAIN", + "\005SummaryInformation", + "Main" + }; + + POIFile[] poiFiles; + + + + /** + *Constructor
+ * + * @param name The name of the test case + */ + public TestEmptyProperties(final String name) + { + super(name); + } + + + + /** + *Read a the test file from the "data" directory.
+ * + * @exception FileNotFoundException if the file containing the test data + * does not exist + * @exception IOException if an I/O exception occurs + */ + public void setUp() throws FileNotFoundException, IOException + { + final File dataDir = + new File(System.getProperty("HPSF.testdata.path")); + final File data = new File(dataDir, POI_FS); + + poiFiles = Util.readPOIFiles(data); + } + + + + /** + *Checks the names of the files in the POI filesystem. They + * are expected to be in a certain order.
+ * + * @exception IOException if an I/O exception occurs + */ + public void testReadFiles() throws IOException + { + String[] expected = POI_FILES; + for (int i = 0; i < expected.length; i++) + Assert.assertEquals(poiFiles[i].getName(), expected[i]); + } + + + + /** + *Tests whether property sets can be created from the POI + * files in the POI file system. This test case expects the first + * file to be a {@link SummaryInformation}, the second file to be + * a {@link DocumentSummaryInformation} and the rest to be no + * property sets. In the latter cases a {@link + * NoPropertySetStreamException} will be thrown when trying to + * create a {@link PropertySet}.
+ * + * @exception IOException if an I/O exception occurs + */ + public void testCreatePropertySets() throws IOException + { + Class[] expected = new Class[] + { + NoPropertySetStreamException.class, + SummaryInformation.class, + NoPropertySetStreamException.class + }; + for (int i = 0; i < expected.length; i++) + { + InputStream in = new ByteArrayInputStream(poiFiles[i].getBytes()); + Object o; + try + { + o = PropertySetFactory.create(in); + } + catch (NoPropertySetStreamException ex) + { + o = ex; + } + catch (UnexpectedPropertySetTypeException ex) + { + o = ex; + } + catch (MarkUnsupportedException ex) + { + o = ex; + } + in.close(); + Assert.assertEquals(o.getClass(), expected[i]); + } + } + + + + /** + *Tests the {@link PropertySet} methods. The test file has two + * property sets: the first one is a {@link SummaryInformation}, + * the second one is a {@link DocumentSummaryInformation}.
+ * + * @exception IOException if an I/O exception occurs + * @exception HPSFException if an HPSF operation fails + */ + public void testPropertySetMethods() throws IOException, HPSFException + { + byte[] b = poiFiles[1].getBytes(); + PropertySet ps = + PropertySetFactory.create(new ByteArrayInputStream(b)); + SummaryInformation s = (SummaryInformation) ps; + assertNull(s.getTitle()); + assertNull(s.getSubject()); + assertNotNull(s.getAuthor()); + assertNull(s.getKeywords()); + assertNull(s.getComments()); + assertNotNull(s.getTemplate()); + assertNotNull(s.getLastAuthor()); + assertNotNull(s.getRevNumber()); + assertNull(s.getEditTime()); + assertNull(s.getLastPrinted()); + assertNull(s.getCreateDateTime()); + assertNull(s.getLastSaveDateTime()); + assertEquals(s.getPageCount(), 0); + assertEquals(s.getWordCount(), 0); + assertEquals(s.getCharCount(), 0); + assertNull(s.getThumbnail()); + assertNull(s.getApplicationName()); + } + + + + /** + *Runs the test cases stand-alone.
+ * + * @param args the command-line arguments (unused) + * + * @exception Throwable if any exception or error occurs + */ + public static void main(final String[] args) throws Throwable + { + System.setProperty("HPSF.testdata.path", + "./src/testcases/org/apache/poi/hpsf/data"); + junit.textui.TestRunner.run(TestBasic.class); + } + +} diff --git a/src/testcases/org/apache/poi/hpsf/basic/TestUnicode.java b/src/testcases/org/apache/poi/hpsf/basic/TestUnicode.java index b2c7b2ab50..cf3b351cc6 100644 --- a/src/testcases/org/apache/poi/hpsf/basic/TestUnicode.java +++ b/src/testcases/org/apache/poi/hpsf/basic/TestUnicode.java @@ -54,10 +54,18 @@ package org.apache.poi.hpsf.basic; -import java.io.*; -import java.util.*; -import junit.framework.*; -import org.apache.poi.hpsf.*; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; + +import junit.framework.Assert; +import junit.framework.TestCase; + +import org.apache.poi.hpsf.HPSFException; +import org.apache.poi.hpsf.PropertySet; +import org.apache.poi.hpsf.PropertySetFactory; +import org.apache.poi.hpsf.Section; @@ -72,17 +80,22 @@ import org.apache.poi.hpsf.*; public class TestUnicode extends TestCase { - final static String POI_FS = "TestUnicode.xls"; - final static String[] POI_FILES = new String[] - { - "\005DocumentSummaryInformation", - }; + static final String POI_FS = "TestUnicode.xls"; + static final String[] POI_FILES = new String[] + { + "\005DocumentSummaryInformation", + }; File data; POIFile[] poiFiles; - public TestUnicode(String name) + /** + *Constructor
+ * + * @param name the test case's name + */ + public TestUnicode(final String name) { super(name); } @@ -92,11 +105,11 @@ public class TestUnicode extends TestCase /** *Read a the test file from the "data" directory.
*/ - public void setUp() throws FileNotFoundException, IOException + protected void setUp() throws FileNotFoundException, IOException { - final File dataDir = - new File(System.getProperty("HPSF.testdata.path")); - data = new File(dataDir, POI_FS); + final File dataDir = + new File(System.getProperty("HPSF.testdata.path")); + data = new File(dataDir, POI_FS); } @@ -108,23 +121,23 @@ public class TestUnicode extends TestCase */ public void testPropertySetMethods() throws IOException, HPSFException { - POIFile poiFile = Util.readPOIFiles(data, POI_FILES)[0]; - byte[] b = poiFile.getBytes(); - PropertySet ps = - PropertySetFactory.create(new ByteArrayInputStream(b)); - Assert.assertTrue(ps.isDocumentSummaryInformation()); - Assert.assertEquals(ps.getSectionCount(), 2); - Section s = (Section) ps.getSections().get(1); - Assert.assertEquals(s.getProperty(1), - new Integer(1200)); - Assert.assertEquals(s.getProperty(2), - new Long(4198897018l)); - Assert.assertEquals(s.getProperty(3), - "MCon_Info zu Office bei Schreiner"); - Assert.assertEquals(s.getProperty(4), - "petrovitsch@schreiner-online.de"); - Assert.assertEquals(s.getProperty(5), - "Petrovitsch, Wilhelm"); + POIFile poiFile = Util.readPOIFiles(data, POI_FILES)[0]; + byte[] b = poiFile.getBytes(); + PropertySet ps = + PropertySetFactory.create(new ByteArrayInputStream(b)); + Assert.assertTrue(ps.isDocumentSummaryInformation()); + Assert.assertEquals(ps.getSectionCount(), 2); + Section s = (Section) ps.getSections().get(1); + Assert.assertEquals(s.getProperty(1), + new Integer(1200)); + Assert.assertEquals(s.getProperty(2), + new Long(4198897018L)); + Assert.assertEquals(s.getProperty(3), + "MCon_Info zu Office bei Schreiner"); + Assert.assertEquals(s.getProperty(4), + "petrovitsch@schreiner-online.de"); + Assert.assertEquals(s.getProperty(5), + "Petrovitsch, Wilhelm"); } @@ -132,10 +145,10 @@ public class TestUnicode extends TestCase /** *Runs the test cases stand-alone.
*/ - public static void main(String[] args) + public static void main(final String[] args) { - System.setProperty("HPSF.testdata.path", - "./src/testcases/org/apache/poi/hpsf/data"); + System.setProperty("HPSF.testdata.path", + "./src/testcases/org/apache/poi/hpsf/data"); junit.textui.TestRunner.run(TestUnicode.class); } diff --git a/src/testcases/org/apache/poi/hpsf/basic/Util.java b/src/testcases/org/apache/poi/hpsf/basic/Util.java index 87aaf216a7..7afd37194f 100644 --- a/src/testcases/org/apache/poi/hpsf/basic/Util.java +++ b/src/testcases/org/apache/poi/hpsf/basic/Util.java @@ -54,9 +54,24 @@ package org.apache.poi.hpsf.basic; -import java.io.*; -import java.util.*; -import org.apache.poi.poifs.eventfilesystem.*; +import java.io.ByteArrayOutputStream; +import java.io.EOFException; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Properties; + +import org.apache.poi.poifs.eventfilesystem.POIFSReader; +import org.apache.poi.poifs.eventfilesystem.POIFSReaderEvent; +import org.apache.poi.poifs.eventfilesystem.POIFSReaderListener; @@ -73,6 +88,9 @@ public class Util /** *Reads bytes from an input stream and writes them to an * output stream until end of file is encountered.
+ * + * @param in the input stream to read from + * @param out the output stream to write to */ public static void copy(final InputStream in, final OutputStream out) throws IOException @@ -88,8 +106,8 @@ public class Util read = in.read(b, 0, BUF_SIZE); if (read > 0) out.write(b, 0, read); - else - eof = true; + else + eof = true; } catch (EOFException ex) { @@ -106,16 +124,16 @@ public class Util * into memory and thus does not cope well with large POI * filessystems. * - * @param file The name of the POI filesystem as seen by the + * @param poiFs The name of the POI filesystem as seen by the * operating system. (This is the "filename".) * * @return The POI files. The elements are ordered in the same way * as the files in the POI filesystem. */ public static POIFile[] readPOIFiles(final File poiFs) - throws FileNotFoundException, IOException + throws FileNotFoundException, IOException { - return readPOIFiles(poiFs, null); + return readPOIFiles(poiFs, null); } @@ -126,7 +144,7 @@ public class Util * files into memory and thus does not cope well with large POI * filessystems. * - * @param file The name of the POI filesystem as seen by the + * @param poiFs The name of the POI filesystem as seen by the * operating system. (This is the "filename".) * * @param poiFiles The names of the POI files to be read. @@ -135,50 +153,49 @@ public class Util * as the files in the POI filesystem. */ public static POIFile[] readPOIFiles(final File poiFs, - final String[] poiFiles) - throws FileNotFoundException, IOException + final String[] poiFiles) + throws FileNotFoundException, IOException { - final List files = new ArrayList(); - POIFSReader r = new POIFSReader(); - POIFSReaderListener pfl = new POIFSReaderListener() - { - public void processPOIFSReaderEvent(POIFSReaderEvent event) - { - try - { - POIFile f = new POIFile(); - f.setName(event.getName()); - f.setPath(event.getPath()); - InputStream in = event.getStream(); - ByteArrayOutputStream out = - new ByteArrayOutputStream(); - Util.copy(in, out); - out.close(); - f.setBytes(out.toByteArray()); - files.add(f); - } - catch (IOException ex) - { - ex.printStackTrace(); - throw new RuntimeException(ex.getMessage()); - } - } - }; - if (poiFiles == null) - /* Register the listener for all POI files. */ - r.registerListener(pfl); - else - /* Register the listener for the specified POI files - * only. */ - for (int i = 0; i < poiFiles.length; i++) - r.registerListener(pfl, poiFiles[i]); + final List files = new ArrayList(); + POIFSReader r = new POIFSReader(); + POIFSReaderListener pfl = new POIFSReaderListener() + { + public void processPOIFSReaderEvent(final POIFSReaderEvent event) + { + try + { + POIFile f = new POIFile(); + f.setName(event.getName()); + f.setPath(event.getPath()); + InputStream in = event.getStream(); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + Util.copy(in, out); + out.close(); + f.setBytes(out.toByteArray()); + files.add(f); + } + catch (IOException ex) + { + ex.printStackTrace(); + throw new RuntimeException(ex.getMessage()); + } + } + }; + if (poiFiles == null) + /* Register the listener for all POI files. */ + r.registerListener(pfl); + else + /* Register the listener for the specified POI files + * only. */ + for (int i = 0; i < poiFiles.length; i++) + r.registerListener(pfl, poiFiles[i]); - /* Read the POI filesystem. */ - r.read(new FileInputStream(poiFs)); - POIFile[] result = new POIFile[files.size()]; - for (int i = 0; i < result.length; i++) - result[i] = (POIFile) files.get(i); - return result; + /* Read the POI filesystem. */ + r.read(new FileInputStream(poiFs)); + POIFile[] result = new POIFile[files.size()]; + for (int i = 0; i < result.length; i++) + result[i] = (POIFile) files.get(i); + return result; } @@ -188,19 +205,19 @@ public class Util */ public static void printSystemProperties() { - Properties p = System.getProperties(); - List names = new LinkedList(); - for (Iterator i = p.keySet().iterator(); i.hasNext();) - names.add(i.next()); - Collections.sort(names); - for (Iterator i = names.iterator(); i.hasNext();) + final Properties p = System.getProperties(); + final List names = new LinkedList(); + for (Iterator i = p.keySet().iterator(); i.hasNext();) + names.add(i.next()); + Collections.sort(names); + for (final Iterator i = names.iterator(); i.hasNext();) { - String name = (String) i.next(); - String value = (String) p.get(name); - System.out.println(name + ": " + value); - } - System.out.println("Current directory: " + - System.getProperty("user.dir")); + String name = (String) i.next(); + String value = (String) p.get(name); + System.out.println(name + ": " + value); + } + System.out.println("Current directory: " + + System.getProperty("user.dir")); } } diff --git a/src/testcases/org/apache/poi/hpsf/data/TestCorel.shw b/src/testcases/org/apache/poi/hpsf/data/TestCorel.shw new file mode 100755 index 0000000000000000000000000000000000000000..e0af1945e89de1496ce534f58017395113c8b819 GIT binary patch literal 76800 zcmeHw3w#vS_5aWlmeCyU+cK`=|q>~ZhGSO+nuUxKF;p}T?QASB>t?w9fTg!}I(*|xt03eG(N zUKHT7zzhWA(uhqH5cVpZmqL;gFtEdMUSY=Id QjA8`Lwq79r0 1)P#%!WoVT<2eNmadlF=5 z5zZ3Aq^w{`Vox~0JP9Ve=*tJ??G3+#p@ETzDJetoSp;jDFx%XzCbbn810ko-cFG#7 z1f+WcX}HmCch8i;2`k*^trcu_$Kvl@$1AhX4AeoV`yhn)p!>9Y`K4!E=a_2+HUon? zW7o;9pZ(qiwYyuags%1;lxcjZ^mdJ(Lmd^xu5KDrN`n X^|&kLzAwo(8kN0k(csaFRZyf}Tyh z8%^!2^MAA;YHIgk+}-Z4!DaZ$4@3Lyq0pHuXqULtS8Q`jA=Ick@1TgGIj*RS&Lh9baT4f+0sf9>y1x&^kGY$HG6ThJ$2(L1L&KB`R+Q zXB|*yiVRDgXuZq*Ifl6(!-s 6d7+bhX+prHd{(hek;gwVE4yLawmk- @ jqV+bso-H(|1GfK>mE@mu_~ eoWfH)@8Q<_ zH+3(Jip_)QdJqzL(7jh2HX33iRUd!MzI?<8Q*Ki2=s~(oTW?=nxajvQ*Fx$)22XgB zOLb+9YQQoPR;Gcf5a`(PD2q>mkuRZ!Ow_frrKo5qKMI8(rC2%I!cu%z${Gq mDZMejNTT%PMD0z lhIoFiwF8OdUyZCvp4YZ3{lpp(Mge z!*wPbxEx^u$_@w0Lb=N$8NyaA{PFx-mqtwu!~Um$LFZaeQ!^aRe+?r;sttzBqE%o* zlA9ie2zHIg7=vIzx+rgL2OH~t7YcdEP50Qc?$Q|F<|3%dS!@@}hSiKXEaB*aS<4?r zl*A-B^Il}=zjKqZ;X*DlzUa`5Ety-kA~y-z$Vb34OM=`_ifzoJ!=_i9huz~m!~ut3 zL^p5$LLY<}(LV-amJrQr5(3OAVReup^({nz1VI{Bha;8bum_fus2vC;s1HIA-!ni^ z mD*yN@JN!+`ea|f;>jHWQuW<=urdQ cOe+ri_sAk&|+Bw^KAQ)xl!Yy2?@rgv{s%y)HtfXZB$#-9zKUz{X`-@DlpR? zvTz?XSWZG01=jag%wL-7vVe#--!MDylyLADf?vGo{7uU@U9vIiNkw0A-$6ni2fK4B zxlBQnTtgj)l51`Dmq7NZ_psWO0lri3MVY2vX3q>w6B1BiA+=ePC&ZNj6)36@h}R*Y z##PzNPG1q7`_GZ3_yw#R6 zk$a8 zW)l%co)m%3fO!FuDN)!70G}nmlVXhHz=L2qH|SEpCR~^i=E?(3>9XhI6o)*)8 f`Y$TeslIHWv+tZ_->p(oc`#M+9URT-*Xm^!4N_t-QRhs_eb3i34&HVSYM>)Bw1 ziN$E}3FV_6oeC2-)A#ObgmiEXnXD0FCe9mNHy`1_b@PGCjJ&yO!4ku4g>>HA!dCP! z$Gpm|=$W+rrdtA)U{;gyKQqkgQMs5*dQ(R!aTtU7D$SbO{ZBY+it#9@Y*6Iw_{R&I z7=)w&MU$(+&R=CZ4`V=nWh5CvlLg@sxJhDs?Lio`=$akD4uBA7+8=_RU@7UJtZ}H9 z;WbMURVp-+iD_aur(l4VnzHbOtT{XUggBy@9?R|W56o>i?S;UoQ5Ls$45~Gq$(YnJ zXUW`Bu<%1-L6P0kX-H%v0~@b$=0WVmg&iQlZv{LTH@l%IjKg-ij1?SXV=(GqG_ K4p<{Z>&pp |}YOV!sT2&99Uc0<>mboaY9>kzdfy>km1N2P#7 z1dJpW!uFkkgw}^4fmBhDnd0th)=E{AV8;+ TD!YZYI|ki#F?mXa+z(L^ zFbG|g?tyg>6{KJgbxSF6Fu@>UfyzAuw^Gc~7Rx{>Q|j=!8l<--nbq#IpDDPWL2(db z(u_YL=5HTtvu?UWotocwCz$biP-YCGPAnrz2cwENeW%`dKoePVE<0=>p;_}~^C|2Q zcM`C8bZR!HKIHc8(5R@;Bl0(BP9AHD(Q!-9dV32KSApwim}Gg(Z~6m 6`4_(>)8!0>hmK?=@+DHDlHz3u~Qn2DeN&1KyK50TEkak3QBA z_Gkgmtg8+ 5w-^&Op`o!6JTP&^O1|Kcw(=Yj=bRAC*O#uT}tU6{Wz zG<+19f`^dEJA_2uTcGtC&Z2QDAxa?g=^eAc;BYMQFc`XrPL`A|bQkpM3H|4#V9_*H z6CVIE=4doK4LiY0am+UtfX!>LPuwIa>>nc^eW&|P_xxKwKX>8cG0XT&0;4J2C%ym> zd%*`LMz}X*7HtsJ0n$s?9_*^Z&b{wj5a`A{%8_j&Rt;Fvab~a~p$Dh*+$$;1XT&t1 zq41odkC2$Tv|n{BfK1HCox25?%0*_a$P6>_T+Vm4gcH+D)7>kC0vou?PfatZJI*}j zP$1Kge?OwqTxB@kvEd??f+5%HGsk}{8t*Xu{m(eO2E8LD8)SJq-BS=l)8M|l_+=#X z!jUOct9M~Jtc@0Nt8cq~G4BnY3ke7}=1!OPP5A`#aU9Oh!P0h^%a9CMj)h*0^Bdi< zZ4H-j`!M@VhAm%N>YiU@(mfk+?II)#c&9^eRCXGs^`^=4C&9g9^M<4~c|T5#=RV}8 z@5O+$$&BS`rOCTA7Kk^WC0t?9eaeO)Q`_k>SNj9V|JNY@T;+qvpB<7L$TpPGtk3hf zq666sZV)HghX%l8SZrGDN__U1t+d`nOwd3P@lk;-&CW7o?uLc %V9ZZoBVR?^E1=caq3z2@Ld5XU=Drce?8n1|N7ouNYbY%4NMnZM zdCc#OGUi8kMz9dFUkOvZZLBdn(00u@Y&GB~0K@3h#$}PGjf)f94^Wyx567)Y0&F|g zm?i|36hNwM0?R;FI>JioTG|}?%I{v7vtnM$QmJpmr;%IN#(Yd_@U$#y^fe04;^1it z=W1MeB3TJF8EKr+SPHeRv{{ AlP^H(mfyzk^!4z$cMe?*5R zc+Y{Z&c=Ht&MA|faw|Lo>7OZj+y)~w-<*QP>RC8D1MHb+n&5jGBss~N ztUOu&0cSi(yrPoR&)JUC?&Kx%^7z^AI0+{&ok_OiE)!}(rKFQ`@|^-F?G!piPO($s zl(L7D=Ol6eS)1~7AS}0k0bP<^1<7nWi2yCAO=t4cnS%CoQDJ)#_JY9$Zv;~iuS!=G z;^u6;)`v3CDRasJXh6Fu1Qb)GEt7SoIGq7f$8@wi?dd$3C{XHDFcA+o7Q&;=E6HR9 z=8(+8^z-u4yyIpks{M#KU7Nra%mI5{iU?gaU(CW6{@DUE1xj~2tO@TA@kpS&8s)zv zZKBs#JH9BGd=13W46)O