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