diff --git a/src/documentation/content/xdocs/changes.xml b/src/documentation/content/xdocs/changes.xml index 2549d2c28..939ab4926 100644 --- a/src/documentation/content/xdocs/changes.xml +++ b/src/documentation/content/xdocs/changes.xml @@ -37,6 +37,7 @@ + 47250 - Fixed FontRecord to expect unicode flags even when name length is zero 47198 - Fixed formula evaluator comparison of -0.0 and 0.0 47229 - Fixed ExternalNameRecord to handle DDE links 46287 - Control of header and footer extraction in ExcelExtractor / XSSFExcelExtractor diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml index 5486266da..481dce9d5 100644 --- a/src/documentation/content/xdocs/status.xml +++ b/src/documentation/content/xdocs/status.xml @@ -34,6 +34,7 @@ + 47250 - Fixed FontRecord to expect unicode flags even when name length is zero 47198 - Fixed formula evaluator comparison of -0.0 and 0.0 47229 - Fixed ExternalNameRecord to handle DDE links 46287 - Control of header and footer extraction in ExcelExtractor / XSSFExcelExtractor diff --git a/src/java/org/apache/poi/hssf/record/FontRecord.java b/src/java/org/apache/poi/hssf/record/FontRecord.java index 3b0b4f3e3..b4a9e267b 100644 --- a/src/java/org/apache/poi/hssf/record/FontRecord.java +++ b/src/java/org/apache/poi/hssf/record/FontRecord.java @@ -19,6 +19,7 @@ package org.apache.poi.hssf.record; import org.apache.poi.util.BitField; import org.apache.poi.util.BitFieldFactory; +import org.apache.poi.util.HexDump; import org.apache.poi.util.LittleEndianOutput; import org.apache.poi.util.StringUtil; @@ -30,477 +31,410 @@ import org.apache.poi.util.StringUtil; * @author Andrew C. Oliver (acoliver at apache dot org) */ public final class FontRecord extends StandardRecord { - public final static short sid = 0x0031; // docs are wrong (0x231 Microsoft Support site article Q184647) - public final static short SS_NONE = 0; - public final static short SS_SUPER = 1; - public final static short SS_SUB = 2; - public final static byte U_NONE = 0; - public final static byte U_SINGLE = 1; - public final static byte U_DOUBLE = 2; - public final static byte U_SINGLE_ACCOUNTING = 0x21; - public final static byte U_DOUBLE_ACCOUNTING = 0x22; - private short field_1_font_height; // in units of .05 of a point - private short field_2_attributes; + public final static short sid = 0x0031; // docs are wrong (0x231 Microsoft Support site article Q184647) + public final static short SS_NONE = 0; + public final static short SS_SUPER = 1; + public final static short SS_SUB = 2; + public final static byte U_NONE = 0; + public final static byte U_SINGLE = 1; + public final static byte U_DOUBLE = 2; + public final static byte U_SINGLE_ACCOUNTING = 0x21; + public final static byte U_DOUBLE_ACCOUNTING = 0x22; + private short field_1_font_height; // in units of .05 of a point + private short field_2_attributes; - // 0 0x01 - Reserved bit must be 0 - private static final BitField italic = BitFieldFactory.getInstance(0x02); // is this font in italics + // 0 0x01 - Reserved bit must be 0 + private static final BitField italic = BitFieldFactory.getInstance(0x02); // is this font in italics - // 2 0x04 - reserved bit must be 0 - private static final BitField strikeout =BitFieldFactory.getInstance(0x08); // is this font has a line through the center - private static final BitField macoutline = BitFieldFactory.getInstance(0x10); // some weird macintosh thing....but who understands those mac people anyhow - private static final BitField macshadow = BitFieldFactory.getInstance(0x20); // some weird macintosh thing....but who understands those mac people anyhow + // 2 0x04 - reserved bit must be 0 + private static final BitField strikeout =BitFieldFactory.getInstance(0x08); // is this font has a line through the center + private static final BitField macoutline = BitFieldFactory.getInstance(0x10); // some weird macintosh thing....but who understands those mac people anyhow + private static final BitField macshadow = BitFieldFactory.getInstance(0x20); // some weird macintosh thing....but who understands those mac people anyhow - // 7-6 - reserved bits must be 0 - // the rest is unused - private short field_3_color_palette_index; - private short field_4_bold_weight; - private short field_5_super_sub_script; // 00none/01super/02sub - private byte field_6_underline; // 00none/01single/02double/21singleaccounting/22doubleaccounting - private byte field_7_family; // ?? defined by windows api logfont structure? - private byte field_8_charset; // ?? defined by windows api logfont structure? - private byte field_9_zero = 0; // must be 0 - /** possibly empty string never null */ - private String field_11_font_name; // whoa...the font name + // 7-6 - reserved bits must be 0 + // the rest is unused + private short field_3_color_palette_index; + private short field_4_bold_weight; + private short field_5_super_sub_script; // 00none/01super/02sub + private byte field_6_underline; // 00none/01single/02double/21singleaccounting/22doubleaccounting + private byte field_7_family; // ?? defined by windows api logfont structure? + private byte field_8_charset; // ?? defined by windows api logfont structure? + private byte field_9_zero = 0; // must be 0 + /** possibly empty string never null */ + private String field_11_font_name; - public FontRecord() { - } + public FontRecord() { + } - public FontRecord(RecordInputStream in) { - field_1_font_height = in.readShort(); - field_2_attributes = in.readShort(); - field_3_color_palette_index = in.readShort(); - field_4_bold_weight = in.readShort(); - field_5_super_sub_script = in.readShort(); - field_6_underline = in.readByte(); - field_7_family = in.readByte(); - field_8_charset = in.readByte(); - field_9_zero = in.readByte(); - int field_10_font_name_len = in.readUByte(); - if (field_10_font_name_len > 0) { - if (in.readByte() == 0) { // is compressed unicode - field_11_font_name = in.readCompressedUnicode(field_10_font_name_len); - } else { // is not compressed unicode - field_11_font_name = in.readUnicodeLEString(field_10_font_name_len); - } - } else { - field_11_font_name = ""; - } - } + public FontRecord(RecordInputStream in) { + field_1_font_height = in.readShort(); + field_2_attributes = in.readShort(); + field_3_color_palette_index = in.readShort(); + field_4_bold_weight = in.readShort(); + field_5_super_sub_script = in.readShort(); + field_6_underline = in.readByte(); + field_7_family = in.readByte(); + field_8_charset = in.readByte(); + field_9_zero = in.readByte(); + int field_10_font_name_len = in.readUByte(); + int unicodeFlags = in.readUByte(); // options byte present always (even if no character data) - /** - * sets the height of the font in 1/20th point units - * - * @param height fontheight (in points/20) - */ - - public void setFontHeight(short height) - { - field_1_font_height = height; - } - - /** - * set the font attributes (see individual bit setters that reference this method) - * - * @param attributes the bitmask to set - */ - - public void setAttributes(short attributes) - { - field_2_attributes = attributes; - } - - // attributes bitfields - - /** - * set the font to be italics or not - * - * @param italics - whether the font is italics or not - * @see #setAttributes(short) - */ - - public void setItalic(boolean italics) - { - field_2_attributes = italic.setShortBoolean(field_2_attributes, italics); - } - - /** - * set the font to be stricken out or not - * - * @param strike - whether the font is stricken out or not - * @see #setAttributes(short) - */ - - public void setStrikeout(boolean strike) - { - field_2_attributes = strikeout.setShortBoolean(field_2_attributes, strike); - } - - /** - * whether to use the mac outline font style thing (mac only) - Some mac person - * should comment this instead of me doing it (since I have no idea) - * - * @param mac - whether to do that mac font outline thing or not - * @see #setAttributes(short) - */ - - public void setMacoutline(boolean mac) - { - field_2_attributes = macoutline.setShortBoolean(field_2_attributes, mac); - } - - /** - * whether to use the mac shado font style thing (mac only) - Some mac person - * should comment this instead of me doing it (since I have no idea) - * - * @param mac - whether to do that mac font shadow thing or not - * @see #setAttributes(short) - */ - - public void setMacshadow(boolean mac) - { - field_2_attributes = macshadow.setShortBoolean(field_2_attributes, mac); - } - - /** - * set the font's color palette index - * - * @param cpi - font color index - */ - - public void setColorPaletteIndex(short cpi) - { - field_3_color_palette_index = cpi; - } - - /** - * set the bold weight for this font (100-1000dec or 0x64-0x3e8). Default is - * 0x190 for normal and 0x2bc for bold - * - * @param bw - a number between 100-1000 for the fonts "boldness" - */ - - public void setBoldWeight(short bw) - { - field_4_bold_weight = bw; - } - - /** - * set the type of super or subscript for the font - * - * @param sss super or subscript option - * @see #SS_NONE - * @see #SS_SUPER - * @see #SS_SUB - */ - - public void setSuperSubScript(short sss) - { - field_5_super_sub_script = sss; - } - - /** - * set the type of underlining for the font - * - * @param u super or subscript option - * - * @see #U_NONE - * @see #U_SINGLE - * @see #U_DOUBLE - * @see #U_SINGLE_ACCOUNTING - * @see #U_DOUBLE_ACCOUNTING - */ - - public void setUnderline(byte u) - { - field_6_underline = u; - } - - /** - * set the font family (TODO) - * - * @param f family - */ - - public void setFamily(byte f) - { - field_7_family = f; - } - - /** - * set the character set - * - * @param charset - characterset - */ - - public void setCharset(byte charset) - { - field_8_charset = charset; - } - - - /** - * set the name of the font - * - * @param fn - name of the font (i.e. "Arial") - */ - - public void setFontName(String fn) - { - field_11_font_name = fn; - } - - /** - * gets the height of the font in 1/20th point units - * - * @return fontheight (in points/20) - */ - - public short getFontHeight() - { - return field_1_font_height; - } - - /** - * get the font attributes (see individual bit getters that reference this method) - * - * @return attribute - the bitmask - */ - - public short getAttributes() - { - return field_2_attributes; - } - - /** - * get whether the font is to be italics or not - * - * @return italics - whether the font is italics or not - * @see #getAttributes() - */ - - public boolean isItalic() - { - return italic.isSet(field_2_attributes); - } - - /** - * get whether the font is to be stricken out or not - * - * @return strike - whether the font is stricken out or not - * @see #getAttributes() - */ - - public boolean isStruckout() - { - return strikeout.isSet(field_2_attributes); - } - - /** - * whether to use the mac outline font style thing (mac only) - Some mac person - * should comment this instead of me doing it (since I have no idea) - * - * @return mac - whether to do that mac font outline thing or not - * @see #getAttributes() - */ - - public boolean isMacoutlined() - { - return macoutline.isSet(field_2_attributes); - } - - /** - * whether to use the mac shado font style thing (mac only) - Some mac person - * should comment this instead of me doing it (since I have no idea) - * - * @return mac - whether to do that mac font shadow thing or not - * @see #getAttributes() - */ - - public boolean isMacshadowed() - { - return macshadow.isSet(field_2_attributes); - } - - /** - * get the font's color palette index - * - * @return cpi - font color index - */ - - public short getColorPaletteIndex() - { - return field_3_color_palette_index; - } - - /** - * get the bold weight for this font (100-1000dec or 0x64-0x3e8). Default is - * 0x190 for normal and 0x2bc for bold - * - * @return bw - a number between 100-1000 for the fonts "boldness" - */ - - public short getBoldWeight() - { - return field_4_bold_weight; - } - - /** - * get the type of super or subscript for the font - * - * @return super or subscript option - * @see #SS_NONE - * @see #SS_SUPER - * @see #SS_SUB - */ - - public short getSuperSubScript() - { - return field_5_super_sub_script; - } - - /** - * get the type of underlining for the font - * - * @return super or subscript option - * - * @see #U_NONE - * @see #U_SINGLE - * @see #U_DOUBLE - * @see #U_SINGLE_ACCOUNTING - * @see #U_DOUBLE_ACCOUNTING - */ - - public byte getUnderline() - { - return field_6_underline; - } - - /** - * get the font family (TODO) - * - * @return family - */ - - public byte getFamily() - { - return field_7_family; - } - - /** - * get the character set - * - * @return charset - characterset - */ - - public byte getCharset() - { - return field_8_charset; - } - - /** - * get the name of the font - * - * @return fn - name of the font (i.e. "Arial") - */ - - public String getFontName() - { - return field_11_font_name; - } - - public String toString() - { - StringBuffer buffer = new StringBuffer(); - - buffer.append("[FONT]\n"); - buffer.append(" .fontheight = ") - .append(Integer.toHexString(getFontHeight())).append("\n"); - buffer.append(" .attributes = ") - .append(Integer.toHexString(getAttributes())).append("\n"); - buffer.append(" .italic = ").append(isItalic()) - .append("\n"); - buffer.append(" .strikout = ").append(isStruckout()) - .append("\n"); - buffer.append(" .macoutlined= ").append(isMacoutlined()) - .append("\n"); - buffer.append(" .macshadowed= ").append(isMacshadowed()) - .append("\n"); - buffer.append(" .colorpalette = ") - .append(Integer.toHexString(getColorPaletteIndex())).append("\n"); - buffer.append(" .boldweight = ") - .append(Integer.toHexString(getBoldWeight())).append("\n"); - buffer.append(" .supersubscript = ") - .append(Integer.toHexString(getSuperSubScript())).append("\n"); - buffer.append(" .underline = ") - .append(Integer.toHexString(getUnderline())).append("\n"); - buffer.append(" .family = ") - .append(Integer.toHexString(getFamily())).append("\n"); - buffer.append(" .charset = ") - .append(Integer.toHexString(getCharset())).append("\n"); - buffer.append(" .fontname = ").append(getFontName()) - .append("\n"); - buffer.append("[/FONT]\n"); - return buffer.toString(); - } - - public void serialize(LittleEndianOutput out) { - - out.writeShort(getFontHeight()); - out.writeShort(getAttributes()); - out.writeShort(getColorPaletteIndex()); - out.writeShort(getBoldWeight()); - out.writeShort(getSuperSubScript()); - out.writeByte(getUnderline()); - out.writeByte(getFamily()); - out.writeByte(getCharset()); - out.writeByte(field_9_zero); - int fontNameLen = field_11_font_name.length(); - out.writeByte(fontNameLen); - if (fontNameLen > 0) { - boolean hasMultibyte = StringUtil.hasMultibyte(field_11_font_name); - out.writeByte(hasMultibyte ? 0x01 : 0x00); - if (hasMultibyte) { - StringUtil.putUnicodeLE(field_11_font_name, out); - } else { - StringUtil.putCompressedUnicode(field_11_font_name, out); - } + if (field_10_font_name_len > 0) { + if (unicodeFlags == 0) { // is compressed unicode + field_11_font_name = in.readCompressedUnicode(field_10_font_name_len); + } else { // is not compressed unicode + field_11_font_name = in.readUnicodeLEString(field_10_font_name_len); + } + } else { + field_11_font_name = ""; } - } - protected int getDataSize() { - int size = 15; // 5 shorts + 5 bytes - int fontNameLen = field_11_font_name.length(); - if (fontNameLen < 1) { - // options byte is not encoded if no character data - return size; - } - size ++; // options byte - - boolean hasMultibyte = StringUtil.hasMultibyte(field_11_font_name); - return size + fontNameLen * (hasMultibyte ? 2 : 1); - } + } - public short getSid() - { - return sid; - } - - /** - * Clones all the font style information from another - * FontRecord, onto this one. This - * will then hold all the same font style options. - */ - public void cloneStyleFrom(FontRecord source) { - field_1_font_height = source.field_1_font_height; - field_2_attributes = source.field_2_attributes; - field_3_color_palette_index = source.field_3_color_palette_index; - field_4_bold_weight = source.field_4_bold_weight; - field_5_super_sub_script = source.field_5_super_sub_script; - field_6_underline = source.field_6_underline; - field_7_family = source.field_7_family; - field_8_charset = source.field_8_charset; - field_9_zero = source.field_9_zero; - field_11_font_name = source.field_11_font_name; - } + /** + * sets the height of the font in 1/20th point units + * + * @param height fontheight (in points/20) + */ + public void setFontHeight(short height) { + field_1_font_height = height; + } + + /** + * set the font attributes (see individual bit setters that reference this method) + * + * @param attributes the bitmask to set + */ + public void setAttributes(short attributes) { + field_2_attributes = attributes; + } + + // attributes bitfields + + /** + * set the font to be italics or not + * + * @param italics - whether the font is italics or not + * @see #setAttributes(short) + */ + public void setItalic(boolean italics) { + field_2_attributes = italic.setShortBoolean(field_2_attributes, italics); + } + + /** + * set the font to be stricken out or not + * + * @param strike - whether the font is stricken out or not + * @see #setAttributes(short) + */ + public void setStrikeout(boolean strike) { + field_2_attributes = strikeout.setShortBoolean(field_2_attributes, strike); + } + + /** + * whether to use the mac outline font style thing (mac only) - Some mac person + * should comment this instead of me doing it (since I have no idea) + * + * @param mac - whether to do that mac font outline thing or not + * @see #setAttributes(short) + */ + public void setMacoutline(boolean mac) { + field_2_attributes = macoutline.setShortBoolean(field_2_attributes, mac); + } + + /** + * whether to use the mac shado font style thing (mac only) - Some mac person + * should comment this instead of me doing it (since I have no idea) + * + * @param mac - whether to do that mac font shadow thing or not + * @see #setAttributes(short) + */ + public void setMacshadow(boolean mac) { + field_2_attributes = macshadow.setShortBoolean(field_2_attributes, mac); + } + + /** + * set the font's color palette index + * + * @param cpi - font color index + */ + public void setColorPaletteIndex(short cpi) { + field_3_color_palette_index = cpi; + } + + /** + * set the bold weight for this font (100-1000dec or 0x64-0x3e8). Default is + * 0x190 for normal and 0x2bc for bold + * + * @param bw - a number between 100-1000 for the fonts "boldness" + */ + public void setBoldWeight(short bw) { + field_4_bold_weight = bw; + } + + /** + * set the type of super or subscript for the font + * + * @param sss super or subscript option + * @see #SS_NONE + * @see #SS_SUPER + * @see #SS_SUB + */ + public void setSuperSubScript(short sss) { + field_5_super_sub_script = sss; + } + + /** + * set the type of underlining for the font + * + * @param u super or subscript option + * + * @see #U_NONE + * @see #U_SINGLE + * @see #U_DOUBLE + * @see #U_SINGLE_ACCOUNTING + * @see #U_DOUBLE_ACCOUNTING + */ + public void setUnderline(byte u) { + field_6_underline = u; + } + + /** + * set the font family (TODO) + * + * @param f family + */ + public void setFamily(byte f) { + field_7_family = f; + } + + /** + * set the character set + * + * @param charset - character set + */ + public void setCharset(byte charset) { + field_8_charset = charset; + } + + + /** + * set the name of the font + * + * @param fn - name of the font (i.e. "Arial") + */ + public void setFontName(String fn) { + field_11_font_name = fn; + } + + /** + * gets the height of the font in 1/20th point units + * + * @return fontheight (in points/20) + */ + public short getFontHeight() { + return field_1_font_height; + } + + /** + * get the font attributes (see individual bit getters that reference this method) + * + * @return attribute - the bitmask + */ + public short getAttributes() { + return field_2_attributes; + } + + /** + * get whether the font is to be italics or not + * + * @return italics - whether the font is italics or not + * @see #getAttributes() + */ + public boolean isItalic() { + return italic.isSet(field_2_attributes); + } + + /** + * get whether the font is to be stricken out or not + * + * @return strike - whether the font is stricken out or not + * @see #getAttributes() + */ + public boolean isStruckout(){ + return strikeout.isSet(field_2_attributes); + } + + /** + * whether to use the mac outline font style thing (mac only) - Some mac person + * should comment this instead of me doing it (since I have no idea) + * + * @return mac - whether to do that mac font outline thing or not + * @see #getAttributes() + */ + public boolean isMacoutlined(){ + return macoutline.isSet(field_2_attributes); + } + + /** + * whether to use the mac shado font style thing (mac only) - Some mac person + * should comment this instead of me doing it (since I have no idea) + * + * @return mac - whether to do that mac font shadow thing or not + * @see #getAttributes() + */ + public boolean isMacshadowed(){ + return macshadow.isSet(field_2_attributes); + } + + /** + * get the font's color palette index + * + * @return cpi - font color index + */ + public short getColorPaletteIndex(){ + return field_3_color_palette_index; + } + + /** + * get the bold weight for this font (100-1000dec or 0x64-0x3e8). Default is + * 0x190 for normal and 0x2bc for bold + * + * @return bw - a number between 100-1000 for the fonts "boldness" + */ + public short getBoldWeight(){ + return field_4_bold_weight; + } + + /** + * get the type of super or subscript for the font + * + * @return super or subscript option + * @see #SS_NONE + * @see #SS_SUPER + * @see #SS_SUB + */ + public short getSuperSubScript(){ + return field_5_super_sub_script; + } + + /** + * get the type of underlining for the font + * + * @return super or subscript option + * + * @see #U_NONE + * @see #U_SINGLE + * @see #U_DOUBLE + * @see #U_SINGLE_ACCOUNTING + * @see #U_DOUBLE_ACCOUNTING + */ + public byte getUnderline() { + return field_6_underline; + } + + /** + * get the font family (TODO) + * + * @return family + */ + public byte getFamily() { + return field_7_family; + } + + /** + * get the character set + * + * @return charset - character set + */ + public byte getCharset() { + return field_8_charset; + } + + /** + * get the name of the font + * + * @return fn - name of the font (i.e. "Arial") + */ + public String getFontName() { + return field_11_font_name; + } + + public String toString() { + StringBuffer sb = new StringBuffer(); + + sb.append("[FONT]\n"); + sb.append(" .fontheight = ").append(HexDump.shortToHex(getFontHeight())).append("\n"); + sb.append(" .attributes = ").append(HexDump.shortToHex(getAttributes())).append("\n"); + sb.append(" .italic = ").append(isItalic()).append("\n"); + sb.append(" .strikout = ").append(isStruckout()).append("\n"); + sb.append(" .macoutlined= ").append(isMacoutlined()).append("\n"); + sb.append(" .macshadowed= ").append(isMacshadowed()).append("\n"); + sb.append(" .colorpalette = ").append(HexDump.shortToHex(getColorPaletteIndex())).append("\n"); + sb.append(" .boldweight = ").append(HexDump.shortToHex(getBoldWeight())).append("\n"); + sb.append(" .supersubscript= ").append(HexDump.shortToHex(getSuperSubScript())).append("\n"); + sb.append(" .underline = ").append(HexDump.byteToHex(getUnderline())).append("\n"); + sb.append(" .family = ").append(HexDump.byteToHex(getFamily())).append("\n"); + sb.append(" .charset = ").append(HexDump.byteToHex(getCharset())).append("\n"); + sb.append(" .fontname = ").append(getFontName()).append("\n"); + sb.append("[/FONT]\n"); + return sb.toString(); + } + + public void serialize(LittleEndianOutput out) { + + out.writeShort(getFontHeight()); + out.writeShort(getAttributes()); + out.writeShort(getColorPaletteIndex()); + out.writeShort(getBoldWeight()); + out.writeShort(getSuperSubScript()); + out.writeByte(getUnderline()); + out.writeByte(getFamily()); + out.writeByte(getCharset()); + out.writeByte(field_9_zero); + int fontNameLen = field_11_font_name.length(); + out.writeByte(fontNameLen); + boolean hasMultibyte = StringUtil.hasMultibyte(field_11_font_name); + out.writeByte(hasMultibyte ? 0x01 : 0x00); + if (fontNameLen > 0) { + if (hasMultibyte) { + StringUtil.putUnicodeLE(field_11_font_name, out); + } else { + StringUtil.putCompressedUnicode(field_11_font_name, out); + } + } + } + protected int getDataSize() { + int size = 16; // 5 shorts + 6 bytes + int fontNameLen = field_11_font_name.length(); + if (fontNameLen < 1) { + return size; + } + + boolean hasMultibyte = StringUtil.hasMultibyte(field_11_font_name); + return size + fontNameLen * (hasMultibyte ? 2 : 1); + } + + public short getSid() { + return sid; + } + + /** + * Clones all the font style information from another + * FontRecord, onto this one. This + * will then hold all the same font style options. + */ + public void cloneStyleFrom(FontRecord source) { + field_1_font_height = source.field_1_font_height; + field_2_attributes = source.field_2_attributes; + field_3_color_palette_index = source.field_3_color_palette_index; + field_4_bold_weight = source.field_4_bold_weight; + field_5_super_sub_script = source.field_5_super_sub_script; + field_6_underline = source.field_6_underline; + field_7_family = source.field_7_family; + field_8_charset = source.field_8_charset; + field_9_zero = source.field_9_zero; + field_11_font_name = source.field_11_font_name; + } public int hashCode() { final int prime = 31; @@ -520,7 +454,7 @@ public final class FontRecord extends StandardRecord { result = prime * result + field_9_zero; return result; } - + /** * Does this FontRecord have all the same font * properties as the supplied FontRecord? @@ -528,10 +462,10 @@ public final class FontRecord extends StandardRecord { * for exact objects, while this will check * for exact contents, because normally the * font record's position makes a big - * difference too. + * difference too. */ public boolean sameProperties(FontRecord other) { - return + return field_1_font_height == other.field_1_font_height && field_2_attributes == other.field_2_attributes && field_3_color_palette_index == other.field_3_color_palette_index && @@ -544,17 +478,4 @@ public final class FontRecord extends StandardRecord { field_11_font_name.equals(other.field_11_font_name) ; } - - /** - * Only returns two for the same exact object - - * creating a second FontRecord with the same - * properties won't be considered equal, as - * the record's position in the record stream - * matters. - */ - public boolean equals(Object obj) { - if (this == obj) - return true; - return false; - } } diff --git a/src/testcases/org/apache/poi/hssf/record/TestFontRecord.java b/src/testcases/org/apache/poi/hssf/record/TestFontRecord.java index 3d5e053da..7791df3aa 100644 --- a/src/testcases/org/apache/poi/hssf/record/TestFontRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/TestFontRecord.java @@ -18,14 +18,18 @@ package org.apache.poi.hssf.record; +import junit.framework.AssertionFailedError; import junit.framework.TestCase; +import org.apache.poi.util.HexRead; + /** * Tests the serialization and deserialization of the {@link FontRecord} * class works correctly. Test data taken directly from a real Excel file. */ public final class TestFontRecord extends TestCase { + private static final int SID = 0x31; private static final byte[] data = { 0xC8-256, 00, // font height = xc8 00, 00, // attrs = 0 @@ -87,9 +91,7 @@ public final class TestFontRecord extends TestCase { record.setFontName("Arial"); byte [] recordBytes = record.serialize(); - assertEquals(recordBytes.length - 4, data.length); - for (int i = 0; i < data.length; i++) - assertEquals("At offset " + i, data[i], recordBytes[i+4]); + TestcaseRecordInputStream.confirmRecordEncoding(0x31, data, recordBytes); } public void testCloneOnto() { @@ -104,7 +106,7 @@ public final class TestFontRecord extends TestCase { assertEquals("At offset " + i, data[i], recordBytes[i+4]); } - public void testSameProperties() throws Exception { + public void testSameProperties() { FontRecord f1 = new FontRecord(TestcaseRecordInputStream.create(0x31, data)); FontRecord f2 = new FontRecord(TestcaseRecordInputStream.create(0x31, data)); @@ -120,4 +122,28 @@ public final class TestFontRecord extends TestCase { f2.setFontHeight((short)0xc8); assertTrue(f1.sameProperties(f2)); } + + /** + * Bugzilla 47250 suggests that the unicode options byte should be present even when the name + * length is zero. The OOO documentation seems to agree with this and POI had no test data + * samples to say otherwise. + */ + public void testEmptyName_bug47250() { + byte[] emptyNameData = HexRead.readFromString( + "C8 00 00 00 FF 7F 90 01 00 00 00 00 00 00 " + + "00" // zero length + + "00" // unicode options byte + ); + + RecordInputStream in = TestcaseRecordInputStream.create(SID, emptyNameData); + FontRecord fr = new FontRecord(in); + if (in.available() == 1) { + throw new AssertionFailedError("Identified bug 47250"); + } + assertEquals(0, in.available()); + + assertEquals(0, fr.getFontName().length()); + byte[] recordBytes = fr.serialize(); + TestcaseRecordInputStream.confirmRecordEncoding(SID, emptyNameData, recordBytes); + } }