From: Avik Sengupta Date: Fri, 25 Jul 2003 18:22:20 +0000 (+0000) Subject: bug 15228 and related fixes: X-Git-Tag: REL_2_5_1~104 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=b5b9a5eb07c54428e7d6db24ef1a26948913b26b;p=poi.git bug 15228 and related fixes: 1. Correct structure of NamePtg 2. Correct Unicode handling of strings in StyleRecord and StringPtg 3. Workaround for SheetReferences 4. Ensure correct handling in NameRecord if we cant parse PTGs 5. Ensure correct order of String and SharFormula records 6. Testcase! git-svn-id: https://svn.apache.org/repos/asf/jakarta/poi/branches/REL_2_BRANCH@353244 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/src/java/org/apache/poi/hssf/model/Workbook.java b/src/java/org/apache/poi/hssf/model/Workbook.java index b86f60887c..da1aa129e9 100644 --- a/src/java/org/apache/poi/hssf/model/Workbook.java +++ b/src/java/org/apache/poi/hssf/model/Workbook.java @@ -1729,15 +1729,17 @@ public class Workbook implements Model { } public SheetReferences getSheetReferences() { - SheetReferences refs = new SheetReferences(); - - if (externSheet != null) { - for (int k = 0; k < externSheet.getNumOfREFStructures(); k++) { - String sheetName = findSheetNameFromExternSheet((short)k); - refs.addSheetReference(sheetName, k); - } - } - return refs; + SheetReferences refs = new SheetReferences(); + + if (externSheet != null) { + for (int k = 0; k < externSheet.getNumOfREFStructures(); k++) { + + String sheetName = findSheetNameFromExternSheet((short)k); + refs.addSheetReference(sheetName, k); + + } + } + return refs; } /** finds the sheet name by his extern sheet index @@ -1745,10 +1747,12 @@ public class Workbook implements Model { * @return sheet name */ public String findSheetNameFromExternSheet(short num){ - String result; + String result=""; short indexToSheet = externSheet.getREFRecordAt(num).getIndexToFirstSupBook(); - result = getSheetName(indexToSheet); + if (indexToSheet>-1) { //error check, bail out gracefully! + result = getSheetName(indexToSheet); + } return result; } diff --git a/src/java/org/apache/poi/hssf/record/NameRecord.java b/src/java/org/apache/poi/hssf/record/NameRecord.java index 09bf2a416d..01fe777dfc 100644 --- a/src/java/org/apache/poi/hssf/record/NameRecord.java +++ b/src/java/org/apache/poi/hssf/record/NameRecord.java @@ -794,6 +794,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 +882,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 +908,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/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/aggregates/FormulaRecordAggregate.java b/src/java/org/apache/poi/hssf/record/aggregates/FormulaRecordAggregate.java index 9a7575c21e..e3eb40e201 100644 --- a/src/java/org/apache/poi/hssf/record/aggregates/FormulaRecordAggregate.java +++ b/src/java/org/apache/poi/hssf/record/aggregates/FormulaRecordAggregate.java @@ -119,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; } 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 57c6dccb59..3786cdd694 100644 --- a/src/java/org/apache/poi/hssf/record/formula/NamePtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/NamePtg.java @@ -73,10 +73,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() { @@ -95,13 +95,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() @@ -111,17 +115,15 @@ public class NamePtg public String toFormulaString(SheetReferences refs) { - return "NO IDEA - NAME"; + return "NAMED RANGE"; } public byte getDefaultOperandClass() {return Ptg.CLASS_VALUE;} 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.setClass(ptgClass); + 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/StringPtg.java b/src/java/org/apache/poi/hssf/record/formula/StringPtg.java index 022fffd83c..a66861914e 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.util.BitField; import org.apache.poi.hssf.util.SheetReferences; +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,32 +103,46 @@ 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) @@ -126,7 +155,9 @@ 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/testcases/org/apache/poi/hssf/data/15228.xls b/src/testcases/org/apache/poi/hssf/data/15228.xls new file mode 100644 index 0000000000..3b26ed1e90 Binary files /dev/null and b/src/testcases/org/apache/poi/hssf/data/15228.xls differ diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java b/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java new file mode 100644 index 0000000000..48cec0192a --- /dev/null +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java @@ -0,0 +1,98 @@ +/* ==================================================================== + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2003, 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 + * . + */ + +package org.apache.poi.hssf.usermodel; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Date; + +import junit.framework.TestCase; + + + +/** + * @author Avik Sengupta + */ + +public class TestBugs +extends TestCase { + public TestBugs(String s) { + super(s); + } + + public void test15228() + throws java.io.IOException + { + String readFilename = System.getProperty("HSSF.testdata.path"); + FileInputStream in = new FileInputStream(readFilename+File.separator+"15228.xls"); + HSSFWorkbook wb = new HSSFWorkbook(in); + HSSFSheet s = wb.getSheetAt(0); + HSSFRow r = s.createRow(0); + HSSFCell c = r.createCell((short)0); + c.setCellValue(10); + File file = File.createTempFile("test15228",".xls"); + FileOutputStream out = new FileOutputStream(file); + wb.write(out); + assertTrue("No exception thrown", true); + assertTrue("File Should Exist", file.exists()); + + } + +} + + +