From 8dd000b7de187481a3e8e80bc05f96de76df92a7 Mon Sep 17 00:00:00 2001 From: Josh Micich Date: Thu, 12 Feb 2009 02:28:43 +0000 Subject: [PATCH] Fix for bug 46693 - serialization errors in CHARTFORMAT, SHTPROPS, SXVD and SXVDEX records git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@743601 13f79535-47bb-0310-9956-ffa450edef68 --- src/documentation/content/xdocs/changes.xml | 1 + src/documentation/content/xdocs/status.xml | 1 + .../hssf/record/chart/ChartFormatRecord.java | 96 +++++++-------- .../poi/hssf/record/chart/ChartRecord.java | 110 ++++++++--------- .../hssf/record/chart/SeriesListRecord.java | 19 +-- .../record/chart/SheetPropertiesRecord.java | 113 +++++++----------- .../ExtendedPivotTableViewFieldsRecord.java | 87 +++++++------- .../record/pivottable/ViewFieldsRecord.java | 67 ++++++----- .../poi/hssf/record/AllRecordTests.java | 2 + .../record/chart/AllChartRecordTests.java | 1 + .../record/chart/TestChartFormatRecord.java | 61 ++++++++++ .../chart/TestSheetPropertiesRecord.java | 31 ++--- .../record/pivot/AllPivotRecordTests.java | 36 ++++++ ...estExtendedPivotTableViewFieldsRecord.java | 54 +++++++++ .../record/pivot/TestViewFieldsRecord.java | 64 ++++++++++ 15 files changed, 452 insertions(+), 291 deletions(-) create mode 100644 src/testcases/org/apache/poi/hssf/record/chart/TestChartFormatRecord.java create mode 100644 src/testcases/org/apache/poi/hssf/record/pivot/AllPivotRecordTests.java create mode 100644 src/testcases/org/apache/poi/hssf/record/pivot/TestExtendedPivotTableViewFieldsRecord.java create mode 100644 src/testcases/org/apache/poi/hssf/record/pivot/TestViewFieldsRecord.java diff --git a/src/documentation/content/xdocs/changes.xml b/src/documentation/content/xdocs/changes.xml index 120656ca95..793448a3c7 100644 --- a/src/documentation/content/xdocs/changes.xml +++ b/src/documentation/content/xdocs/changes.xml @@ -37,6 +37,7 @@ + 46693 - Fixed bugs serialization bugs in records: CHARTFORMAT, SHTPROPS, SXVD and SXVDEX 46627 - Fixed offset of added images if Pictures stream contains pictures with zero length diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml index f8b6fb674d..126a0876b9 100644 --- a/src/documentation/content/xdocs/status.xml +++ b/src/documentation/content/xdocs/status.xml @@ -34,6 +34,7 @@ + 46693 - Fixed bugs serialization bugs in records: CHARTFORMAT, SHTPROPS, SXVD and SXVDEX 46627 - Fixed offset of added images if Pictures stream contains pictures with zero length diff --git a/src/java/org/apache/poi/hssf/record/chart/ChartFormatRecord.java b/src/java/org/apache/poi/hssf/record/chart/ChartFormatRecord.java index de17e46125..d7bc8750ad 100644 --- a/src/java/org/apache/poi/hssf/record/chart/ChartFormatRecord.java +++ b/src/java/org/apache/poi/hssf/record/chart/ChartFormatRecord.java @@ -21,14 +21,16 @@ import org.apache.poi.hssf.record.RecordInputStream; import org.apache.poi.hssf.record.StandardRecord; import org.apache.poi.util.BitField; import org.apache.poi.util.BitFieldFactory; +import org.apache.poi.util.HexDump; import org.apache.poi.util.LittleEndianOutput; /** - * Class ChartFormatRecord + * Class ChartFormatRecord (0x1014)

* + * (As with all chart related records, documentation is lacking. + * See {@link ChartRecord} for more details) * * @author Glen Stampoultzis (glens at apache.org) - * @version %I%, %G% */ public final class ChartFormatRecord extends StandardRecord { public static final short sid = 0x1014; @@ -36,40 +38,35 @@ public final class ChartFormatRecord extends StandardRecord { private static final BitField varyDisplayPattern = BitFieldFactory.getInstance(0x01); // ignored? - private int field1_x_position; // lower left - private int field2_y_position; // lower left - private int field3_width; - private int field4_height; - private short field5_grbit; + private int field1_x_position; // lower left + private int field2_y_position; // lower left + private int field3_width; + private int field4_height; + private int field5_grbit; + private int field6_unknown; - public ChartFormatRecord() - { + public ChartFormatRecord() { + // fields uninitialised } - public ChartFormatRecord(RecordInputStream in) - { + public ChartFormatRecord(RecordInputStream in) { field1_x_position = in.readInt(); field2_y_position = in.readInt(); - field3_width = in.readInt(); - field4_height = in.readInt(); - field5_grbit = in.readShort(); + field3_width = in.readInt(); + field4_height = in.readInt(); + field5_grbit = in.readUShort(); + field6_unknown = in.readUShort(); } - public String toString() - { + public String toString() { StringBuffer buffer = new StringBuffer(); buffer.append("[CHARTFORMAT]\n"); - buffer.append(" .xPosition = ").append(getXPosition()) - .append("\n"); - buffer.append(" .yPosition = ").append(getYPosition()) - .append("\n"); - buffer.append(" .width = ").append(getWidth()) - .append("\n"); - buffer.append(" .height = ").append(getHeight()) - .append("\n"); - buffer.append(" .grBit = ") - .append(Integer.toHexString(field5_grbit)).append("\n"); + buffer.append(" .xPosition = ").append(getXPosition()).append("\n"); + buffer.append(" .yPosition = ").append(getYPosition()).append("\n"); + buffer.append(" .width = ").append(getWidth()).append("\n"); + buffer.append(" .height = ").append(getHeight()).append("\n"); + buffer.append(" .grBit = ").append(HexDump.intToHex(field5_grbit)).append("\n"); buffer.append("[/CHARTFORMAT]\n"); return buffer.toString(); } @@ -80,65 +77,54 @@ public final class ChartFormatRecord extends StandardRecord { out.writeInt(getWidth()); out.writeInt(getHeight()); out.writeShort(field5_grbit); + out.writeShort(field6_unknown); } protected int getDataSize() { - return 18; + return 20; // 4 ints and 2 shorts } - public short getSid() - { + public short getSid() { return sid; } - public int getXPosition() - { + public int getXPosition() { return field1_x_position; } - public void setXPosition(int xPosition) - { - this.field1_x_position = xPosition; + public void setXPosition(int xPosition) { + field1_x_position = xPosition; } - public int getYPosition() - { + public int getYPosition() { return field2_y_position; } - public void setYPosition(int yPosition) - { - this.field2_y_position = yPosition; + public void setYPosition(int yPosition) { + field2_y_position = yPosition; } - public int getWidth() - { + public int getWidth() { return field3_width; } - public void setWidth(int width) - { - this.field3_width = width; + public void setWidth(int width) { + field3_width = width; } - public int getHeight() - { + public int getHeight() { return field4_height; } - public void setHeight(int height) - { - this.field4_height = height; + public void setHeight(int height) { + field4_height = height; } - public boolean getVaryDisplayPattern() - { + public boolean getVaryDisplayPattern() { return varyDisplayPattern.isSet(field5_grbit); } - public void setVaryDisplayPattern(boolean value) - { - field5_grbit = varyDisplayPattern.setShortBoolean(field5_grbit, - value); + public void setVaryDisplayPattern(boolean value) { + field5_grbit = varyDisplayPattern.setBoolean(field5_grbit, value); } } diff --git a/src/java/org/apache/poi/hssf/record/chart/ChartRecord.java b/src/java/org/apache/poi/hssf/record/chart/ChartRecord.java index 639a96027f..4299e887d3 100644 --- a/src/java/org/apache/poi/hssf/record/chart/ChartRecord.java +++ b/src/java/org/apache/poi/hssf/record/chart/ChartRecord.java @@ -19,58 +19,56 @@ package org.apache.poi.hssf.record.chart; import org.apache.poi.hssf.record.RecordInputStream; import org.apache.poi.hssf.record.StandardRecord; -import org.apache.poi.util.HexDump; import org.apache.poi.util.LittleEndianOutput; /** - * The chart record is used to define the location and size of a chart. + * CHART (0x1002)

+ * + * The chart record is used to define the location and size of a chart.

+ * + * Chart related records don't seem to be covered in either the + * OOO + * or the + * MS + * documentation. + * + * The book "Microsoft Excel 97 Developer's Kit" ISBN: (1-57231-498-2) seems to have an entire + * chapter (10) devoted to Chart records. One + * blog + * suggests that some documentation for these records is available in "MSDN Library, Feb 1998", + * but no later. + * * @author Glen Stampoultzis (glens at apache.org) */ public final class ChartRecord extends StandardRecord { - public final static short sid = 0x1002; - private int field_1_x; - private int field_2_y; - private int field_3_width; - private int field_4_height; + public final static short sid = 0x1002; + private int field_1_x; + private int field_2_y; + private int field_3_width; + private int field_4_height; - public ChartRecord() - { - + public ChartRecord() { + // fields uninitialised } - public ChartRecord(RecordInputStream in) - { - field_1_x = in.readInt(); - field_2_y = in.readInt(); - field_3_width = in.readInt(); - field_4_height = in.readInt(); + public ChartRecord(RecordInputStream in) { + field_1_x = in.readInt(); + field_2_y = in.readInt(); + field_3_width = in.readInt(); + field_4_height = in.readInt(); } - public String toString() - { - StringBuffer buffer = new StringBuffer(); - - buffer.append("[CHART]\n"); - buffer.append(" .x = ") - .append("0x").append(HexDump.toHex( getX ())) - .append(" (").append( getX() ).append(" )"); - buffer.append(System.getProperty("line.separator")); - buffer.append(" .y = ") - .append("0x").append(HexDump.toHex( getY ())) - .append(" (").append( getY() ).append(" )"); - buffer.append(System.getProperty("line.separator")); - buffer.append(" .width = ") - .append("0x").append(HexDump.toHex( getWidth ())) - .append(" (").append( getWidth() ).append(" )"); - buffer.append(System.getProperty("line.separator")); - buffer.append(" .height = ") - .append("0x").append(HexDump.toHex( getHeight ())) - .append(" (").append( getHeight() ).append(" )"); - buffer.append(System.getProperty("line.separator")); - - buffer.append("[/CHART]\n"); - return buffer.toString(); + public String toString() { + StringBuffer sb = new StringBuffer(); + + sb.append("[CHART]\n"); + sb.append(" .x = ").append(getX()).append('\n'); + sb.append(" .y = ").append(getY()).append('\n'); + sb.append(" .width = ").append(getWidth()).append('\n'); + sb.append(" .height= ").append(getHeight()).append('\n'); + sb.append("[/CHART]\n"); + return sb.toString(); } public void serialize(LittleEndianOutput out) { @@ -105,64 +103,56 @@ public final class ChartRecord extends StandardRecord { /** * Get the x field for the Chart record. */ - public int getX() - { + public int getX() { return field_1_x; } /** * Set the x field for the Chart record. */ - public void setX(int field_1_x) - { - this.field_1_x = field_1_x; + public void setX(int x) { + field_1_x = x; } /** * Get the y field for the Chart record. */ - public int getY() - { + public int getY() { return field_2_y; } /** * Set the y field for the Chart record. */ - public void setY(int field_2_y) - { - this.field_2_y = field_2_y; + public void setY(int y) { + field_2_y = y; } /** * Get the width field for the Chart record. */ - public int getWidth() - { + public int getWidth() { return field_3_width; } /** * Set the width field for the Chart record. */ - public void setWidth(int field_3_width) - { - this.field_3_width = field_3_width; + public void setWidth(int width) { + field_3_width = width; } /** * Get the height field for the Chart record. */ - public int getHeight() - { + public int getHeight() { return field_4_height; } /** * Set the height field for the Chart record. */ - public void setHeight(int field_4_height) - { - this.field_4_height = field_4_height; + public void setHeight(int height) { + field_4_height = height; } } diff --git a/src/java/org/apache/poi/hssf/record/chart/SeriesListRecord.java b/src/java/org/apache/poi/hssf/record/chart/SeriesListRecord.java index 779ae05afe..b67559f194 100644 --- a/src/java/org/apache/poi/hssf/record/chart/SeriesListRecord.java +++ b/src/java/org/apache/poi/hssf/record/chart/SeriesListRecord.java @@ -22,12 +22,12 @@ import org.apache.poi.hssf.record.StandardRecord; import org.apache.poi.util.LittleEndianOutput; /** - * SERIESLIST (0x1016) + * SERIESLIST (0x1016)

* * The series list record defines the series displayed as an overlay to the main chart record.
- * This record doesn't seem to be referenced in either the OOO or MS doc, but this page mentions it - * http://ooxmlisdefectivebydesign.blogspot.com/2008/03/bad-surprise-in-microsoft-office-binary.html * + * (As with all chart related records, documentation is lacking. + * See {@link ChartRecord} for more details) * * @author Glen Stampoultzis (glens at apache.org) */ @@ -73,8 +73,7 @@ public final class SeriesListRecord extends StandardRecord { return field_1_seriesNumbers.length * 2 + 2; } - public short getSid() - { + public short getSid() { return sid; } @@ -88,14 +87,4 @@ public final class SeriesListRecord extends StandardRecord { public short[] getSeriesNumbers() { return field_1_seriesNumbers; } - - /** - * Set the series numbers field for the SeriesList record. - */ - public void setSeriesNumbers(short[] field_1_seriesNumbers) { - this.field_1_seriesNumbers = field_1_seriesNumbers; - } } - - - diff --git a/src/java/org/apache/poi/hssf/record/chart/SheetPropertiesRecord.java b/src/java/org/apache/poi/hssf/record/chart/SheetPropertiesRecord.java index 7ca006354a..eae23a4329 100644 --- a/src/java/org/apache/poi/hssf/record/chart/SheetPropertiesRecord.java +++ b/src/java/org/apache/poi/hssf/record/chart/SheetPropertiesRecord.java @@ -25,8 +25,11 @@ import org.apache.poi.util.HexDump; import org.apache.poi.util.LittleEndianOutput; /** - * Describes a chart sheet properties record.

+ * Describes a chart sheet properties record. SHTPROPS (0x1044)

* + * (As with all chart related records, documentation is lacking. + * See {@link ChartRecord} for more details) + * * @author Glen Stampoultzis (glens at apache.org) */ public final class SheetPropertiesRecord extends StandardRecord { @@ -38,42 +41,33 @@ public final class SheetPropertiesRecord extends StandardRecord { private static final BitField defaultPlotDimensions = BitFieldFactory.getInstance(0x08); private static final BitField autoPlotArea = BitFieldFactory.getInstance(0x10); - private short field_1_flags; - private byte field_2_empty; + private int field_1_flags; + private int field_2_empty; public final static byte EMPTY_NOT_PLOTTED = 0; public final static byte EMPTY_ZERO = 1; public final static byte EMPTY_INTERPOLATED = 2; - public SheetPropertiesRecord() - { - + public SheetPropertiesRecord() { + // fields uninitialised } - public SheetPropertiesRecord(RecordInputStream in) - { - field_1_flags = in.readShort(); - field_2_empty = in.readByte(); + public SheetPropertiesRecord(RecordInputStream in) { + field_1_flags = in.readUShort(); + field_2_empty = in.readUShort(); } - public String toString() - { + public String toString() { StringBuffer buffer = new StringBuffer(); buffer.append("[SHTPROPS]\n"); - buffer.append(" .flags = ") - .append("0x").append(HexDump.toHex( getFlags ())) - .append(" (").append( getFlags() ).append(" )"); - buffer.append(System.getProperty("line.separator")); - buffer.append(" .chartTypeManuallyFormatted = ").append(isChartTypeManuallyFormatted()).append('\n'); - buffer.append(" .plotVisibleOnly = ").append(isPlotVisibleOnly()).append('\n'); - buffer.append(" .doNotSizeWithWindow = ").append(isDoNotSizeWithWindow()).append('\n'); + buffer.append(" .flags = ").append(HexDump.shortToHex(field_1_flags)).append('\n'); + buffer.append(" .chartTypeManuallyFormatted= ").append(isChartTypeManuallyFormatted()).append('\n'); + buffer.append(" .plotVisibleOnly = ").append(isPlotVisibleOnly()).append('\n'); + buffer.append(" .doNotSizeWithWindow = ").append(isDoNotSizeWithWindow()).append('\n'); buffer.append(" .defaultPlotDimensions = ").append(isDefaultPlotDimensions()).append('\n'); - buffer.append(" .autoPlotArea = ").append(isAutoPlotArea()).append('\n'); - buffer.append(" .empty = ") - .append("0x").append(HexDump.toHex( getEmpty ())) - .append(" (").append( getEmpty() ).append(" )"); - buffer.append(System.getProperty("line.separator")); + buffer.append(" .autoPlotArea = ").append(isAutoPlotArea()).append('\n'); + buffer.append(" .empty = ").append(HexDump.shortToHex(field_2_empty)).append('\n'); buffer.append("[/SHTPROPS]\n"); return buffer.toString(); @@ -81,15 +75,14 @@ public final class SheetPropertiesRecord extends StandardRecord { public void serialize(LittleEndianOutput out) { out.writeShort(field_1_flags); - out.writeByte(field_2_empty); + out.writeShort(field_2_empty); } protected int getDataSize() { - return 2 + 1; + return 2 + 2; } - public short getSid() - { + public short getSid() { return sid; } @@ -101,25 +94,13 @@ public final class SheetPropertiesRecord extends StandardRecord { return rec; } - - - /** * Get the flags field for the SheetProperties record. */ - public short getFlags() - { + public int getFlags() { return field_1_flags; } - /** - * Set the flags field for the SheetProperties record. - */ - public void setFlags(short field_1_flags) - { - this.field_1_flags = field_1_flags; - } - /** * Get the empty field for the SheetProperties record. * @@ -128,40 +109,36 @@ public final class SheetPropertiesRecord extends StandardRecord { * EMPTY_ZERO * EMPTY_INTERPOLATED */ - public byte getEmpty() - { + public int getEmpty() { return field_2_empty; } /** * Set the empty field for the SheetProperties record. * - * @param field_2_empty + * @param empty * One of * EMPTY_NOT_PLOTTED * EMPTY_ZERO * EMPTY_INTERPOLATED */ - public void setEmpty(byte field_2_empty) - { - this.field_2_empty = field_2_empty; + public void setEmpty(byte empty) { + this.field_2_empty = empty; } /** * Sets the chart type manually formatted field value. * Has the chart type been manually formatted? */ - public void setChartTypeManuallyFormatted(boolean value) - { - field_1_flags = chartTypeManuallyFormatted.setShortBoolean(field_1_flags, value); + public void setChartTypeManuallyFormatted(boolean value) { + field_1_flags = chartTypeManuallyFormatted.setBoolean(field_1_flags, value); } /** * Has the chart type been manually formatted? * @return the chart type manually formatted field value. */ - public boolean isChartTypeManuallyFormatted() - { + public boolean isChartTypeManuallyFormatted() { return chartTypeManuallyFormatted.isSet(field_1_flags); } @@ -169,17 +146,15 @@ public final class SheetPropertiesRecord extends StandardRecord { * Sets the plot visible only field value. * Only show visible cells on the chart. */ - public void setPlotVisibleOnly(boolean value) - { - field_1_flags = plotVisibleOnly.setShortBoolean(field_1_flags, value); + public void setPlotVisibleOnly(boolean value) { + field_1_flags = plotVisibleOnly.setBoolean(field_1_flags, value); } /** * Only show visible cells on the chart. * @return the plot visible only field value. */ - public boolean isPlotVisibleOnly() - { + public boolean isPlotVisibleOnly() { return plotVisibleOnly.isSet(field_1_flags); } @@ -187,17 +162,15 @@ public final class SheetPropertiesRecord extends StandardRecord { * Sets the do not size with window field value. * Do not size the chart when the window changes size */ - public void setDoNotSizeWithWindow(boolean value) - { - field_1_flags = doNotSizeWithWindow.setShortBoolean(field_1_flags, value); + public void setDoNotSizeWithWindow(boolean value) { + field_1_flags = doNotSizeWithWindow.setBoolean(field_1_flags, value); } /** * Do not size the chart when the window changes size * @return the do not size with window field value. */ - public boolean isDoNotSizeWithWindow() - { + public boolean isDoNotSizeWithWindow() { return doNotSizeWithWindow.isSet(field_1_flags); } @@ -205,17 +178,15 @@ public final class SheetPropertiesRecord extends StandardRecord { * Sets the default plot dimensions field value. * Indicates that the default area dimensions should be used. */ - public void setDefaultPlotDimensions(boolean value) - { - field_1_flags = defaultPlotDimensions.setShortBoolean(field_1_flags, value); + public void setDefaultPlotDimensions(boolean value) { + field_1_flags = defaultPlotDimensions.setBoolean(field_1_flags, value); } /** * Indicates that the default area dimensions should be used. * @return the default plot dimensions field value. */ - public boolean isDefaultPlotDimensions() - { + public boolean isDefaultPlotDimensions() { return defaultPlotDimensions.isSet(field_1_flags); } @@ -223,17 +194,15 @@ public final class SheetPropertiesRecord extends StandardRecord { * Sets the auto plot area field value. * ?? */ - public void setAutoPlotArea(boolean value) - { - field_1_flags = autoPlotArea.setShortBoolean(field_1_flags, value); + public void setAutoPlotArea(boolean value) { + field_1_flags = autoPlotArea.setBoolean(field_1_flags, value); } /** * ?? * @return the auto plot area field value. */ - public boolean isAutoPlotArea() - { + public boolean isAutoPlotArea() { return autoPlotArea.isSet(field_1_flags); } } diff --git a/src/java/org/apache/poi/hssf/record/pivottable/ExtendedPivotTableViewFieldsRecord.java b/src/java/org/apache/poi/hssf/record/pivottable/ExtendedPivotTableViewFieldsRecord.java index 82cae7ac63..92911a1f2b 100644 --- a/src/java/org/apache/poi/hssf/record/pivottable/ExtendedPivotTableViewFieldsRecord.java +++ b/src/java/org/apache/poi/hssf/record/pivottable/ExtendedPivotTableViewFieldsRecord.java @@ -31,61 +31,60 @@ import org.apache.poi.util.StringUtil; public final class ExtendedPivotTableViewFieldsRecord extends StandardRecord { public static final short sid = 0x0100; - /** the value of the cchSubName field when the subName is not present */ - private static final int STRING_NOT_PRESENT_LEN = -1; - - private int grbit1; - private int grbit2; - private int citmShow; - private int isxdiSort; - private int isxdiShow; - private int reserved1; - private int reserved2; - private String subName; - + /** the value of the subname length when the {@link #_subName} is not present */ + private static final int STRING_NOT_PRESENT_LEN = 0xFFFF; + + private int _grbit1; + private int _grbit2; + private int _citmShow; + private int _isxdiSort; + private int _isxdiShow; + private int _reserved1; + private int _reserved2; + private String _subName; + public ExtendedPivotTableViewFieldsRecord(RecordInputStream in) { - - grbit1 = in.readInt(); - grbit2 = in.readUByte(); - citmShow = in.readUByte(); - isxdiSort = in.readUShort(); - isxdiShow = in.readUShort(); + + _grbit1 = in.readInt(); + _grbit2 = in.readUByte(); + _citmShow = in.readUByte(); + _isxdiSort = in.readUShort(); + _isxdiShow = in.readUShort(); int cchSubName = in.readUShort(); - reserved1 = in.readInt(); - reserved2 = in.readInt(); + _reserved1 = in.readInt(); + _reserved2 = in.readInt(); if (cchSubName != STRING_NOT_PRESENT_LEN) { - subName = in.readUnicodeLEString(cchSubName); + _subName = in.readUnicodeLEString(cchSubName); } } - + @Override protected void serialize(LittleEndianOutput out) { - - out.writeInt(grbit1); - out.writeByte(grbit2); - out.writeByte(citmShow); - out.writeShort(isxdiSort); - out.writeShort(isxdiShow); - - if (subName == null) { + + out.writeInt(_grbit1); + out.writeByte(_grbit2); + out.writeByte(_citmShow); + out.writeShort(_isxdiSort); + out.writeShort(_isxdiShow); + + if (_subName == null) { out.writeShort(STRING_NOT_PRESENT_LEN); } else { - out.writeShort(subName.length()); + out.writeShort(_subName.length()); } - - out.writeInt(reserved1); - out.writeInt(reserved2); - if (subName != null) { - StringUtil.putUnicodeLE(subName, out); + + out.writeInt(_reserved1); + out.writeInt(_reserved2); + if (_subName != null) { + StringUtil.putUnicodeLE(_subName, out); } - } @Override protected int getDataSize() { return 4 + 1 + 1 + 2 + 2 + 2 + 4 + 4 + - (subName == null ? 0 : (2*subName.length())); // in unicode + (_subName == null ? 0 : (2*_subName.length())); // in unicode } @Override @@ -99,12 +98,12 @@ public final class ExtendedPivotTableViewFieldsRecord extends StandardRecord { buffer.append("[SXVDEX]\n"); - buffer.append(" .grbit1 =").append(HexDump.intToHex(grbit1)).append("\n"); - buffer.append(" .grbit2 =").append(HexDump.byteToHex(grbit2)).append("\n"); - buffer.append(" .citmShow =").append(HexDump.byteToHex(citmShow)).append("\n"); - buffer.append(" .isxdiSort =").append(HexDump.shortToHex(isxdiSort)).append("\n"); - buffer.append(" .isxdiShow =").append(HexDump.shortToHex(isxdiShow)).append("\n"); - buffer.append(" .subName =").append(subName).append("\n"); + buffer.append(" .grbit1 =").append(HexDump.intToHex(_grbit1)).append("\n"); + buffer.append(" .grbit2 =").append(HexDump.byteToHex(_grbit2)).append("\n"); + buffer.append(" .citmShow =").append(HexDump.byteToHex(_citmShow)).append("\n"); + buffer.append(" .isxdiSort =").append(HexDump.shortToHex(_isxdiSort)).append("\n"); + buffer.append(" .isxdiShow =").append(HexDump.shortToHex(_isxdiShow)).append("\n"); + buffer.append(" .subName =").append(_subName).append("\n"); buffer.append("[/SXVDEX]\n"); return buffer.toString(); } diff --git a/src/java/org/apache/poi/hssf/record/pivottable/ViewFieldsRecord.java b/src/java/org/apache/poi/hssf/record/pivottable/ViewFieldsRecord.java index 9e477ac846..de73f8447b 100644 --- a/src/java/org/apache/poi/hssf/record/pivottable/ViewFieldsRecord.java +++ b/src/java/org/apache/poi/hssf/record/pivottable/ViewFieldsRecord.java @@ -31,18 +31,20 @@ import org.apache.poi.util.StringUtil; public final class ViewFieldsRecord extends StandardRecord { public static final short sid = 0x00B1; - /** the value of the cchName field when the name is not present */ - private static final int STRING_NOT_PRESENT_LEN = -1; + /** the value of the cchName field when the {@link #_name} is not present */ + private static final int STRING_NOT_PRESENT_LEN = 0xFFFF; + /** 5 shorts */ + private static final int BASE_SIZE = 10; - private int sxaxis; - private int cSub; - private int grbitSub; - private int cItm; + private int _sxaxis; + private int _cSub; + private int _grbitSub; + private int _cItm; - private String name = null; + private String _name; /** - * values for the {@link ViewFieldsRecord#sxaxis} field + * values for the {@link ViewFieldsRecord#_sxaxis} field */ private static final class Axis { public static final int NO_AXIS = 0; @@ -53,27 +55,32 @@ public final class ViewFieldsRecord extends StandardRecord { } public ViewFieldsRecord(RecordInputStream in) { - sxaxis = in.readShort(); - cSub = in.readShort(); - grbitSub = in.readShort(); - cItm = in.readShort(); + _sxaxis = in.readShort(); + _cSub = in.readShort(); + _grbitSub = in.readShort(); + _cItm = in.readShort(); - int cchName = in.readShort(); + int cchName = in.readUShort(); if (cchName != STRING_NOT_PRESENT_LEN) { - name = in.readCompressedUnicode(cchName); + int flag = in.readByte(); + if ((flag & 0x01) != 0) { + _name = in.readUnicodeLEString(cchName); + } else { + _name = in.readCompressedUnicode(cchName); + } } } @Override protected void serialize(LittleEndianOutput out) { - out.writeShort(sxaxis); - out.writeShort(cSub); - out.writeShort(grbitSub); - out.writeShort(cItm); + out.writeShort(_sxaxis); + out.writeShort(_cSub); + out.writeShort(_grbitSub); + out.writeShort(_cItm); - if (name != null) { - StringUtil.writeUnicodeString(out, name); + if (_name != null) { + StringUtil.writeUnicodeString(out, _name); } else { out.writeShort(STRING_NOT_PRESENT_LEN); } @@ -81,12 +88,12 @@ public final class ViewFieldsRecord extends StandardRecord { @Override protected int getDataSize() { - - int cchName = 0; - if (name != null) { - cchName = name.length(); + if (_name == null) { + return BASE_SIZE; } - return 2 +2 + 2 + 2 + 2 + cchName; + return BASE_SIZE + + 1 // unicode flag + + _name.length() * (StringUtil.hasMultibyte(_name) ? 2 : 1); } @Override @@ -98,11 +105,11 @@ public final class ViewFieldsRecord extends StandardRecord { public String toString() { StringBuffer buffer = new StringBuffer(); buffer.append("[SXVD]\n"); - buffer.append(" .sxaxis = ").append(HexDump.shortToHex(sxaxis)).append('\n'); - buffer.append(" .cSub = ").append(HexDump.shortToHex(cSub)).append('\n'); - buffer.append(" .grbitSub = ").append(HexDump.shortToHex(grbitSub)).append('\n'); - buffer.append(" .cItm = ").append(HexDump.shortToHex(cItm)).append('\n'); - buffer.append(" .name = ").append(name).append('\n'); + buffer.append(" .sxaxis = ").append(HexDump.shortToHex(_sxaxis)).append('\n'); + buffer.append(" .cSub = ").append(HexDump.shortToHex(_cSub)).append('\n'); + buffer.append(" .grbitSub = ").append(HexDump.shortToHex(_grbitSub)).append('\n'); + buffer.append(" .cItm = ").append(HexDump.shortToHex(_cItm)).append('\n'); + buffer.append(" .name = ").append(_name).append('\n'); buffer.append("[/SXVD]\n"); return buffer.toString(); diff --git a/src/testcases/org/apache/poi/hssf/record/AllRecordTests.java b/src/testcases/org/apache/poi/hssf/record/AllRecordTests.java index db6c7ff3f2..3458051ee7 100755 --- a/src/testcases/org/apache/poi/hssf/record/AllRecordTests.java +++ b/src/testcases/org/apache/poi/hssf/record/AllRecordTests.java @@ -25,6 +25,7 @@ import org.apache.poi.hssf.record.cf.TestCellRange; import org.apache.poi.hssf.record.chart.AllChartRecordTests; import org.apache.poi.hssf.record.constant.TestConstantValueParser; import org.apache.poi.hssf.record.formula.AllFormulaTests; +import org.apache.poi.hssf.record.pivot.AllPivotRecordTests; /** * Collects all tests for package org.apache.poi.hssf.record and sub-packages. @@ -38,6 +39,7 @@ public final class AllRecordTests { result.addTest(AllChartRecordTests.suite()); result.addTest(AllFormulaTests.suite()); + result.addTest(AllPivotRecordTests.suite()); result.addTest(AllRecordAggregateTests.suite()); result.addTestSuite(TestBOFRecord.class); diff --git a/src/testcases/org/apache/poi/hssf/record/chart/AllChartRecordTests.java b/src/testcases/org/apache/poi/hssf/record/chart/AllChartRecordTests.java index 1714e91c02..d2fcf2bd05 100644 --- a/src/testcases/org/apache/poi/hssf/record/chart/AllChartRecordTests.java +++ b/src/testcases/org/apache/poi/hssf/record/chart/AllChartRecordTests.java @@ -39,6 +39,7 @@ public final class AllChartRecordTests { result.addTestSuite(TestAxisUsedRecord.class); result.addTestSuite(TestBarRecord.class); result.addTestSuite(TestCategorySeriesAxisRecord.class); + result.addTestSuite(TestChartFormatRecord.class); result.addTestSuite(TestChartRecord.class); result.addTestSuite(TestChartTitleFormatRecord.class); result.addTestSuite(TestDatRecord.class); diff --git a/src/testcases/org/apache/poi/hssf/record/chart/TestChartFormatRecord.java b/src/testcases/org/apache/poi/hssf/record/chart/TestChartFormatRecord.java new file mode 100644 index 0000000000..52b25057d5 --- /dev/null +++ b/src/testcases/org/apache/poi/hssf/record/chart/TestChartFormatRecord.java @@ -0,0 +1,61 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + +package org.apache.poi.hssf.record.chart; + +import java.util.Arrays; + +import org.apache.poi.hssf.record.RecordInputStream; +import org.apache.poi.hssf.record.TestcaseRecordInputStream; +import org.apache.poi.util.HexRead; + +import junit.framework.AssertionFailedError; +import junit.framework.TestCase; + +/** + * Tests for {@link ChartFormatRecord} Test data taken directly from a real + * Excel file. + * + * @author Josh Micich + */ +public final class TestChartFormatRecord extends TestCase { + /** + * This rather uninteresting data came from attachment 23347 of bug 46693 at + * offsets 0x6BB2 and 0x7BAF + */ + private static final byte[] data = HexRead.readFromString( + "14 10 14 00 " // BIFF header + + "00 00 00 00 00 00 00 00 " + + "00 00 00 00 00 00 00 00 " + + "00 00 00 00"); + + /** + * The correct size of a {@link ChartFormatRecord} is 20 bytes (not including header). + */ + public void testLoad() { + RecordInputStream in = TestcaseRecordInputStream.create(data); + ChartFormatRecord record = new ChartFormatRecord(in); + if (in.remaining() == 2) { + throw new AssertionFailedError("Identified bug 44693d"); + } + assertEquals(0, in.remaining()); + assertEquals(24, record.getRecordSize()); + + byte[] data2 = record.serialize(); + assertTrue(Arrays.equals(data, data2)); + } +} diff --git a/src/testcases/org/apache/poi/hssf/record/chart/TestSheetPropertiesRecord.java b/src/testcases/org/apache/poi/hssf/record/chart/TestSheetPropertiesRecord.java index 51794029ef..ba1415e4db 100644 --- a/src/testcases/org/apache/poi/hssf/record/chart/TestSheetPropertiesRecord.java +++ b/src/testcases/org/apache/poi/hssf/record/chart/TestSheetPropertiesRecord.java @@ -18,27 +18,32 @@ package org.apache.poi.hssf.record.chart; +import org.apache.poi.hssf.record.RecordInputStream; import org.apache.poi.hssf.record.TestcaseRecordInputStream; +import junit.framework.AssertionFailedError; import junit.framework.TestCase; /** - * Tests the serialization and deserialization of the SheetPropertiesRecord - * class works correctly. Test data taken directly from a real - * Excel file. + * Tests for {@link SheetPropertiesRecord} + * Test data taken directly from a real Excel file. * - * @author Glen Stampoultzis (glens at apache.org) */ public final class TestSheetPropertiesRecord extends TestCase { - byte[] data = new byte[] { + private static final byte[] data = { (byte)0x0A,(byte)0x00, - (byte)0x00 - //,(byte)0x00 // not sure where that last byte comes from + (byte)0x00, + (byte)0x00, // not sure where that last byte comes from }; public void testLoad() { - SheetPropertiesRecord record = new SheetPropertiesRecord(TestcaseRecordInputStream.create(0x1044, data)); + RecordInputStream in = TestcaseRecordInputStream.create(0x1044, data); + SheetPropertiesRecord record = new SheetPropertiesRecord(in); + if (in.remaining() == 1) { + throw new AssertionFailedError("Identified bug 44693c"); + } + assertEquals(0, in.remaining()); assertEquals( 10, record.getFlags()); assertEquals( false, record.isChartTypeManuallyFormatted() ); assertEquals( true, record.isPlotVisibleOnly() ); @@ -47,12 +52,10 @@ public final class TestSheetPropertiesRecord extends TestCase { assertEquals( false, record.isAutoPlotArea() ); assertEquals( 0, record.getEmpty()); - - assertEquals( 7, record.getRecordSize() ); + assertEquals( 8, record.getRecordSize() ); } - public void testStore() - { + public void testStore() { SheetPropertiesRecord record = new SheetPropertiesRecord(); record.setChartTypeManuallyFormatted( false ); record.setPlotVisibleOnly( true ); @@ -63,8 +66,6 @@ public final class TestSheetPropertiesRecord extends TestCase { 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(SheetPropertiesRecord.sid, data, recordBytes); } } diff --git a/src/testcases/org/apache/poi/hssf/record/pivot/AllPivotRecordTests.java b/src/testcases/org/apache/poi/hssf/record/pivot/AllPivotRecordTests.java new file mode 100644 index 0000000000..39546135ad --- /dev/null +++ b/src/testcases/org/apache/poi/hssf/record/pivot/AllPivotRecordTests.java @@ -0,0 +1,36 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + +package org.apache.poi.hssf.record.pivot; + +import junit.framework.Test; +import junit.framework.TestSuite; + +/** + * Collects all tests for org.apache.poi.hssf.record.pivot. + * + * @author Josh Micich + */ +public final class AllPivotRecordTests { + + public static Test suite() { + TestSuite result = new TestSuite(AllPivotRecordTests.class.getName()); + + result.addTestSuite(TestExtendedPivotTableViewFieldsRecord.class); + return result; + } +} diff --git a/src/testcases/org/apache/poi/hssf/record/pivot/TestExtendedPivotTableViewFieldsRecord.java b/src/testcases/org/apache/poi/hssf/record/pivot/TestExtendedPivotTableViewFieldsRecord.java new file mode 100644 index 0000000000..7ba15d5c26 --- /dev/null +++ b/src/testcases/org/apache/poi/hssf/record/pivot/TestExtendedPivotTableViewFieldsRecord.java @@ -0,0 +1,54 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + +package org.apache.poi.hssf.record.pivot; + +import org.apache.poi.hssf.record.RecordFormatException; +import org.apache.poi.hssf.record.RecordInputStream; +import org.apache.poi.hssf.record.TestcaseRecordInputStream; +import org.apache.poi.hssf.record.pivottable.ExtendedPivotTableViewFieldsRecord; +import org.apache.poi.util.HexRead; + +import junit.framework.AssertionFailedError; +import junit.framework.TestCase; + +/** + * Tests for {@link ExtendedPivotTableViewFieldsRecord} + * + * @author Josh Micich + */ +public final class TestExtendedPivotTableViewFieldsRecord extends TestCase { + + public void testSubNameNotPresent_bug46693() { + // This data came from attachment 23347 of bug 46693 at offset 0xAA43 + byte[] data = HexRead.readFromString( + "00 01 14 00" + // BIFF header + "1E 14 00 0A FF FF FF FF 00 00 FF FF 00 00 00 00 00 00 00 00"); + RecordInputStream in = TestcaseRecordInputStream.create(data); + ExtendedPivotTableViewFieldsRecord rec; + try { + rec = new ExtendedPivotTableViewFieldsRecord(in); + } catch (RecordFormatException e) { + if (e.getMessage().equals("Expected to find a ContinueRecord in order to read remaining 65535 of 65535 chars")) { + throw new AssertionFailedError("Identified bug 46693a"); + } + throw e; + } + + assertEquals(data.length, rec.getRecordSize()); + } +} diff --git a/src/testcases/org/apache/poi/hssf/record/pivot/TestViewFieldsRecord.java b/src/testcases/org/apache/poi/hssf/record/pivot/TestViewFieldsRecord.java new file mode 100644 index 0000000000..448a2acb3d --- /dev/null +++ b/src/testcases/org/apache/poi/hssf/record/pivot/TestViewFieldsRecord.java @@ -0,0 +1,64 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + +package org.apache.poi.hssf.record.pivot; + +import junit.framework.AssertionFailedError; +import junit.framework.TestCase; + +import org.apache.poi.hssf.record.RecordInputStream; +import org.apache.poi.hssf.record.TestcaseRecordInputStream; +import org.apache.poi.hssf.record.pivottable.ViewFieldsRecord; +import org.apache.poi.util.HexRead; + +/** + * Tests for {@link ViewFieldsRecord} + * + * @author Josh Micich + */ +public final class TestViewFieldsRecord extends TestCase { + + public void testUnicodeFlag_bug46693() { + byte[] data = HexRead.readFromString("01 00 01 00 01 00 04 00 05 00 00 6D 61 72 63 6F"); + RecordInputStream in = TestcaseRecordInputStream.create(ViewFieldsRecord.sid, data); + ViewFieldsRecord rec = new ViewFieldsRecord(in); + if (in.remaining() == 1) { + throw new AssertionFailedError("Identified bug 46693b"); + } + assertEquals(0, in.remaining()); + assertEquals(4+data.length, rec.getRecordSize()); + } + + public void testSerialize() { + // This hex data was produced by changing the 'Custom Name' property, + // available under 'Field Settings' from the 'PivotTable Field List' (Excel 2007) + confirmSerialize("00 00 01 00 01 00 00 00 FF FF"); + confirmSerialize("01 00 01 00 01 00 04 00 05 00 00 6D 61 72 63 6F"); + confirmSerialize("01 00 01 00 01 00 04 00 0A 00 01 48 00 69 00 73 00 74 00 6F 00 72 00 79 00 2D 00 82 69 81 89"); + } + + private static ViewFieldsRecord confirmSerialize(String hexDump) { + byte[] data = HexRead.readFromString(hexDump); + RecordInputStream in = TestcaseRecordInputStream.create(ViewFieldsRecord.sid, data); + ViewFieldsRecord rec = new ViewFieldsRecord(in); + assertEquals(0, in.remaining()); + assertEquals(4+data.length, rec.getRecordSize()); + byte[] data2 = rec.serialize(); + TestcaseRecordInputStream.confirmRecordEncoding(ViewFieldsRecord.sid, data, data2); + return rec; + } +} -- 2.39.5