From 08b87dee0feb93c4ad711303fa643e207c0e72f7 Mon Sep 17 00:00:00 2001 From: Josh Micich Date: Tue, 23 Sep 2008 18:52:14 +0000 Subject: [PATCH] Merged revisions 698039 via svnmerge from https://svn.apache.org/repos/asf/poi/trunk ........ r698039 | josh | 2008-09-22 16:43:50 -0700 (Mon, 22 Sep 2008) | 1 line Some clean-up in BoundSheetRecord ........ git-svn-id: https://svn.apache.org/repos/asf/poi/branches/ooxml@698282 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/poi/hssf/model/Workbook.java | 66 +-- .../poi/hssf/record/BoundSheetRecord.java | 519 +++++++----------- .../poi/hssf/usermodel/HSSFWorkbook.java | 41 -- .../apache/poi/hssf/record/TestBOFRecord.java | 21 - .../poi/hssf/record/TestBoundSheetRecord.java | 95 ++-- .../poi/hssf/usermodel/TestSanityChecker.java | 242 ++++---- 6 files changed, 377 insertions(+), 607 deletions(-) diff --git a/src/java/org/apache/poi/hssf/model/Workbook.java b/src/java/org/apache/poi/hssf/model/Workbook.java index 1e37a80ca2..dbf7ecf7e1 100644 --- a/src/java/org/apache/poi/hssf/model/Workbook.java +++ b/src/java/org/apache/poi/hssf/model/Workbook.java @@ -326,15 +326,14 @@ public final class Workbook implements Model { int nBoundSheets = 1; // now just do 1 for ( int k = 0; k < nBoundSheets; k++ ) { - BoundSheetRecord bsr = - (BoundSheetRecord) retval.createBoundSheet( k ); + BoundSheetRecord bsr = retval.createBoundSheet(k); - records.add( bsr ); - retval.boundsheets.add( bsr ); - retval.records.setBspos( records.size() - 1 ); + records.add(bsr); + retval.boundsheets.add(bsr); + retval.records.setBspos(records.size() - 1); } -// retval.records.supbookpos = retval.records.bspos + 1; -// retval.records.namepos = retval.records.supbookpos + 2; + // retval.records.supbookpos = retval.records.bspos + 1; + // retval.records.namepos = retval.records.supbookpos + 2; records.add( retval.createCountry() ); for ( int k = 0; k < nBoundSheets; k++ ) { retval.getOrCreateLinkTable().checkExternSheet(k); @@ -498,7 +497,6 @@ public final class Workbook implements Model { checkSheets(sheetnum); BoundSheetRecord sheet = (BoundSheetRecord)boundsheets.get( sheetnum ); sheet.setSheetname(sheetname); - sheet.setSheetnameLength( (byte)sheetname.length() ); } /** @@ -518,22 +516,6 @@ public final class Workbook implements Model { } return false; } - - /** - * sets the name for a given sheet forcing the encoding. This is STILL A BAD IDEA. - * Poi now automatically detects unicode - * - *@deprecated 3-Jan-06 Simply use setSheetNam e(int sheetnum, String sheetname) - * @param sheetnum the sheet number (0 based) - * @param sheetname the name for the sheet - */ - public void setSheetName(int sheetnum, String sheetname, short encoding ) { - checkSheets(sheetnum); - BoundSheetRecord sheet = getBoundSheetRec(sheetnum); - sheet.setSheetname(sheetname); - sheet.setSheetnameLength( (byte)sheetname.length() ); - sheet.setCompressedUnicodeFlag( (byte)encoding ); - } /** * sets the order of appearance for a given sheet. @@ -643,13 +625,12 @@ public final class Workbook implements Model { * if we're trying to address one more sheet than we have, go ahead and add it! if we're * trying to address >1 more than we have throw an exception! */ - private void checkSheets(int sheetnum) { if ((boundsheets.size()) <= sheetnum) { // if we're short one add another.. if ((boundsheets.size() + 1) <= sheetnum) { throw new RuntimeException("Sheet number out of bounds!"); } - BoundSheetRecord bsr = (BoundSheetRecord ) createBoundSheet(sheetnum); + BoundSheetRecord bsr = createBoundSheet(sheetnum); records.add(records.getBspos()+1, bsr); records.setBspos( records.getBspos() + 1 ); @@ -1860,37 +1841,8 @@ public final class Workbook implements Model { * @see org.apache.poi.hssf.record.BoundSheetRecord * @see org.apache.poi.hssf.record.Record */ - - protected Record createBoundSheet(int id) { // 1,2,3 sheets - BoundSheetRecord retval = new BoundSheetRecord(); - - switch (id) { - - case 0 : - retval.setPositionOfBof(0x0); // should be set later - retval.setOptionFlags(( short ) 0); - retval.setSheetnameLength(( byte ) 0x6); - retval.setCompressedUnicodeFlag(( byte ) 0); - retval.setSheetname("Sheet1"); - break; - - case 1 : - retval.setPositionOfBof(0x0); // should be set later - retval.setOptionFlags(( short ) 0); - retval.setSheetnameLength(( byte ) 0x6); - retval.setCompressedUnicodeFlag(( byte ) 0); - retval.setSheetname("Sheet2"); - break; - - case 2 : - retval.setPositionOfBof(0x0); // should be set later - retval.setOptionFlags(( short ) 0); - retval.setSheetnameLength(( byte ) 0x6); - retval.setCompressedUnicodeFlag(( byte ) 0); - retval.setSheetname("Sheet3"); - break; - } - return retval; + private static BoundSheetRecord createBoundSheet(int id) { + return new BoundSheetRecord("Sheet" + (id+1)); } /** diff --git a/src/java/org/apache/poi/hssf/record/BoundSheetRecord.java b/src/java/org/apache/poi/hssf/record/BoundSheetRecord.java index 412e991d26..2c1d0220f5 100644 --- a/src/java/org/apache/poi/hssf/record/BoundSheetRecord.java +++ b/src/java/org/apache/poi/hssf/record/BoundSheetRecord.java @@ -23,6 +23,7 @@ import java.util.List; import org.apache.poi.util.BitField; import org.apache.poi.util.BitFieldFactory; +import org.apache.poi.util.HexDump; import org.apache.poi.util.LittleEndian; import org.apache.poi.util.StringUtil; @@ -37,327 +38,215 @@ import org.apache.poi.util.StringUtil; * @version 2.0-pre */ public final class BoundSheetRecord extends Record { - public final static short sid = 0x0085; + public final static short sid = 0x0085; private static final BitField hiddenFlag = BitFieldFactory.getInstance(0x01); private static final BitField veryHiddenFlag = BitFieldFactory.getInstance(0x02); - private int field_1_position_of_BOF; - private short field_2_option_flags; - private byte field_3_sheetname_length; - private byte field_4_compressed_unicode_flag; // not documented - private String field_5_sheetname; - - public BoundSheetRecord() - { - } - - /** - * Constructs a BoundSheetRecord and sets its fields appropriately - * - * @param in the RecordInputstream to read the record from - */ - - public BoundSheetRecord( RecordInputStream in ) - { - super( in ); - } - - protected void validateSid( short id ) - { - if ( id != sid ) - { - throw new RecordFormatException( "NOT A Bound Sheet RECORD" ); - } - } - - /** - * UTF8: - * sid + len + bof + flags + len(str) + unicode + str - * 2 + 2 + 4 + 2 + 1 + 1 + len(str) - * - * UNICODE: - * sid + len + bof + flags + len(str) + unicode + str - * 2 + 2 + 4 + 2 + 1 + 1 + 2 * len(str) - * - */ - - protected void fillFields( RecordInputStream in ) - { - field_1_position_of_BOF = in.readInt(); // bof - field_2_option_flags = in.readShort(); // flags - field_3_sheetname_length = in.readByte(); // len(str) - field_4_compressed_unicode_flag = in.readByte(); // unicode - - int nameLength = LittleEndian.ubyteToInt( field_3_sheetname_length ); - if ( ( field_4_compressed_unicode_flag & 0x01 ) == 1 ) - { - field_5_sheetname = in.readUnicodeLEString(nameLength); - } - else - { - field_5_sheetname = in.readCompressedUnicode(nameLength); - } - } - - /** - * set the offset in bytes of the Beginning of File Marker within the HSSF Stream part of the POIFS file - * - * @param pos offset in bytes - */ - - public void setPositionOfBof( int pos ) - { - field_1_position_of_BOF = pos; - } - - /** - * set the option flags (unimportant for HSSF supported sheets) - * - * @param flags to set - */ - - public void setOptionFlags( short flags ) - { - field_2_option_flags = flags; - } - - /** - * Set the length of the sheetname in characters - * - * @param len number of characters in the sheet name - * @see #setSheetname(String) - */ - - public void setSheetnameLength( byte len ) - { - field_3_sheetname_length = len; - } - - /** - * set whether or not to interperate the Sheetname as compressed unicode (8/16 bit) - * (This is undocumented but can be found as Q187919 on the Microsoft(tm) Support site) - * @param flag (0/1) 0- compressed, 1 - uncompressed (16-bit) - */ - - public void setCompressedUnicodeFlag( byte flag ) - { - field_4_compressed_unicode_flag = flag; - } - - /** - * Set the sheetname for this sheet. (this appears in the tabs at the bottom) - * @param sheetname the name of the sheet - * @throws IllegalArgumentException if sheet name will cause excel to crash. - */ - - public void setSheetname( String sheetname ) - { - - if ((sheetname == null) || (sheetname.length()==0) - || (sheetname.length()>31) - || (sheetname.indexOf("/") > -1) - || (sheetname.indexOf("\\") > -1) - || (sheetname.indexOf("?") > -1) - || (sheetname.indexOf("*") > -1) - || (sheetname.indexOf("]") > -1) - || (sheetname.indexOf("[") > -1) ){ - throw new IllegalArgumentException("Sheet name cannot be blank, greater than 31 chars, or contain any of /\\*?[]"); - } - field_5_sheetname = sheetname; - setCompressedUnicodeFlag(StringUtil.hasMultibyte(sheetname) ? (byte)1 : (byte)0); - } - - /** - * get the offset in bytes of the Beginning of File Marker within the HSSF Stream part of the POIFS file - * - * @return offset in bytes - */ - - public int getPositionOfBof() - { - return field_1_position_of_BOF; - } - - /** - * get the option flags (unimportant for HSSF supported sheets) - * - * @return flags to set - */ - - public short getOptionFlags() - { - return field_2_option_flags; - } - - /** - * get the length of the sheetname in characters - * - * @return number of characters in the sheet name - * @see #getSheetname() - */ - - public byte getSheetnameLength() - { - return field_3_sheetname_length; - } - - /** - * get the length of the raw sheetname in characters - * the length depends on the unicode flag - * - * @return number of characters in the raw sheet name - */ - - public byte getRawSheetnameLength() - { - return (byte) ( ( ( field_4_compressed_unicode_flag & 0x01 ) == 1 ) - ? 2 * field_3_sheetname_length - : field_3_sheetname_length ); - } - - /** - * get whether or not to interperate the Sheetname as compressed unicode (8/16 bit) - * (This is undocumented but can be found as Q187919 on the Microsoft(tm) Support site) - * @return flag (0/1) 0- compressed, 1 - uncompressed (16-bit) - */ - - public byte getCompressedUnicodeFlag() - { - return field_4_compressed_unicode_flag; - } - - /** - * get the sheetname for this sheet. (this appears in the tabs at the bottom) - * @return sheetname the name of the sheet - */ - - public String getSheetname() - { - return field_5_sheetname; - } - - public String toString() - { - StringBuffer buffer = new StringBuffer(); - - buffer.append( "[BOUNDSHEET]\n" ); - buffer.append( " .bof = " ) - .append( Integer.toHexString( getPositionOfBof() ) ).append( "\n" ); - buffer.append( " .optionflags = " ) - .append( Integer.toHexString( getOptionFlags() ) ).append( "\n" ); - buffer.append( " .sheetname length= " ) - .append( Integer.toHexString( getSheetnameLength() ) ).append( "\n" ); - buffer.append( " .unicodeflag = " ) - .append( Integer.toHexString( getCompressedUnicodeFlag() ) ) - .append( "\n" ); - buffer.append( " .sheetname = " ).append( getSheetname() ) - .append( "\n" ); - buffer.append( "[/BOUNDSHEET]\n" ); - return buffer.toString(); - } - - public int serialize( int offset, byte[] data ) - { - LittleEndian.putShort( data, 0 + offset, sid ); - LittleEndian.putShort( data, 2 + offset, (short) ( 8 + getRawSheetnameLength() ) ); - LittleEndian.putInt( data, 4 + offset, getPositionOfBof() ); - LittleEndian.putShort( data, 8 + offset, getOptionFlags() ); - data[10 + offset] = (byte) ( getSheetnameLength() ); - data[11 + offset] = getCompressedUnicodeFlag(); - - if ( ( field_4_compressed_unicode_flag & 0x01 ) == 1 ) - StringUtil.putUnicodeLE( getSheetname(), data, 12 + offset ); - else - StringUtil.putCompressedUnicode( getSheetname(), data, 12 + offset ); - - - return getRecordSize(); - - /* - byte[] fake = new byte[] { (byte)0x85, 0x00, // sid - 0x1a, 0x00, // length - 0x3C, 0x09, 0x00, 0x00, // bof - 0x00, 0x00, // flags - 0x09, // len( str ) - 0x01, // unicode - // - 0x21, 0x04, 0x42, 0x04, 0x40, 0x04, 0x30, 0x04, 0x3D, - 0x04, 0x38, 0x04, 0x47, 0x04, 0x3A, 0x04, 0x30, 0x04 - // - }; - - sid + len + bof + flags + len(str) + unicode + str - 2 + 2 + 4 + 2 + 1 + 1 + len(str) - - System.arraycopy( fake, 0, data, offset, fake.length ); - - return fake.length; - */ - } - - public int getRecordSize() - { - // Includes sid length + size length - return 12 + getRawSheetnameLength(); - } - - public short getSid() - { - return sid; - } - - /** - * Is the sheet hidden? Different from very hidden - */ - public boolean isHidden() { - return hiddenFlag.isSet(field_2_option_flags); - } - - /** - * Is the sheet hidden? Different from very hidden - */ - public void setHidden(boolean hidden) { - field_2_option_flags = hiddenFlag.setShortBoolean(field_2_option_flags, hidden); - } - - /** - * Is the sheet very hidden? Different from (normal) hidden - */ - public boolean isVeryHidden() { - return veryHiddenFlag.isSet(field_2_option_flags); - } - - /** - * Is the sheet very hidden? Different from (normal) hidden - */ - public void setVeryHidden(boolean veryHidden) { - field_2_option_flags = veryHiddenFlag.setShortBoolean(field_2_option_flags, veryHidden); - } - - /** - * Takes a list of BoundSheetRecords, and returns the all - * ordered by the position of their BOFs. - */ - public static BoundSheetRecord[] orderByBofPosition(List boundSheetRecords) { - BoundSheetRecord[] bsrs = (BoundSheetRecord[])boundSheetRecords.toArray( - new BoundSheetRecord[boundSheetRecords.size()]); - - // Sort - Arrays.sort(bsrs, new BOFComparator()); - - // All done - return bsrs; - } - private static class BOFComparator implements Comparator { + private int field_1_position_of_BOF; + private int field_2_option_flags; + private int field_4_isMultibyteUnicode; + private String field_5_sheetname; + + public BoundSheetRecord(String sheetname) { + field_2_option_flags = 0; + setSheetname(sheetname); + } + + /** + * Constructs a BoundSheetRecord and sets its fields appropriately + * + * @param in the RecordInputstream to read the record from + */ + public BoundSheetRecord(RecordInputStream in) { + super(in); + } + + protected void validateSid(short id) { + if (id != sid) { + throw new RecordFormatException("NOT A Bound Sheet RECORD"); + } + } + + /** + * UTF8: sid + len + bof + flags + len(str) + unicode + str 2 + 2 + 4 + 2 + + * 1 + 1 + len(str) + * + * UNICODE: sid + len + bof + flags + len(str) + unicode + str 2 + 2 + 4 + 2 + + * 1 + 1 + 2 * len(str) + * + */ + protected void fillFields(RecordInputStream in) { + field_1_position_of_BOF = in.readInt(); + field_2_option_flags = in.readUShort(); + int field_3_sheetname_length = in.readUByte(); + field_4_isMultibyteUnicode = in.readByte(); + + if (isMultibyte()) { + field_5_sheetname = in.readUnicodeLEString(field_3_sheetname_length); + } else { + field_5_sheetname = in.readCompressedUnicode(field_3_sheetname_length); + } + } + + /** + * set the offset in bytes of the Beginning of File Marker within the HSSF + * Stream part of the POIFS file + * + * @param pos + * offset in bytes + */ + public void setPositionOfBof(int pos) { + field_1_position_of_BOF = pos; + } + + /** + * Set the sheetname for this sheet. (this appears in the tabs at the bottom) + * @param sheetName the name of the sheet + * @throws IllegalArgumentException if sheet name will cause excel to crash. + */ + public void setSheetname(String sheetName) { + + validateSheetName(sheetName); + field_5_sheetname = sheetName; + field_4_isMultibyteUnicode = StringUtil.hasMultibyte(sheetName) ? 1 : 0; + } + + private static void validateSheetName(String sheetName) { + if (sheetName == null) { + throw new IllegalArgumentException("sheetName must not be null"); + } + int len = sheetName.length(); + if (len < 1 || len > 31) { + throw new IllegalArgumentException("sheetName '" + sheetName + + "' is invalid - must be 1-30 characters long"); + } + for (int i=0; i