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
This commit is contained in:
Avik Sengupta 2003-07-25 18:22:20 +00:00
parent b6967b691a
commit abe41db286
8 changed files with 209 additions and 54 deletions

View File

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

View File

@ -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();

View File

@ -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<P>
* Description: Describes a builtin to the gui or user defined style<P>
* REFERENCE: PG 390 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<P>
* @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;
}

View File

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

View File

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

View File

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

Binary file not shown.

View File

@ -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
* <http://www.apache.org/>.
*/
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());
}
}