1 /* ==================================================================== 2 * The Apache Software License, Version 1.1 3 * 4 * Copyright (c) 2002 The Apache Software Foundation. All rights 5 * reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in 16 * the documentation and/or other materials provided with the 17 * distribution. 18 * 19 * 3. The end-user documentation included with the redistribution, 20 * if any, must include the following acknowledgment: 21 * "This product includes software developed by the 22 * Apache Software Foundation (http://www.apache.org/)." 23 * Alternately, this acknowledgment may appear in the software itself, 24 * if and wherever such third-party acknowledgments normally appear. 25 * 26 * 4. The names "Apache" and "Apache Software Foundation" and 27 * "Apache POI" must not be used to endorse or promote products 28 * derived from this software without prior written permission. For 29 * written permission, please contact apache@apache.org. 30 * 31 * 5. Products derived from this software may not be called "Apache", 32 * "Apache POI", nor may "Apache" appear in their name, without 33 * prior written permission of the Apache Software Foundation. 34 * 35 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 36 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 37 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 38 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR 39 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 40 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 41 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 42 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 43 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 44 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 45 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 46 * SUCH DAMAGE. 47 * ==================================================================== 48 * 49 * This software consists of voluntary contributions made by many 50 * individuals on behalf of the Apache Software Foundation. For more 51 * information on the Apache Software Foundation, please see 52 * <http://www.apache.org/>. 53 */ 54 55 package org.apache.poi.hssf.record; 56 57 import org.apache.poi.util.LittleEndian; 58 import org.apache.poi.util.StringUtil; 59 60 /** 61 * Title: Bound Sheet Record (aka BundleSheet) <P> 62 * Description: Defines a sheet within a workbook. Basically stores the sheetname 63 * and tells where the Beginning of file record is within the HSSF 64 * file. <P> 65 * REFERENCE: PG 291 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<P> 66 * @author Andrew C. Oliver (acoliver at apache dot org) 67 * @author Sergei Kozello (sergeikozello at mail.ru) 68 * @version 2.0-pre 69 */ 70 71 public class BoundSheetRecord 72 extends Record 73 { 74 public final static short sid = 0x85; 75 private int field_1_position_of_BOF; 76 private short field_2_option_flags; 77 private byte field_3_sheetname_length; 78 private byte field_4_compressed_unicode_flag; // not documented 79 private String field_5_sheetname; 80 81 public BoundSheetRecord() 82 { 83 } 84 85 /** 86 * Constructs a BoundSheetRecord and sets its fields appropriately 87 * 88 * @param id id must be 0x85 or an exception will be throw upon validation 89 * @param size the size of the data area of the record 90 * @param data data of the record (should not contain sid/len) 91 */ 92 93 public BoundSheetRecord( short id, short size, byte[] data ) 94 { 95 super( id, size, data ); 96 } 97 98 /** 99 * Constructs a BoundSheetRecord and sets its fields appropriately 100 * 101 * @param id id must be 0x85 or an exception will be throw upon validation 102 * @param size the size of the data area of the record 103 * @param data data of the record (should not contain sid/len) 104 * @param offset of the record's data 105 */ 106 107 public BoundSheetRecord( short id, short size, byte[] data, int offset ) 108 { 109 super( id, size, data, offset ); 110 } 111 112 protected void validateSid( short id ) 113 { 114 if ( id != sid ) 115 { 116 throw new RecordFormatException( "NOT A Bound Sheet RECORD" ); 117 } 118 } 119 120 /** 121 * UTF8: 122 * sid + len + bof + flags + len(str) + unicode + str 123 * 2 + 2 + 4 + 2 + 1 + 1 + len(str) 124 * 125 * UNICODE: 126 * sid + len + bof + flags + len(str) + unicode + str 127 * 2 + 2 + 4 + 2 + 1 + 1 + 2 * len(str) 128 * 129 */ 130 131 protected void fillFields( byte[] data, short size, int offset ) 132 { 133 field_1_position_of_BOF = LittleEndian.getInt( data, 0 + offset ); // bof 134 field_2_option_flags = LittleEndian.getShort( data, 4 + offset ); // flags 135 field_3_sheetname_length = data[6 + offset]; // len(str) 136 field_4_compressed_unicode_flag = data[7 + offset]; // unicode 137 138 int nameLength = LittleEndian.ubyteToInt( field_3_sheetname_length ); 139 if ( ( field_4_compressed_unicode_flag & 0x01 ) == 1 ) 140 { 141 field_5_sheetname = StringUtil.getFromUnicodeHigh( data, 8 + offset, nameLength ); 142 } 143 else 144 { 145 field_5_sheetname = new String( data, 8 + offset, nameLength ); 146 } 147 } 148 149 /** 150 * set the offset in bytes of the Beginning of File Marker within the HSSF Stream part of the POIFS file 151 * 152 * @param pos offset in bytes 153 */ 154 155 public void setPositionOfBof( int pos ) 156 { 157 field_1_position_of_BOF = pos; 158 } 159 160 /** 161 * set the option flags (unimportant for HSSF supported sheets) 162 * 163 * @param flags to set 164 */ 165 166 public void setOptionFlags( short flags ) 167 { 168 field_2_option_flags = flags; 169 } 170 171 /** 172 * Set the length of the sheetname in characters 173 * 174 * @param len number of characters in the sheet name 175 * @see #setSheetname(String) 176 */ 177 178 public void setSheetnameLength( byte len ) 179 { 180 field_3_sheetname_length = len; 181 } 182 183 /** 184 * set whether or not to interperate the Sheetname as compressed unicode (8/16 bit) 185 * (This is undocumented but can be found as Q187919 on the Microsoft(tm) Support site) 186 * @param flag (0/1) 0- compressed, 1 - uncompressed (16-bit) 187 */ 188 189 public void setCompressedUnicodeFlag( byte flag ) 190 { 191 field_4_compressed_unicode_flag = flag; 192 } 193 194 /** 195 * Set the sheetname for this sheet. (this appears in the tabs at the bottom) 196 * @param sheetname the name of the sheet 197 */ 198 199 public void setSheetname( String sheetname ) 200 { 201 field_5_sheetname = sheetname; 202 } 203 204 /** 205 * get the offset in bytes of the Beginning of File Marker within the HSSF Stream part of the POIFS file 206 * 207 * @return offset in bytes 208 */ 209 210 public int getPositionOfBof() 211 { 212 return field_1_position_of_BOF; 213 } 214 215 /** 216 * get the option flags (unimportant for HSSF supported sheets) 217 * 218 * @return flags to set 219 */ 220 221 public short getOptionFlags() 222 { 223 return field_2_option_flags; 224 } 225 226 /** 227 * get the length of the sheetname in characters 228 * 229 * @return number of characters in the sheet name 230 * @see #getSheetname() 231 */ 232 233 public byte getSheetnameLength() 234 { 235 return field_3_sheetname_length; 236 } 237 238 /** 239 * get the length of the raw sheetname in characters 240 * the length depends on the unicode flag 241 * 242 * @return number of characters in the raw sheet name 243 */ 244 245 public byte getRawSheetnameLength() 246 { 247 return (byte) ( ( ( field_4_compressed_unicode_flag & 0x01 ) == 1 ) 248 ? 2 * field_3_sheetname_length 249 : field_3_sheetname_length ); 250 } 251 252 /** 253 * get whether or not to interperate the Sheetname as compressed unicode (8/16 bit) 254 * (This is undocumented but can be found as Q187919 on the Microsoft(tm) Support site) 255 * @return flag (0/1) 0- compressed, 1 - uncompressed (16-bit) 256 */ 257 258 public byte getCompressedUnicodeFlag() 259 { 260 return field_4_compressed_unicode_flag; 261 } 262 263 /** 264 * get the sheetname for this sheet. (this appears in the tabs at the bottom) 265 * @return sheetname the name of the sheet 266 */ 267 268 public String getSheetname() 269 { 270 return field_5_sheetname; 271 } 272 273 public String toString() 274 { 275 StringBuffer buffer = new StringBuffer(); 276 277 buffer.append( "[BOUNDSHEET]\n" ); 278 buffer.append( " .bof = " ) 279 .append( Integer.toHexString( getPositionOfBof() ) ).append( "\n" ); 280 buffer.append( " .optionflags = " ) 281 .append( Integer.toHexString( getOptionFlags() ) ).append( "\n" ); 282 buffer.append( " .sheetname length= " ) 283 .append( Integer.toHexString( getSheetnameLength() ) ).append( "\n" ); 284 buffer.append( " .unicodeflag = " ) 285 .append( Integer.toHexString( getCompressedUnicodeFlag() ) ) 286 .append( "\n" ); 287 buffer.append( " .sheetname = " ).append( getSheetname() ) 288 .append( "\n" ); 289 buffer.append( "[/BOUNDSHEET]\n" ); 290 return buffer.toString(); 291 } 292 293 public int serialize( int offset, byte[] data ) 294 { 295 LittleEndian.putShort( data, 0 + offset, sid ); 296 LittleEndian.putShort( data, 2 + offset, (short) ( 8 + getRawSheetnameLength() ) ); 297 LittleEndian.putInt( data, 4 + offset, getPositionOfBof() ); 298 LittleEndian.putShort( data, 8 + offset, getOptionFlags() ); 299 data[10 + offset] = (byte) ( getSheetnameLength() ); 300 data[11 + offset] = getCompressedUnicodeFlag(); 301 302 if ( ( field_4_compressed_unicode_flag & 0x01 ) == 1 ) 303 StringUtil.putUncompressedUnicode( getSheetname(), data, 12 + offset ); 304 else 305 StringUtil.putCompressedUnicode( getSheetname(), data, 12 + offset ); 306 307 308 return getRecordSize(); 309 310 /* 311 byte[] fake = new byte[] { (byte)0x85, 0x00, // sid 312 0x1a, 0x00, // length 313 0x3C, 0x09, 0x00, 0x00, // bof 314 0x00, 0x00, // flags 315 0x09, // len( str ) 316 0x01, // unicode 317 // <str> 318 0x21, 0x04, 0x42, 0x04, 0x40, 0x04, 0x30, 0x04, 0x3D, 319 0x04, 0x38, 0x04, 0x47, 0x04, 0x3A, 0x04, 0x30, 0x04 320 // </str> 321 }; 322 323 sid + len + bof + flags + len(str) + unicode + str 324 2 + 2 + 4 + 2 + 1 + 1 + len(str) 325 326 System.arraycopy( fake, 0, data, offset, fake.length ); 327 328 return fake.length; 329 */ 330 } 331 332 public int getRecordSize() 333 { 334 // Includes sid length + size length 335 return 12 + getRawSheetnameLength(); 336 } 337 338 public short getSid() 339 { 340 return this.sid; 341 } 342 } 343