blob: 95c58780648b3d3fd7b3efb952df042b16481d22 [file] [log] [blame]
/* ====================================================================
* 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;
}
}