| /* ==================================================================== |
| * 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 |
| * <http://www.apache.org/>. |
| */ |
| |
| package org.apache.poi.hssf.record; |
| |
| import org.apache.poi.util.LittleEndian; |
| import org.apache.poi.util.StringUtil; |
| |
| /** |
| * Title: Bound Sheet Record (aka BundleSheet) <P> |
| * Description: Defines a sheet within a workbook. Basically stores the sheetname |
| * and tells where the Beginning of file record is within the HSSF |
| * file. <P> |
| * REFERENCE: PG 291 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<P> |
| * @author Andrew C. Oliver (acoliver at apache dot org) |
| * @author Sergei Kozello (sergeikozello at mail.ru) |
| * @version 2.0-pre |
| */ |
| |
| public class BoundSheetRecord |
| extends Record |
| { |
| public final static short sid = 0x85; |
| 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 id id must be 0x85 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 BoundSheetRecord( short id, short size, byte[] data ) |
| { |
| super( id, size, data ); |
| } |
| |
| /** |
| * Constructs a BoundSheetRecord and sets its fields appropriately |
| * |
| * @param id id must be 0x85 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 BoundSheetRecord( short id, short size, byte[] data, int offset ) |
| { |
| super( id, size, data, offset ); |
| } |
| |
| 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( byte[] data, short size, int offset ) |
| { |
| field_1_position_of_BOF = LittleEndian.getInt( data, 0 + offset ); // bof |
| field_2_option_flags = LittleEndian.getShort( data, 4 + offset ); // flags |
| field_3_sheetname_length = data[6 + offset]; // len(str) |
| field_4_compressed_unicode_flag = data[7 + offset]; // unicode |
| |
| int nameLength = LittleEndian.ubyteToInt( field_3_sheetname_length ); |
| if ( ( field_4_compressed_unicode_flag & 0x01 ) == 1 ) |
| { |
| field_5_sheetname = StringUtil.getFromUnicodeHigh( data, 8 + offset, nameLength ); |
| } |
| else |
| { |
| field_5_sheetname = StringUtil.getFromCompressedUnicode( data, 8 + offset, 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 |
| * @thows 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; |
| } |
| |
| /** |
| * 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.putUncompressedUnicode( 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 |
| // <str> |
| 0x21, 0x04, 0x42, 0x04, 0x40, 0x04, 0x30, 0x04, 0x3D, |
| 0x04, 0x38, 0x04, 0x47, 0x04, 0x3A, 0x04, 0x30, 0x04 |
| // </str> |
| }; |
| |
| 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 this.sid; |
| } |
| } |