diff --git a/src/documentation/content/xdocs/changes.xml b/src/documentation/content/xdocs/changes.xml index 577e2c1d1..c1b430122 100644 --- a/src/documentation/content/xdocs/changes.xml +++ b/src/documentation/content/xdocs/changes.xml @@ -37,6 +37,7 @@ + 46917 - Fixed PageItemRecord(SXPI) to allow multiple field infos 46904 - Fix POIFS issue with duplicate block 0 references on very old BIFF5/BIFF7 files 46840 - PageSettingsBlock should include HEADERFOOTER record 46885 - update cell type when setting cached formula result in XSSFCell diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml index af309e998..bc383a269 100644 --- a/src/documentation/content/xdocs/status.xml +++ b/src/documentation/content/xdocs/status.xml @@ -34,6 +34,7 @@ + 46917 - Fixed PageItemRecord(SXPI) to allow multiple field infos 46904 - Fix POIFS issue with duplicate block 0 references on very old BIFF5/BIFF7 files 46840 - PageSettingsBlock should include HEADERFOOTER record 46885 - update cell type when setting cached formula result in XSSFCell diff --git a/src/java/org/apache/poi/hssf/record/pivottable/PageItemRecord.java b/src/java/org/apache/poi/hssf/record/pivottable/PageItemRecord.java index 8dd476c2a..ebcb843cc 100644 --- a/src/java/org/apache/poi/hssf/record/pivottable/PageItemRecord.java +++ b/src/java/org/apache/poi/hssf/record/pivottable/PageItemRecord.java @@ -17,6 +17,7 @@ package org.apache.poi.hssf.record.pivottable; +import org.apache.poi.hssf.record.RecordFormatException; import org.apache.poi.hssf.record.RecordInputStream; import org.apache.poi.hssf.record.StandardRecord; import org.apache.poi.util.HexDump; @@ -30,26 +31,63 @@ import org.apache.poi.util.LittleEndianOutput; public final class PageItemRecord extends StandardRecord { public static final short sid = 0x00B6; - private int isxvi; - private int isxvd; - private int idObj; - - public PageItemRecord(RecordInputStream in) { - isxvi = in.readShort(); - isxvd = in.readShort(); - idObj = in.readShort(); + private static final class FieldInfo { + public static final int ENCODED_SIZE = 6; + /** Index to the View Item SXVI(0x00B2) record */ + private int _isxvi; + /** Index to the {@link ViewFieldsRecord} SXVD(0x00B1) record */ + private int _isxvd; + /** Object ID for the drop-down arrow */ + private int _idObj; + + public FieldInfo(RecordInputStream in) { + _isxvi = in.readShort(); + _isxvd = in.readShort(); + _idObj = in.readShort(); + } + + protected void serialize(LittleEndianOutput out) { + out.writeShort(_isxvi); + out.writeShort(_isxvd); + out.writeShort(_idObj); + } + + public void appendDebugInfo(StringBuffer sb) { + sb.append('('); + sb.append( "isxvi=").append(HexDump.shortToHex(_isxvi)); + sb.append(" isxvd=").append(HexDump.shortToHex(_isxvd)); + sb.append(" idObj=").append(HexDump.shortToHex(_idObj)); + sb.append(')'); + } } - + + private final FieldInfo[] _fieldInfos; + + public PageItemRecord(RecordInputStream in) { + int dataSize = in.remaining(); + if (dataSize % FieldInfo.ENCODED_SIZE != 0) { + throw new RecordFormatException("Bad data size " + dataSize); + } + + int nItems = dataSize / FieldInfo.ENCODED_SIZE; + + FieldInfo[] fis = new FieldInfo[nItems]; + for (int i = 0; i < fis.length; i++) { + fis[i] = new FieldInfo(in); + } + _fieldInfos = fis; + } + @Override protected void serialize(LittleEndianOutput out) { - out.writeShort(isxvi); - out.writeShort(isxvd); - out.writeShort(idObj); + for (int i = 0; i < _fieldInfos.length; i++) { + _fieldInfos[i].serialize(out); + } } @Override protected int getDataSize() { - return 2 + 2 + 2; + return _fieldInfos.length * FieldInfo.ENCODED_SIZE; } @Override @@ -59,14 +97,15 @@ public final class PageItemRecord extends StandardRecord { @Override public String toString() { - StringBuffer buffer = new StringBuffer(); + StringBuffer sb = new StringBuffer(); - buffer.append("[SXPI]\n"); - buffer.append(" .isxvi =").append(HexDump.shortToHex(isxvi)).append('\n'); - buffer.append(" .isxvd =").append(HexDump.shortToHex(isxvd)).append('\n'); - buffer.append(" .idObj =").append(HexDump.shortToHex(idObj)).append('\n'); - - buffer.append("[/SXPI]\n"); - return buffer.toString(); + sb.append("[SXPI]\n"); + for (int i = 0; i < _fieldInfos.length; i++) { + sb.append(" item[").append(i).append("]="); + _fieldInfos[i].appendDebugInfo(sb); + sb.append('\n'); + } + sb.append("[/SXPI]\n"); + return sb.toString(); } } diff --git a/src/testcases/org/apache/poi/hssf/record/pivot/AllPivotRecordTests.java b/src/testcases/org/apache/poi/hssf/record/pivot/AllPivotRecordTests.java index 39546135a..1787317b8 100644 --- a/src/testcases/org/apache/poi/hssf/record/pivot/AllPivotRecordTests.java +++ b/src/testcases/org/apache/poi/hssf/record/pivot/AllPivotRecordTests.java @@ -31,6 +31,8 @@ public final class AllPivotRecordTests { TestSuite result = new TestSuite(AllPivotRecordTests.class.getName()); result.addTestSuite(TestExtendedPivotTableViewFieldsRecord.class); + result.addTestSuite(TestPageItemRecord.class); + result.addTestSuite(TestViewFieldsRecord.class); return result; } } diff --git a/src/testcases/org/apache/poi/hssf/record/pivot/TestPageItemRecord.java b/src/testcases/org/apache/poi/hssf/record/pivot/TestPageItemRecord.java new file mode 100644 index 000000000..7cf3b4929 --- /dev/null +++ b/src/testcases/org/apache/poi/hssf/record/pivot/TestPageItemRecord.java @@ -0,0 +1,63 @@ +/* ==================================================================== + 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.PageItemRecord; +import org.apache.poi.util.HexRead; + +/** + * Tests for {@link PageItemRecord} + * + * @author Josh Micich + */ +public final class TestPageItemRecord extends TestCase { + + public void testMoreThanOneInfoItem_bug46917() { + byte[] data = HexRead.readFromString("01 02 03 04 05 06 07 08 09 0A 0B 0C"); + RecordInputStream in = TestcaseRecordInputStream.create(PageItemRecord.sid, data); + PageItemRecord rec = new PageItemRecord(in); + if (in.remaining() == 6) { + throw new AssertionFailedError("Identified bug 46917"); + } + assertEquals(0, in.remaining()); + + assertEquals(4+data.length, rec.getRecordSize()); + } + + public void testSerialize() { + confirmSerialize("01 02 03 04 05 06"); + confirmSerialize("01 02 03 04 05 06 07 08 09 0A 0B 0C"); + confirmSerialize("01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12"); + } + + private static PageItemRecord confirmSerialize(String hexDump) { + byte[] data = HexRead.readFromString(hexDump); + RecordInputStream in = TestcaseRecordInputStream.create(PageItemRecord.sid, data); + PageItemRecord rec = new PageItemRecord(in); + assertEquals(0, in.remaining()); + assertEquals(4+data.length, rec.getRecordSize()); + byte[] data2 = rec.serialize(); + TestcaseRecordInputStream.confirmRecordEncoding(PageItemRecord.sid, data, data2); + return rec; + } +}