Merged revisions 638786-638802,638805-638811,638813-638814,638816-639230,639233-639241,639243-639253,639255-639486,639488-639601,639603-639835,639837-639917,639919-640056,640058-640710,640712-641156,641158-641184,641186-641795,641797-641798,641800-641933,641935-641963,641965-641966,641968-641995,641997-642230,642232-642562,642564-642565,642568-642570,642572-642573,642576-642736,642739-642877,642879,642881-642890,642892-642903,642905-642945,642947-643624,643626-643653,643655-643669,643671,643673-643830,643832-643833,643835-644342,644344-644472,644474-644508,644510-645347,645349-645351,645353-645559,645561-645565,645568-645951,645953-646193,646195-646311,646313-646820 via svnmerge from
https://svn.apache.org:443/repos/asf/poi/trunk ........ r646405 | nick | 2008-04-09 16:36:39 +0100 (Wed, 09 Apr 2008) | 1 line Implement a proxy HSSFListener which tracks the format records, and lets you lookup the format string for a given cell. Convert the xls to csv example to use it ........ r646666 | josh | 2008-04-10 08:06:55 +0100 (Thu, 10 Apr 2008) | 1 line bugzilla 44792 - fixed encode/decode problems in ExternalNameRecord and CRNRecord. ........ git-svn-id: https://svn.apache.org/repos/asf/poi/branches/ooxml@646826 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
958e1ffb71
commit
077fb6c6f9
@ -37,6 +37,7 @@
|
|||||||
|
|
||||||
<!-- Don't forget to update status.xml too! -->
|
<!-- Don't forget to update status.xml too! -->
|
||||||
<release version="3.0.3-beta1" date="2008-04-??">
|
<release version="3.0.3-beta1" date="2008-04-??">
|
||||||
|
<action dev="POI-DEVELOPERS" type="fix">44792 - fixed encode/decode problems in ExternalNameRecord and CRNRecord.</action>
|
||||||
<action dev="POI-DEVELOPERS" type="fix">43670, 44501 - Fix how HDGF deals with trailing data in the list of chunk headers</action>
|
<action dev="POI-DEVELOPERS" type="fix">43670, 44501 - Fix how HDGF deals with trailing data in the list of chunk headers</action>
|
||||||
<action dev="POI-DEVELOPERS" type="add">30311 - More work on Conditional Formatting</action>
|
<action dev="POI-DEVELOPERS" type="add">30311 - More work on Conditional Formatting</action>
|
||||||
<action dev="POI-DEVELOPERS" type="fix">refactored all junits' usage of HSSF.testdata.path to one place</action>
|
<action dev="POI-DEVELOPERS" type="fix">refactored all junits' usage of HSSF.testdata.path to one place</action>
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
<!-- Don't forget to update changes.xml too! -->
|
<!-- Don't forget to update changes.xml too! -->
|
||||||
<changes>
|
<changes>
|
||||||
<release version="3.0.3-beta1" date="2008-04-??">
|
<release version="3.0.3-beta1" date="2008-04-??">
|
||||||
|
<action dev="POI-DEVELOPERS" type="fix">44792 - fixed encode/decode problems in ExternalNameRecord and CRNRecord.</action>
|
||||||
<action dev="POI-DEVELOPERS" type="fix">43670, 44501 - Fix how HDGF deals with trailing data in the list of chunk headers</action>
|
<action dev="POI-DEVELOPERS" type="fix">43670, 44501 - Fix how HDGF deals with trailing data in the list of chunk headers</action>
|
||||||
<action dev="POI-DEVELOPERS" type="add">30311 - More work on Conditional Formatting</action>
|
<action dev="POI-DEVELOPERS" type="add">30311 - More work on Conditional Formatting</action>
|
||||||
<action dev="POI-DEVELOPERS" type="fix">refactored all junits' usage of HSSF.testdata.path to one place</action>
|
<action dev="POI-DEVELOPERS" type="fix">refactored all junits' usage of HSSF.testdata.path to one place</action>
|
||||||
|
@ -0,0 +1,117 @@
|
|||||||
|
/* ====================================================================
|
||||||
|
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
contributor license agreements. See the NOTICE file distributed with
|
||||||
|
this work for additional information regarding copyright ownership.
|
||||||
|
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
(the "License"); you may not use this file except in compliance with
|
||||||
|
the License. You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
==================================================================== */
|
||||||
|
package org.apache.poi.hssf.eventusermodel;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Hashtable;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.poi.hssf.record.CellValueRecordInterface;
|
||||||
|
import org.apache.poi.hssf.record.ExtendedFormatRecord;
|
||||||
|
import org.apache.poi.hssf.record.FormatRecord;
|
||||||
|
import org.apache.poi.hssf.record.Record;
|
||||||
|
import org.apache.poi.hssf.usermodel.HSSFDataFormat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A proxy HSSFListener that keeps track of the document
|
||||||
|
* formatting records, and provides an easy way to look
|
||||||
|
* up the format strings used by cells from their ids.
|
||||||
|
*/
|
||||||
|
public class FormatTrackingHSSFListener implements HSSFListener {
|
||||||
|
private HSSFListener childListener;
|
||||||
|
private Map customFormatRecords = new Hashtable();
|
||||||
|
private List xfRecords = new ArrayList();
|
||||||
|
|
||||||
|
public FormatTrackingHSSFListener(HSSFListener childListener) {
|
||||||
|
this.childListener = childListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process this record ourselves, and then
|
||||||
|
* pass it on to our child listener
|
||||||
|
*/
|
||||||
|
public void processRecord(Record record) {
|
||||||
|
// Handle it ourselves
|
||||||
|
processRecordInternally(record);
|
||||||
|
|
||||||
|
// Now pass on to our child
|
||||||
|
childListener.processRecord(record);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process the record ourselves, but do not
|
||||||
|
* pass it on to the child Listener.
|
||||||
|
* @param record
|
||||||
|
*/
|
||||||
|
public void processRecordInternally(Record record) {
|
||||||
|
if(record instanceof FormatRecord) {
|
||||||
|
FormatRecord fr = (FormatRecord) record;
|
||||||
|
customFormatRecords.put(new Integer(fr.getIndexCode()), fr);
|
||||||
|
}
|
||||||
|
if(record instanceof ExtendedFormatRecord) {
|
||||||
|
ExtendedFormatRecord xr = (ExtendedFormatRecord) record;
|
||||||
|
xfRecords.add(xr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the format string, eg $##.##, for the
|
||||||
|
* given number format index.
|
||||||
|
*/
|
||||||
|
public String getFormatString(int formatIndex) {
|
||||||
|
String format = null;
|
||||||
|
if(formatIndex >= HSSFDataFormat.getNumberOfBuiltinBuiltinFormats()) {
|
||||||
|
FormatRecord tfr = (FormatRecord)customFormatRecords.get(new Integer(formatIndex));
|
||||||
|
if(tfr == null) {
|
||||||
|
System.err.println("Requested format at index " + formatIndex + ", but it wasn't found");
|
||||||
|
} else {
|
||||||
|
format = tfr.getFormatString();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
format = HSSFDataFormat.getBuiltinFormat((short)formatIndex);
|
||||||
|
}
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the format string, eg $##.##, used
|
||||||
|
* by your cell
|
||||||
|
*/
|
||||||
|
public String getFormatString(CellValueRecordInterface cell) {
|
||||||
|
int formatIndex = getFormatIndex(cell);
|
||||||
|
if(formatIndex == -1) {
|
||||||
|
// Not found
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return getFormatString(formatIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the index of the format string, used by your cell,
|
||||||
|
* or -1 if none found
|
||||||
|
*/
|
||||||
|
public int getFormatIndex(CellValueRecordInterface cell) {
|
||||||
|
ExtendedFormatRecord xfr = (ExtendedFormatRecord)
|
||||||
|
xfRecords.get(cell.getXFIndex());
|
||||||
|
if(xfr == null) {
|
||||||
|
System.err.println("Cell " + cell.getRow() + "," + cell.getColumn() + " uses XF with index " + cell.getXFIndex() + ", but we don't have that");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return xfr.getFormatIndex();
|
||||||
|
}
|
||||||
|
}
|
@ -60,7 +60,7 @@ public final class CRNRecord extends Record {
|
|||||||
field_3_row_index = in.readShort();
|
field_3_row_index = in.readShort();
|
||||||
int nValues = field_1_last_column_index - field_2_first_column_index + 1;
|
int nValues = field_1_last_column_index - field_2_first_column_index + 1;
|
||||||
field_4_constant_values = ConstantValueParser.parse(in, nValues);
|
field_4_constant_values = ConstantValueParser.parse(in, nValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
@ -83,6 +83,7 @@ public final class CRNRecord extends Record {
|
|||||||
LittleEndian.putByte(data, 4 + offset, field_1_last_column_index);
|
LittleEndian.putByte(data, 4 + offset, field_1_last_column_index);
|
||||||
LittleEndian.putByte(data, 5 + offset, field_2_first_column_index);
|
LittleEndian.putByte(data, 5 + offset, field_2_first_column_index);
|
||||||
LittleEndian.putShort(data, 6 + offset, (short) field_3_row_index);
|
LittleEndian.putShort(data, 6 + offset, (short) field_3_row_index);
|
||||||
|
ConstantValueParser.encode(data, 8 + offset, field_4_constant_values);
|
||||||
return getRecordSize();
|
return getRecordSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,10 +30,12 @@ import org.apache.poi.util.StringUtil;
|
|||||||
*/
|
*/
|
||||||
public final class ExternalNameRecord extends Record {
|
public final class ExternalNameRecord extends Record {
|
||||||
|
|
||||||
|
private static final Ptg[] EMPTY_PTG_ARRAY = { };
|
||||||
|
|
||||||
public final static short sid = 0x23; // as per BIFF8. (some old versions used 0x223)
|
public final static short sid = 0x23; // as per BIFF8. (some old versions used 0x223)
|
||||||
|
|
||||||
private static final int OPT_BUILTIN_NAME = 0x0001;
|
private static final int OPT_BUILTIN_NAME = 0x0001;
|
||||||
private static final int OPT_AUTOMATIC_LINK = 0x0002;
|
private static final int OPT_AUTOMATIC_LINK = 0x0002; // m$ doc calls this fWantAdvise
|
||||||
private static final int OPT_PICTURE_LINK = 0x0004;
|
private static final int OPT_PICTURE_LINK = 0x0004;
|
||||||
private static final int OPT_STD_DOCUMENT_NAME = 0x0008;
|
private static final int OPT_STD_DOCUMENT_NAME = 0x0008;
|
||||||
private static final int OPT_OLE_LINK = 0x0010;
|
private static final int OPT_OLE_LINK = 0x0010;
|
||||||
@ -51,8 +53,8 @@ public final class ExternalNameRecord extends Record {
|
|||||||
super(in);
|
super(in);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convenience Function to determine if the name is a built-in name
|
* Convenience Function to determine if the name is a built-in name
|
||||||
*/
|
*/
|
||||||
public boolean isBuiltInName() {
|
public boolean isBuiltInName() {
|
||||||
return (field_1_option_flag & OPT_BUILTIN_NAME) != 0;
|
return (field_1_option_flag & OPT_BUILTIN_NAME) != 0;
|
||||||
@ -102,9 +104,12 @@ public final class ExternalNameRecord extends Record {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private int getDataSize(){
|
private int getDataSize(){
|
||||||
return 3 * 2 // 3 short fields
|
int result = 3 * 2 // 3 short fields
|
||||||
+ 2 + field_4_name.length() // nameLen and name
|
+ 2 + field_4_name.length(); // nameLen and name
|
||||||
+ 2 + getNameDefinitionSize(); // nameDefLen and nameDef
|
if(hasFormula()) {
|
||||||
|
result += 2 + getNameDefinitionSize(); // nameDefLen and nameDef
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -127,9 +132,11 @@ public final class ExternalNameRecord extends Record {
|
|||||||
short nameLen = (short) field_4_name.length();
|
short nameLen = (short) field_4_name.length();
|
||||||
LittleEndian.putShort( data, 10 + offset, nameLen );
|
LittleEndian.putShort( data, 10 + offset, nameLen );
|
||||||
StringUtil.putCompressedUnicode( field_4_name, data, 12 + offset );
|
StringUtil.putCompressedUnicode( field_4_name, data, 12 + offset );
|
||||||
short defLen = (short) getNameDefinitionSize();
|
if(hasFormula()) {
|
||||||
LittleEndian.putShort( data, 12 + nameLen + offset, defLen );
|
short defLen = (short) getNameDefinitionSize();
|
||||||
Ptg.serializePtgStack(toStack(field_5_name_definition), data, 14 + nameLen + offset );
|
LittleEndian.putShort( data, 12 + nameLen + offset, defLen );
|
||||||
|
Ptg.serializePtgStack(toStack(field_5_name_definition), data, 14 + nameLen + offset );
|
||||||
|
}
|
||||||
return dataSize + 4;
|
return dataSize + 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,13 +156,58 @@ public final class ExternalNameRecord extends Record {
|
|||||||
|
|
||||||
protected void fillFields(RecordInputStream in) {
|
protected void fillFields(RecordInputStream in) {
|
||||||
field_1_option_flag = in.readShort();
|
field_1_option_flag = in.readShort();
|
||||||
field_2_index = in.readShort();
|
field_2_index = in.readShort();
|
||||||
field_3_not_used = in.readShort();
|
field_3_not_used = in.readShort();
|
||||||
short nameLength = in.readShort();
|
short nameLength = in.readShort();
|
||||||
field_4_name = in.readCompressedUnicode(nameLength);
|
field_4_name = in.readCompressedUnicode(nameLength);
|
||||||
short formulaLen = in.readShort();
|
if(!hasFormula()) {
|
||||||
|
if(in.remaining() > 0) {
|
||||||
|
throw readFail("Some unread data (is formula present?)");
|
||||||
|
}
|
||||||
|
field_5_name_definition = EMPTY_PTG_ARRAY;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(in.remaining() <= 0) {
|
||||||
|
throw readFail("Ran out of record data trying to read formula.");
|
||||||
|
}
|
||||||
|
short formulaLen = in.readShort();
|
||||||
field_5_name_definition = toPtgArray(Ptg.createParsedExpressionTokens(formulaLen, in));
|
field_5_name_definition = toPtgArray(Ptg.createParsedExpressionTokens(formulaLen, in));
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
* Makes better error messages (while hasFormula() is not reliable)
|
||||||
|
* Remove this when hasFormula() is stable.
|
||||||
|
*/
|
||||||
|
private RuntimeException readFail(String msg) {
|
||||||
|
String fullMsg = msg + " fields: (option=" + field_1_option_flag + " index=" + field_2_index
|
||||||
|
+ " not_used=" + field_3_not_used + " name='" + field_4_name + "')";
|
||||||
|
return new RuntimeException(fullMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasFormula() {
|
||||||
|
// TODO - determine exact conditions when formula is present
|
||||||
|
if (false) {
|
||||||
|
// "Microsoft Office Excel 97-2007 Binary File Format (.xls) Specification"
|
||||||
|
// m$'s document suggests logic like this, but bugzilla 44774 att 21790 seems to disagree
|
||||||
|
if (isStdDocumentNameIdentifier()) {
|
||||||
|
if (isOLELink()) {
|
||||||
|
// seems to be not possible according to m$ document
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"flags (std-doc-name and ole-link) cannot be true at the same time");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (isOLELink()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This was derived by trial and error, but doesn't seem quite right
|
||||||
|
if (isAutomaticLink()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private static Ptg[] toPtgArray(Stack s) {
|
private static Ptg[] toPtgArray(Stack s) {
|
||||||
Ptg[] result = new Ptg[s.size()];
|
Ptg[] result = new Ptg[s.size()];
|
||||||
@ -169,7 +221,7 @@ public final class ExternalNameRecord extends Record {
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public short getSid() {
|
public short getSid() {
|
||||||
return sid;
|
return sid;
|
||||||
}
|
}
|
||||||
|
@ -14,12 +14,13 @@
|
|||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
==================================================================== */
|
==================================================================== */
|
||||||
|
|
||||||
package org.apache.poi.hssf.record.constant;
|
package org.apache.poi.hssf.record.constant;
|
||||||
|
|
||||||
import org.apache.poi.hssf.record.RecordInputStream;
|
import org.apache.poi.hssf.record.RecordInputStream;
|
||||||
import org.apache.poi.hssf.record.UnicodeString;
|
import org.apache.poi.hssf.record.UnicodeString;
|
||||||
import org.apache.poi.hssf.record.UnicodeString.UnicodeRecordStats;
|
import org.apache.poi.hssf.record.UnicodeString.UnicodeRecordStats;
|
||||||
|
import org.apache.poi.util.LittleEndian;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* To support Constant Values (2.5.7) as required by the CRN record.
|
* To support Constant Values (2.5.7) as required by the CRN record.
|
||||||
@ -30,11 +31,12 @@ import org.apache.poi.hssf.record.UnicodeString.UnicodeRecordStats;
|
|||||||
* @author Josh Micich
|
* @author Josh Micich
|
||||||
*/
|
*/
|
||||||
public final class ConstantValueParser {
|
public final class ConstantValueParser {
|
||||||
// note - value 3 seems to be unused
|
// note - these (non-combinable) enum values are sparse.
|
||||||
private static final int TYPE_EMPTY = 0;
|
private static final int TYPE_EMPTY = 0;
|
||||||
private static final int TYPE_NUMBER = 1;
|
private static final int TYPE_NUMBER = 1;
|
||||||
private static final int TYPE_STRING = 2;
|
private static final int TYPE_STRING = 2;
|
||||||
private static final int TYPE_BOOLEAN = 4;
|
private static final int TYPE_BOOLEAN = 4;
|
||||||
|
private static final int TYPE_ERROR_CODE = 16; // TODO - update OOO document to include this value
|
||||||
|
|
||||||
private static final int TRUE_ENCODING = 1;
|
private static final int TRUE_ENCODING = 1;
|
||||||
private static final int FALSE_ENCODING = 0;
|
private static final int FALSE_ENCODING = 0;
|
||||||
@ -47,11 +49,11 @@ public final class ConstantValueParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static Object[] parse(RecordInputStream in, int nValues) {
|
public static Object[] parse(RecordInputStream in, int nValues) {
|
||||||
Object[] result = new Object[nValues];
|
Object[] result = new Object[nValues];
|
||||||
for (int i = 0; i < result.length; i++) {
|
for (int i = 0; i < result.length; i++) {
|
||||||
result[i] = readAConstantValue(in);
|
result[i] = readAConstantValue(in);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Object readAConstantValue(RecordInputStream in) {
|
private static Object readAConstantValue(RecordInputStream in) {
|
||||||
@ -66,13 +68,18 @@ public final class ConstantValueParser {
|
|||||||
return in.readUnicodeString();
|
return in.readUnicodeString();
|
||||||
case TYPE_BOOLEAN:
|
case TYPE_BOOLEAN:
|
||||||
return readBoolean(in);
|
return readBoolean(in);
|
||||||
|
case TYPE_ERROR_CODE:
|
||||||
|
int errCode = in.readUShort();
|
||||||
|
// next 6 bytes are unused
|
||||||
|
in.readUShort();
|
||||||
|
in.readInt();
|
||||||
|
return ErrorConstant.valueOf(errCode);
|
||||||
}
|
}
|
||||||
return null;
|
throw new RuntimeException("Unknown grbit value (" + grbit + ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Object readBoolean(RecordInputStream in) {
|
private static Object readBoolean(RecordInputStream in) {
|
||||||
byte val = in.readByte();
|
byte val = (byte)in.readLong(); // 7 bytes 'not used'
|
||||||
in.readLong(); // 8 byte 'not used' field
|
|
||||||
switch(val) {
|
switch(val) {
|
||||||
case FALSE_ENCODING:
|
case FALSE_ENCODING:
|
||||||
return Boolean.FALSE;
|
return Boolean.FALSE;
|
||||||
@ -89,7 +96,7 @@ public final class ConstantValueParser {
|
|||||||
for (int i = 0; i < values.length; i++) {
|
for (int i = 0; i < values.length; i++) {
|
||||||
result += getEncodedSize(values[i]);
|
result += getEncodedSize(values[i]);
|
||||||
}
|
}
|
||||||
return 0;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -100,7 +107,8 @@ public final class ConstantValueParser {
|
|||||||
return 8;
|
return 8;
|
||||||
}
|
}
|
||||||
Class cls = object.getClass();
|
Class cls = object.getClass();
|
||||||
if(cls == Boolean.class || cls == Double.class) {
|
|
||||||
|
if(cls == Boolean.class || cls == Double.class || cls == ErrorConstant.class) {
|
||||||
return 8;
|
return 8;
|
||||||
}
|
}
|
||||||
UnicodeString strVal = (UnicodeString)object;
|
UnicodeString strVal = (UnicodeString)object;
|
||||||
@ -108,4 +116,49 @@ public final class ConstantValueParser {
|
|||||||
strVal.getRecordSize(urs);
|
strVal.getRecordSize(urs);
|
||||||
return urs.recordSize;
|
return urs.recordSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void encode(byte[] data, int offset, Object[] values) {
|
||||||
|
int currentOffset = offset;
|
||||||
|
for (int i = 0; i < values.length; i++) {
|
||||||
|
currentOffset += encodeSingleValue(data, currentOffset, values[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int encodeSingleValue(byte[] data, int offset, Object value) {
|
||||||
|
if (value == EMPTY_REPRESENTATION) {
|
||||||
|
LittleEndian.putByte(data, offset, TYPE_EMPTY);
|
||||||
|
LittleEndian.putLong(data, offset+1, 0L);
|
||||||
|
return 9;
|
||||||
|
}
|
||||||
|
if (value instanceof Boolean) {
|
||||||
|
Boolean bVal = ((Boolean)value);
|
||||||
|
LittleEndian.putByte(data, offset, TYPE_BOOLEAN);
|
||||||
|
long longVal = bVal.booleanValue() ? 1L : 0L;
|
||||||
|
LittleEndian.putLong(data, offset+1, longVal);
|
||||||
|
return 9;
|
||||||
|
}
|
||||||
|
if (value instanceof Double) {
|
||||||
|
Double dVal = (Double) value;
|
||||||
|
LittleEndian.putByte(data, offset, TYPE_NUMBER);
|
||||||
|
LittleEndian.putDouble(data, offset+1, dVal.doubleValue());
|
||||||
|
return 9;
|
||||||
|
}
|
||||||
|
if (value instanceof UnicodeString) {
|
||||||
|
UnicodeString usVal = (UnicodeString) value;
|
||||||
|
LittleEndian.putByte(data, offset, TYPE_STRING);
|
||||||
|
UnicodeRecordStats urs = new UnicodeRecordStats();
|
||||||
|
usVal.serialize(urs, offset +1, data);
|
||||||
|
return 1 + urs.recordSize;
|
||||||
|
}
|
||||||
|
if (value instanceof ErrorConstant) {
|
||||||
|
ErrorConstant ecVal = (ErrorConstant) value;
|
||||||
|
LittleEndian.putByte(data, offset, TYPE_ERROR_CODE);
|
||||||
|
LittleEndian.putUShort(data, offset+1, ecVal.getErrorCode());
|
||||||
|
LittleEndian.putUShort(data, offset+3, 0);
|
||||||
|
LittleEndian.putInt(data, offset+5, 0);
|
||||||
|
return 9;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalStateException("Unexpected value type (" + value.getClass().getName() + "'");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,64 @@
|
|||||||
|
/* ====================================================================
|
||||||
|
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
contributor license agreements. See the NOTICE file distributed with
|
||||||
|
this work for additional information regarding copyright ownership.
|
||||||
|
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
(the "License"); you may not use this file except in compliance with
|
||||||
|
the License. You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
==================================================================== */
|
||||||
|
|
||||||
|
package org.apache.poi.hssf.record.constant;
|
||||||
|
|
||||||
|
import org.apache.poi.hssf.usermodel.HSSFErrorConstants;
|
||||||
|
/**
|
||||||
|
* Represents a constant error code value as encoded in a constant values array. <p/>
|
||||||
|
*
|
||||||
|
* This class is a type-safe wrapper for a 16-bit int value performing a similar job to
|
||||||
|
* <tt>ErrorEval</tt>.
|
||||||
|
*
|
||||||
|
* @author Josh Micich
|
||||||
|
*/
|
||||||
|
public class ErrorConstant {
|
||||||
|
// convenient access to name space
|
||||||
|
private static final HSSFErrorConstants EC = null;
|
||||||
|
|
||||||
|
private static final ErrorConstant NULL = new ErrorConstant(EC.ERROR_NULL);
|
||||||
|
private static final ErrorConstant DIV_0 = new ErrorConstant(EC.ERROR_DIV_0);
|
||||||
|
private static final ErrorConstant VALUE = new ErrorConstant(EC.ERROR_VALUE);
|
||||||
|
private static final ErrorConstant REF = new ErrorConstant(EC.ERROR_REF);
|
||||||
|
private static final ErrorConstant NAME = new ErrorConstant(EC.ERROR_NAME);
|
||||||
|
private static final ErrorConstant NUM = new ErrorConstant(EC.ERROR_NUM);
|
||||||
|
private static final ErrorConstant NA = new ErrorConstant(EC.ERROR_NA);
|
||||||
|
|
||||||
|
private final int _errorCode;
|
||||||
|
|
||||||
|
private ErrorConstant(int errorCode) {
|
||||||
|
_errorCode = errorCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getErrorCode() {
|
||||||
|
return _errorCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ErrorConstant valueOf(int errorCode) {
|
||||||
|
switch (errorCode) {
|
||||||
|
case HSSFErrorConstants.ERROR_NULL: return NULL;
|
||||||
|
case HSSFErrorConstants.ERROR_DIV_0: return DIV_0;
|
||||||
|
case HSSFErrorConstants.ERROR_VALUE: return VALUE;
|
||||||
|
case HSSFErrorConstants.ERROR_REF: return REF;
|
||||||
|
case HSSFErrorConstants.ERROR_NAME: return NAME;
|
||||||
|
case HSSFErrorConstants.ERROR_NUM: return NUM;
|
||||||
|
case HSSFErrorConstants.ERROR_NA: return NA;
|
||||||
|
}
|
||||||
|
System.err.println("Warning - unexpected error code (" + errorCode + ")");
|
||||||
|
return new ErrorConstant(errorCode);
|
||||||
|
}
|
||||||
|
}
|
@ -29,6 +29,7 @@ import java.util.Hashtable;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.poi.hssf.eventusermodel.FormatTrackingHSSFListener;
|
||||||
import org.apache.poi.hssf.eventusermodel.HSSFEventFactory;
|
import org.apache.poi.hssf.eventusermodel.HSSFEventFactory;
|
||||||
import org.apache.poi.hssf.eventusermodel.HSSFListener;
|
import org.apache.poi.hssf.eventusermodel.HSSFListener;
|
||||||
import org.apache.poi.hssf.eventusermodel.HSSFRequest;
|
import org.apache.poi.hssf.eventusermodel.HSSFRequest;
|
||||||
@ -70,8 +71,7 @@ public class XLS2CSVmra implements HSSFListener {
|
|||||||
|
|
||||||
// Records we pick up as we process
|
// Records we pick up as we process
|
||||||
private SSTRecord sstRecord;
|
private SSTRecord sstRecord;
|
||||||
private Map customFormatRecords = new Hashtable();
|
private FormatTrackingHSSFListener formatListener;
|
||||||
private List xfRecords = new ArrayList();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new XLS -> CSV converter
|
* Creates a new XLS -> CSV converter
|
||||||
@ -104,9 +104,11 @@ public class XLS2CSVmra implements HSSFListener {
|
|||||||
*/
|
*/
|
||||||
public void process() throws IOException {
|
public void process() throws IOException {
|
||||||
MissingRecordAwareHSSFListener listener = new MissingRecordAwareHSSFListener(this);
|
MissingRecordAwareHSSFListener listener = new MissingRecordAwareHSSFListener(this);
|
||||||
|
formatListener = new FormatTrackingHSSFListener(listener);
|
||||||
|
|
||||||
HSSFEventFactory factory = new HSSFEventFactory();
|
HSSFEventFactory factory = new HSSFEventFactory();
|
||||||
HSSFRequest request = new HSSFRequest();
|
HSSFRequest request = new HSSFRequest();
|
||||||
request.addListenerForAllRecords(listener);
|
request.addListenerForAllRecords(formatListener);
|
||||||
|
|
||||||
factory.processWorkbookEvents(request, fs);
|
factory.processWorkbookEvents(request, fs);
|
||||||
}
|
}
|
||||||
@ -125,14 +127,6 @@ public class XLS2CSVmra implements HSSFListener {
|
|||||||
case SSTRecord.sid:
|
case SSTRecord.sid:
|
||||||
sstRecord = (SSTRecord) record;
|
sstRecord = (SSTRecord) record;
|
||||||
break;
|
break;
|
||||||
case FormatRecord.sid:
|
|
||||||
FormatRecord fr = (FormatRecord) record;
|
|
||||||
customFormatRecords.put(new Integer(fr.getIndexCode()), fr);
|
|
||||||
break;
|
|
||||||
case ExtendedFormatRecord.sid:
|
|
||||||
ExtendedFormatRecord xr = (ExtendedFormatRecord) record;
|
|
||||||
xfRecords.add(xr);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BlankRecord.sid:
|
case BlankRecord.sid:
|
||||||
BlankRecord brec = (BlankRecord) record;
|
BlankRecord brec = (BlankRecord) record;
|
||||||
@ -259,41 +253,32 @@ public class XLS2CSVmra implements HSSFListener {
|
|||||||
*/
|
*/
|
||||||
private String formatNumberDateCell(CellValueRecordInterface cell, double value) {
|
private String formatNumberDateCell(CellValueRecordInterface cell, double value) {
|
||||||
// Get the built in format, if there is one
|
// Get the built in format, if there is one
|
||||||
ExtendedFormatRecord xfr = (ExtendedFormatRecord)
|
int formatIndex = formatListener.getFormatIndex(cell);
|
||||||
xfRecords.get(cell.getXFIndex());
|
String formatString = formatListener.getFormatString(cell);
|
||||||
if(xfr == null) {
|
|
||||||
System.err.println("Cell " + cell.getRow() + "," + cell.getColumn() + " uses XF with index " + cell.getXFIndex() + ", but we don't have that");
|
if(formatString == null) {
|
||||||
return Double.toString(value);
|
return Double.toString(value);
|
||||||
} else {
|
} else {
|
||||||
int formatIndex = xfr.getFormatIndex();
|
|
||||||
String format;
|
|
||||||
if(formatIndex >= HSSFDataFormat.getNumberOfBuiltinBuiltinFormats()) {
|
|
||||||
FormatRecord tfr = (FormatRecord)customFormatRecords.get(new Integer(formatIndex));
|
|
||||||
format = tfr.getFormatString();
|
|
||||||
} else {
|
|
||||||
format = HSSFDataFormat.getBuiltinFormat(xfr.getFormatIndex());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Is it a date?
|
// Is it a date?
|
||||||
if(HSSFDateUtil.isADateFormat(formatIndex,format) &&
|
if(HSSFDateUtil.isADateFormat(formatIndex,formatString) &&
|
||||||
HSSFDateUtil.isValidExcelDate(value)) {
|
HSSFDateUtil.isValidExcelDate(value)) {
|
||||||
// Java wants M not m for month
|
// Java wants M not m for month
|
||||||
format = format.replace('m','M');
|
formatString = formatString.replace('m','M');
|
||||||
// Change \- into -, if it's there
|
// Change \- into -, if it's there
|
||||||
format = format.replaceAll("\\\\-","-");
|
formatString = formatString.replaceAll("\\\\-","-");
|
||||||
|
|
||||||
// Format as a date
|
// Format as a date
|
||||||
Date d = HSSFDateUtil.getJavaDate(value, false);
|
Date d = HSSFDateUtil.getJavaDate(value, false);
|
||||||
DateFormat df = new SimpleDateFormat(format);
|
DateFormat df = new SimpleDateFormat(formatString);
|
||||||
return df.format(d);
|
return df.format(d);
|
||||||
} else {
|
} else {
|
||||||
if(format == "General") {
|
if(formatString == "General") {
|
||||||
// Some sort of wierd default
|
// Some sort of wierd default
|
||||||
return Double.toString(value);
|
return Double.toString(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Format as a number
|
// Format as a number
|
||||||
DecimalFormat df = new DecimalFormat(format);
|
DecimalFormat df = new DecimalFormat(formatString);
|
||||||
return df.format(value);
|
return df.format(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,65 @@
|
|||||||
|
/* ====================================================================
|
||||||
|
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
contributor license agreements. See the NOTICE file distributed with
|
||||||
|
this work for additional information regarding copyright ownership.
|
||||||
|
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
(the "License"); you may not use this file except in compliance with
|
||||||
|
the License. You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
==================================================================== */
|
||||||
|
|
||||||
|
package org.apache.poi.hssf.eventusermodel;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
import org.apache.poi.hssf.HSSFTestDataSamples;
|
||||||
|
import org.apache.poi.hssf.record.Record;
|
||||||
|
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
|
||||||
|
/**
|
||||||
|
* Tests for FormatTrackingHSSFListener
|
||||||
|
*/
|
||||||
|
public final class TestFormatTrackingHSSFListener extends TestCase {
|
||||||
|
private FormatTrackingHSSFListener listener;
|
||||||
|
|
||||||
|
public void setUp() {
|
||||||
|
HSSFRequest req = new HSSFRequest();
|
||||||
|
MockHSSFListener mockListen = new MockHSSFListener();
|
||||||
|
listener = new FormatTrackingHSSFListener(mockListen);
|
||||||
|
req.addListenerForAllRecords(listener);
|
||||||
|
|
||||||
|
HSSFEventFactory factory = new HSSFEventFactory();
|
||||||
|
try {
|
||||||
|
InputStream is = HSSFTestDataSamples.openSampleFileStream("MissingBits.xls");
|
||||||
|
POIFSFileSystem fs = new POIFSFileSystem(is);
|
||||||
|
factory.processWorkbookEvents(req, fs);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testFormats() throws Exception {
|
||||||
|
assertEquals("_(*#,##0_);_(*(#,##0);_(* \"-\"_);_(@_)", listener.getFormatString(41));
|
||||||
|
assertEquals("_($*#,##0_);_($*(#,##0);_($* \"-\"_);_(@_)", listener.getFormatString(42));
|
||||||
|
assertEquals("_(*#,##0.00_);_(*(#,##0.00);_(*\"-\"??_);_(@_)", listener.getFormatString(43));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class MockHSSFListener implements HSSFListener {
|
||||||
|
public MockHSSFListener() {}
|
||||||
|
private final List _records = new ArrayList();
|
||||||
|
|
||||||
|
public void processRecord(Record record) {
|
||||||
|
_records.add(record);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -22,6 +22,7 @@ import junit.framework.TestSuite;
|
|||||||
|
|
||||||
import org.apache.poi.hssf.record.aggregates.AllRecordAggregateTests;
|
import org.apache.poi.hssf.record.aggregates.AllRecordAggregateTests;
|
||||||
import org.apache.poi.hssf.record.cf.TestCellRange;
|
import org.apache.poi.hssf.record.cf.TestCellRange;
|
||||||
|
import org.apache.poi.hssf.record.constant.TestConstantValueParser;
|
||||||
import org.apache.poi.hssf.record.formula.AllFormulaTests;
|
import org.apache.poi.hssf.record.formula.AllFormulaTests;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -105,6 +106,7 @@ public final class AllRecordTests {
|
|||||||
result.addTestSuite(TestUnitsRecord.class);
|
result.addTestSuite(TestUnitsRecord.class);
|
||||||
result.addTestSuite(TestValueRangeRecord.class);
|
result.addTestSuite(TestValueRangeRecord.class);
|
||||||
result.addTestSuite(TestCellRange.class);
|
result.addTestSuite(TestCellRange.class);
|
||||||
|
result.addTestSuite(TestConstantValueParser.class);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,13 +28,25 @@ public final class TestExternalNameRecord extends TestCase {
|
|||||||
private static final byte[] dataFDS = {
|
private static final byte[] dataFDS = {
|
||||||
0, 0, 0, 0, 0, 0, 3, 0, 70, 68, 83, 0, 0,
|
0, 0, 0, 0, 0, 0, 3, 0, 70, 68, 83, 0, 0,
|
||||||
};
|
};
|
||||||
private static ExternalNameRecord createSimpleENR() {
|
|
||||||
return new ExternalNameRecord(new TestcaseRecordInputStream((short)0x0023, dataFDS));
|
// data taken from bugzilla 44774 att 21790
|
||||||
|
private static final byte[] dataAutoDocName = {
|
||||||
|
-22, 127, 0, 0, 0, 0, 29, 0, 39, 49, 57, 49, 50, 49, 57, 65, 87, 52, 32, 67, 111, 114,
|
||||||
|
112, 44, 91, 87, 79, 82, 75, 79, 85, 84, 95, 80, 88, 93, 39,
|
||||||
|
};
|
||||||
|
|
||||||
|
// data taken from bugzilla 44774 att 21790
|
||||||
|
private static final byte[] dataPlainName = {
|
||||||
|
0, 0, 0, 0, 0, 0, 9, 0, 82, 97, 116, 101, 95, 68, 97, 116, 101, 9, 0, 58, 0, 0, 0, 0, 4, 0, 8, 0
|
||||||
|
};
|
||||||
|
|
||||||
|
private static ExternalNameRecord createSimpleENR(byte[] data) {
|
||||||
|
return new ExternalNameRecord(new TestcaseRecordInputStream((short)0x0023, data));
|
||||||
}
|
}
|
||||||
public void testBasicDeserializeReserialize() {
|
public void testBasicDeserializeReserialize() {
|
||||||
|
|
||||||
ExternalNameRecord enr = createSimpleENR();
|
ExternalNameRecord enr = createSimpleENR(dataFDS);
|
||||||
assertEquals( "FDS", enr.getText());
|
assertEquals("FDS", enr.getText());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
TestcaseRecordInputStream.confirmRecordEncoding(0x0023, dataFDS, enr.serialize());
|
TestcaseRecordInputStream.confirmRecordEncoding(0x0023, dataFDS, enr.serialize());
|
||||||
@ -46,10 +58,50 @@ public final class TestExternalNameRecord extends TestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void testBasicSize() {
|
public void testBasicSize() {
|
||||||
ExternalNameRecord enr = createSimpleENR();
|
ExternalNameRecord enr = createSimpleENR(dataFDS);
|
||||||
if(enr.getRecordSize() == 13) {
|
if(enr.getRecordSize() == 13) {
|
||||||
throw new AssertionFailedError("Identified bug 44695");
|
throw new AssertionFailedError("Identified bug 44695");
|
||||||
}
|
}
|
||||||
assertEquals(17, enr.getRecordSize());
|
assertEquals(17, enr.getRecordSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testAutoStdDocName() {
|
||||||
|
|
||||||
|
ExternalNameRecord enr;
|
||||||
|
try {
|
||||||
|
enr = createSimpleENR(dataAutoDocName);
|
||||||
|
} catch (ArrayIndexOutOfBoundsException e) {
|
||||||
|
if(e.getMessage() == null) {
|
||||||
|
throw new AssertionFailedError("Identified bug XXXX");
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
assertEquals("'191219AW4 Corp,[WORKOUT_PX]'", enr.getText());
|
||||||
|
assertTrue(enr.isAutomaticLink());
|
||||||
|
assertFalse(enr.isBuiltInName());
|
||||||
|
assertFalse(enr.isIconifiedPictureLink());
|
||||||
|
assertFalse(enr.isInValueSection());
|
||||||
|
assertFalse(enr.isOLELink());
|
||||||
|
assertFalse(enr.isPicureLink());
|
||||||
|
assertTrue(enr.isStdDocumentNameIdentifier());
|
||||||
|
assertFalse(enr.isValue());
|
||||||
|
|
||||||
|
TestcaseRecordInputStream.confirmRecordEncoding(0x0023, dataAutoDocName, enr.serialize());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testPlainName() {
|
||||||
|
|
||||||
|
ExternalNameRecord enr = createSimpleENR(dataPlainName);
|
||||||
|
assertEquals("Rate_Date", enr.getText());
|
||||||
|
assertFalse(enr.isAutomaticLink());
|
||||||
|
assertFalse(enr.isBuiltInName());
|
||||||
|
assertFalse(enr.isIconifiedPictureLink());
|
||||||
|
assertFalse(enr.isInValueSection());
|
||||||
|
assertFalse(enr.isOLELink());
|
||||||
|
assertFalse(enr.isPicureLink());
|
||||||
|
assertFalse(enr.isStdDocumentNameIdentifier());
|
||||||
|
assertFalse(enr.isValue());
|
||||||
|
|
||||||
|
TestcaseRecordInputStream.confirmRecordEncoding(0x0023, dataPlainName, enr.serialize());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,77 @@
|
|||||||
|
/* ====================================================================
|
||||||
|
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
contributor license agreements. See the NOTICE file distributed with
|
||||||
|
this work for additional information regarding copyright ownership.
|
||||||
|
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
(the "License"); you may not use this file except in compliance with
|
||||||
|
the License. You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
==================================================================== */
|
||||||
|
|
||||||
|
package org.apache.poi.hssf.record.constant;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
import org.apache.poi.hssf.record.RecordInputStream;
|
||||||
|
import org.apache.poi.hssf.record.TestcaseRecordInputStream;
|
||||||
|
import org.apache.poi.hssf.record.UnicodeString;
|
||||||
|
import org.apache.poi.hssf.usermodel.HSSFErrorConstants;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Josh Micich
|
||||||
|
*/
|
||||||
|
public final class TestConstantValueParser extends TestCase {
|
||||||
|
private static final Object[] SAMPLE_VALUES = {
|
||||||
|
Boolean.TRUE,
|
||||||
|
null,
|
||||||
|
new Double(1.1),
|
||||||
|
new UnicodeString("Sample text"),
|
||||||
|
ErrorConstant.valueOf(HSSFErrorConstants.ERROR_DIV_0),
|
||||||
|
};
|
||||||
|
private static final byte[] SAMPLE_ENCODING = {
|
||||||
|
4, 1, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
1, -102, -103, -103, -103, -103, -103, -15, 63,
|
||||||
|
2, 11, 0, 0, 83, 97, 109, 112, 108, 101, 32, 116, 101, 120, 116,
|
||||||
|
16, 7, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
public void testGetEncodedSize() {
|
||||||
|
int actual = ConstantValueParser.getEncodedSize(SAMPLE_VALUES);
|
||||||
|
assertEquals(51, actual);
|
||||||
|
}
|
||||||
|
public void testEncode() {
|
||||||
|
int size = ConstantValueParser.getEncodedSize(SAMPLE_VALUES);
|
||||||
|
byte[] data = new byte[size];
|
||||||
|
ConstantValueParser.encode(data, 0, SAMPLE_VALUES);
|
||||||
|
|
||||||
|
if (!Arrays.equals(data, SAMPLE_ENCODING)) {
|
||||||
|
fail("Encoding differs");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void testDecode() {
|
||||||
|
RecordInputStream in = new TestcaseRecordInputStream(0x0001, SAMPLE_ENCODING);
|
||||||
|
|
||||||
|
Object[] values = ConstantValueParser.parse(in, 4);
|
||||||
|
for (int i = 0; i < values.length; i++) {
|
||||||
|
if(!isEqual(SAMPLE_VALUES[i], values[i])) {
|
||||||
|
fail("Decoded result differs");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private static boolean isEqual(Object a, Object b) {
|
||||||
|
if (a == null) {
|
||||||
|
return b == null;
|
||||||
|
}
|
||||||
|
return a.equals(b);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user