1 2 /* ==================================================================== 3 * The Apache Software License, Version 1.1 4 * 5 * Copyright (c) 2002 The Apache Software Foundation. All rights 6 * reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in 17 * the documentation and/or other materials provided with the 18 * distribution. 19 * 20 * 3. The end-user documentation included with the redistribution, 21 * if any, must include the following acknowledgment: 22 * "This product includes software developed by the 23 * Apache Software Foundation (http://www.apache.org/)." 24 * Alternately, this acknowledgment may appear in the software itself, 25 * if and wherever such third-party acknowledgments normally appear. 26 * 27 * 4. The names "Apache" and "Apache Software Foundation" and 28 * "Apache POI" must not be used to endorse or promote products 29 * derived from this software without prior written permission. For 30 * written permission, please contact apache@apache.org. 31 * 32 * 5. Products derived from this software may not be called "Apache", 33 * "Apache POI", nor may "Apache" appear in their name, without 34 * prior written permission of the Apache Software Foundation. 35 * 36 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 37 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 38 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 39 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR 40 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 41 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 42 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 43 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 44 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 45 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 46 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 47 * SUCH DAMAGE. 48 * ==================================================================== 49 * 50 * This software consists of voluntary contributions made by many 51 * individuals on behalf of the Apache Software Foundation. For more 52 * information on the Apache Software Foundation, please see 53 * <http://www.apache.org/>. 54 */ 55 56 package org.apache.poi.hssf.record; 57 58 import org.apache.poi.util.LittleEndian; 59 import org.apache.poi.util.StringUtil; 60 import org.apache.poi.util.BitField; 61 62 /** 63 * Title: Font Record - descrbes a font in the workbook (index = 0-3,5-infinity - skip 4)<P> 64 * Description: An element in the Font Table<P> 65 * REFERENCE: PG 315 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<P> 66 * @author Andrew C. Oliver (acoliver at apache dot org) 67 * @version 2.0-pre 68 */ 69 70 public class FontRecord 71 extends Record 72 { 73 public final static short sid = 74 0x31; // docs are wrong (0x231 Microsoft Support site article Q184647) 75 public final static short SS_NONE = 0; 76 public final static short SS_SUPER = 1; 77 public final static short SS_SUB = 2; 78 public final static byte U_NONE = 0; 79 public final static byte U_SINGLE = 1; 80 public final static byte U_DOUBLE = 2; 81 public final static byte U_SINGLE_ACCOUNTING = 0x21; 82 public final static byte U_DOUBLE_ACCOUNTING = 0x22; 83 private short field_1_font_height; // in units of .05 of a point 84 private short field_2_attributes; 85 86 // 0 0x01 - Reserved bit must be 0 87 static final private BitField italic = 88 new BitField(0x02); // is this font in italics 89 90 // 2 0x04 - reserved bit must be 0 91 static final private BitField strikeout = 92 new BitField(0x08); // is this font has a line through the center 93 static final private BitField macoutline = new BitField( 94 0x10); // some weird macintosh thing....but who understands those mac people anyhow 95 static final private BitField macshadow = new BitField( 96 0x20); // some weird macintosh thing....but who understands those mac people anyhow 97 98 // 7-6 - reserved bits must be 0 99 // the rest is unused 100 private short field_3_color_palette_index; 101 private short field_4_bold_weight; 102 private short field_5_super_sub_script; // 00none/01super/02sub 103 private byte field_6_underline; // 00none/01single/02double/21singleaccounting/22doubleaccounting 104 private byte field_7_family; // ?? defined by windows api logfont structure? 105 private byte field_8_charset; // ?? defined by windows api logfont structure? 106 private byte field_9_zero = 0; // must be 0 107 private byte field_10_font_name_len; // length of the font name 108 private String field_11_font_name; // whoa...the font name 109 110 public FontRecord() 111 { 112 } 113 114 /** 115 * Constructs a Font record and sets its fields appropriately. 116 * 117 * @param id id must be 0x31 (NOT 0x231 see MSKB #Q184647 for an "explanation of 118 * this bug in the documentation) or an exception will be throw upon validation 119 * @param size the size of the data area of the record 120 * @param data data of the record (should not contain sid/len) 121 */ 122 123 public FontRecord(short id, short size, byte [] data) 124 { 125 super(id, size, data); 126 } 127 128 /** 129 * Constructs a Font record and sets its fields appropriately. 130 * 131 * @param id id must be 0x31 (NOT 0x231 see MSKB #Q184647 for an "explanation of 132 * this bug in the documentation) or an exception will be throw upon validation 133 * @param size the size of the data area of the record 134 * @param data data of the record (should not contain sid/len) 135 * @param offset of the record's data 136 */ 137 138 public FontRecord(short id, short size, byte [] data, int offset) 139 { 140 super(id, size, data, offset); 141 } 142 143 protected void validateSid(short id) 144 { 145 if (id != sid) 146 { 147 throw new RecordFormatException("NOT A FONT RECORD"); 148 } 149 } 150 151 protected void fillFields(byte [] data, short size, int offset) 152 { 153 field_1_font_height = LittleEndian.getShort(data, 0 + offset); 154 field_2_attributes = LittleEndian.getShort(data, 2 + offset); 155 field_3_color_palette_index = LittleEndian.getShort(data, 4 + offset); 156 field_4_bold_weight = LittleEndian.getShort(data, 6 + offset); 157 field_5_super_sub_script = LittleEndian.getShort(data, 8 + offset); 158 field_6_underline = data[ 10 + offset ]; 159 field_7_family = data[ 11 + offset ]; 160 field_8_charset = data[ 12 + offset ]; 161 field_9_zero = data[ 13 + offset ]; 162 field_10_font_name_len = data[ 14 + offset ]; 163 if (field_10_font_name_len > 0) 164 { 165 if (data[ 15 ] == 0) 166 { // is compressed unicode 167 field_11_font_name = new String(data, 16, 168 LittleEndian.ubyteToInt(field_10_font_name_len)); 169 } 170 else 171 { // is not compressed unicode 172 field_11_font_name = StringUtil.getFromUnicodeHigh(data, 16, 173 field_10_font_name_len); 174 } 175 } 176 } 177 178 /** 179 * sets the height of the font in 1/20th point units 180 * 181 * @param height fontheight (in points/20) 182 */ 183 184 public void setFontHeight(short height) 185 { 186 field_1_font_height = height; 187 } 188 189 /** 190 * set the font attributes (see individual bit setters that reference this method) 191 * 192 * @param attributes the bitmask to set 193 */ 194 195 public void setAttributes(short attributes) 196 { 197 field_2_attributes = attributes; 198 } 199 200 // attributes bitfields 201 202 /** 203 * set the font to be italics or not 204 * 205 * @param italics - whether the font is italics or not 206 * @see #setAttributes(short) 207 */ 208 209 public void setItalic(boolean italics) 210 { 211 field_2_attributes = italic.setShortBoolean(field_2_attributes, italics); 212 } 213 214 /** 215 * set the font to be stricken out or not 216 * 217 * @param strike - whether the font is stricken out or not 218 * @see #setAttributes(short) 219 */ 220 221 public void setStrikeout(boolean strike) 222 { 223 field_2_attributes = strikeout.setShortBoolean(field_2_attributes, strike); 224 } 225 226 /** 227 * whether to use the mac outline font style thing (mac only) - Some mac person 228 * should comment this instead of me doing it (since I have no idea) 229 * 230 * @param mac - whether to do that mac font outline thing or not 231 * @see #setAttributes(short) 232 */ 233 234 public void setMacoutline(boolean mac) 235 { 236 field_2_attributes = macoutline.setShortBoolean(field_2_attributes, mac); 237 } 238 239 /** 240 * whether to use the mac shado font style thing (mac only) - Some mac person 241 * should comment this instead of me doing it (since I have no idea) 242 * 243 * @param mac - whether to do that mac font shadow thing or not 244 * @see #setAttributes(short) 245 */ 246 247 public void setMacshadow(boolean mac) 248 { 249 field_2_attributes = macshadow.setShortBoolean(field_2_attributes, mac); 250 } 251 252 /** 253 * set the font's color palette index 254 * 255 * @param cpi - font color index 256 */ 257 258 public void setColorPaletteIndex(short cpi) 259 { 260 field_3_color_palette_index = cpi; 261 } 262 263 /** 264 * set the bold weight for this font (100-1000dec or 0x64-0x3e8). Default is 265 * 0x190 for normal and 0x2bc for bold 266 * 267 * @param bw - a number between 100-1000 for the fonts "boldness" 268 */ 269 270 public void setBoldWeight(short bw) 271 { 272 field_4_bold_weight = bw; 273 } 274 275 /** 276 * set the type of super or subscript for the font 277 * 278 * @param sss super or subscript option 279 * @see #SS_NONE 280 * @see #SS_SUPER 281 * @see #SS_SUB 282 */ 283 284 public void setSuperSubScript(short sss) 285 { 286 field_5_super_sub_script = sss; 287 } 288 289 /** 290 * set the type of underlining for the font 291 * 292 * @param u super or subscript option 293 * 294 * @see #U_NONE 295 * @see #U_SINGLE 296 * @see #U_DOUBLE 297 * @see #U_SINGLE_ACCOUNTING 298 * @see #U_DOUBLE_ACCOUNTING 299 */ 300 301 public void setUnderline(byte u) 302 { 303 field_6_underline = u; 304 } 305 306 /** 307 * set the font family (TODO) 308 * 309 * @param f family 310 */ 311 312 public void setFamily(byte f) 313 { 314 field_7_family = f; 315 } 316 317 /** 318 * set the character set 319 * 320 * @param charset - characterset 321 */ 322 323 public void setCharset(byte charset) 324 { 325 field_8_charset = charset; 326 } 327 328 /** 329 * set the length of the fontname string 330 * 331 * @param len length of the font name 332 * @see #setFontName(String) 333 */ 334 335 public void setFontNameLength(byte len) 336 { 337 field_10_font_name_len = len; 338 } 339 340 /** 341 * set the name of the font 342 * 343 * @param fn - name of the font (i.e. "Arial") 344 */ 345 346 public void setFontName(String fn) 347 { 348 field_11_font_name = fn; 349 } 350 351 /** 352 * gets the height of the font in 1/20th point units 353 * 354 * @return fontheight (in points/20) 355 */ 356 357 public short getFontHeight() 358 { 359 return field_1_font_height; 360 } 361 362 /** 363 * get the font attributes (see individual bit getters that reference this method) 364 * 365 * @return attribute - the bitmask 366 */ 367 368 public short getAttributes() 369 { 370 return field_2_attributes; 371 } 372 373 /** 374 * get whether the font is to be italics or not 375 * 376 * @return italics - whether the font is italics or not 377 * @see #getAttributes() 378 */ 379 380 public boolean isItalic() 381 { 382 return italic.isSet(field_2_attributes); 383 } 384 385 /** 386 * get whether the font is to be stricken out or not 387 * 388 * @return strike - whether the font is stricken out or not 389 * @see #getAttributes() 390 */ 391 392 public boolean isStruckout() 393 { 394 return strikeout.isSet(field_2_attributes); 395 } 396 397 /** 398 * whether to use the mac outline font style thing (mac only) - Some mac person 399 * should comment this instead of me doing it (since I have no idea) 400 * 401 * @return mac - whether to do that mac font outline thing or not 402 * @see #getAttributes() 403 */ 404 405 public boolean isMacoutlined() 406 { 407 return macoutline.isSet(field_2_attributes); 408 } 409 410 /** 411 * whether to use the mac shado font style thing (mac only) - Some mac person 412 * should comment this instead of me doing it (since I have no idea) 413 * 414 * @return mac - whether to do that mac font shadow thing or not 415 * @see #getAttributes() 416 */ 417 418 public boolean isMacshadowed() 419 { 420 return macshadow.isSet(field_2_attributes); 421 } 422 423 /** 424 * get the font's color palette index 425 * 426 * @return cpi - font color index 427 */ 428 429 public short getColorPaletteIndex() 430 { 431 return field_3_color_palette_index; 432 } 433 434 /** 435 * get the bold weight for this font (100-1000dec or 0x64-0x3e8). Default is 436 * 0x190 for normal and 0x2bc for bold 437 * 438 * @return bw - a number between 100-1000 for the fonts "boldness" 439 */ 440 441 public short getBoldWeight() 442 { 443 return field_4_bold_weight; 444 } 445 446 /** 447 * get the type of super or subscript for the font 448 * 449 * @return super or subscript option 450 * @see #SS_NONE 451 * @see #SS_SUPER 452 * @see #SS_SUB 453 */ 454 455 public short getSuperSubScript() 456 { 457 return field_5_super_sub_script; 458 } 459 460 /** 461 * get the type of underlining for the font 462 * 463 * @return super or subscript option 464 * 465 * @see #U_NONE 466 * @see #U_SINGLE 467 * @see #U_DOUBLE 468 * @see #U_SINGLE_ACCOUNTING 469 * @see #U_DOUBLE_ACCOUNTING 470 */ 471 472 public byte getUnderline() 473 { 474 return field_6_underline; 475 } 476 477 /** 478 * get the font family (TODO) 479 * 480 * @return family 481 */ 482 483 public byte getFamily() 484 { 485 return field_7_family; 486 } 487 488 /** 489 * get the character set 490 * 491 * @return charset - characterset 492 */ 493 494 public byte getCharset() 495 { 496 return field_8_charset; 497 } 498 499 /** 500 * get the length of the fontname string 501 * 502 * @return length of the font name 503 * @see #getFontName() 504 */ 505 506 public byte getFontNameLength() 507 { 508 return field_10_font_name_len; 509 } 510 511 /** 512 * get the name of the font 513 * 514 * @return fn - name of the font (i.e. "Arial") 515 */ 516 517 public String getFontName() 518 { 519 return field_11_font_name; 520 } 521 522 public String toString() 523 { 524 StringBuffer buffer = new StringBuffer(); 525 526 buffer.append("[FONT]\n"); 527 buffer.append(" .fontheight = ") 528 .append(Integer.toHexString(getFontHeight())).append("\n"); 529 buffer.append(" .attributes = ") 530 .append(Integer.toHexString(getAttributes())).append("\n"); 531 buffer.append(" .italic = ").append(isItalic()) 532 .append("\n"); 533 buffer.append(" .strikout = ").append(isStruckout()) 534 .append("\n"); 535 buffer.append(" .macoutlined= ").append(isMacoutlined()) 536 .append("\n"); 537 buffer.append(" .macshadowed= ").append(isMacshadowed()) 538 .append("\n"); 539 buffer.append(" .colorpalette = ") 540 .append(Integer.toHexString(getColorPaletteIndex())).append("\n"); 541 buffer.append(" .boldweight = ") 542 .append(Integer.toHexString(getBoldWeight())).append("\n"); 543 buffer.append(" .supersubscript = ") 544 .append(Integer.toHexString(getSuperSubScript())).append("\n"); 545 buffer.append(" .underline = ") 546 .append(Integer.toHexString(getUnderline())).append("\n"); 547 buffer.append(" .family = ") 548 .append(Integer.toHexString(getFamily())).append("\n"); 549 buffer.append(" .charset = ") 550 .append(Integer.toHexString(getCharset())).append("\n"); 551 buffer.append(" .namelength = ") 552 .append(Integer.toHexString(getFontNameLength())).append("\n"); 553 buffer.append(" .fontname = ").append(getFontName()) 554 .append("\n"); 555 buffer.append("[/FONT]\n"); 556 return buffer.toString(); 557 } 558 559 public int serialize(int offset, byte [] data) 560 { 561 int realflen = getFontNameLength() * 2; 562 563 LittleEndian.putShort(data, 0 + offset, sid); 564 LittleEndian.putShort( 565 data, 2 + offset, 566 ( short ) (15 + realflen 567 + 1)); // 19 - 4 (sid/len) + font name length = datasize 568 569 // undocumented single byte (1) 570 LittleEndian.putShort(data, 4 + offset, getFontHeight()); 571 LittleEndian.putShort(data, 6 + offset, getAttributes()); 572 LittleEndian.putShort(data, 8 + offset, getColorPaletteIndex()); 573 LittleEndian.putShort(data, 10 + offset, getBoldWeight()); 574 LittleEndian.putShort(data, 12 + offset, getSuperSubScript()); 575 data[ 14 + offset ] = getUnderline(); 576 data[ 15 + offset ] = getFamily(); 577 data[ 16 + offset ] = getCharset(); 578 data[ 17 + offset ] = (( byte ) 0); 579 data[ 18 + offset ] = getFontNameLength(); 580 data[ 19 + offset ] = ( byte ) 1; 581 StringUtil.putUncompressedUnicode(getFontName(), data, 20 + offset); 582 return getRecordSize(); 583 } 584 585 public int getRecordSize() 586 { 587 return (getFontNameLength() * 2) + 20; 588 } 589 590 public short getSid() 591 { 592 return this.sid; 593 } 594 } 595