+ * Usage:
*
- * with hex dumps of records
+ * BiffViewer [--biffhex] [--noint] [--out] <fileName>
+ * BiffViewer --rawhex [--out] <fileName>
+ *
+ *
+ *
--biffhex | show hex dump of each BIFF record |
--noint | do not output interpretation of BIFF records |
--out | send output to <fileName>.out |
--rawhex | output raw hex dump of whole workbook stream |
* Define the system property
@@ -51,7 +52,8 @@ public final class RecordFactory {
* contains the classes for all the records we want to parse.poi.deserialize.escher
to turn on
* deserialization of escher records.
*
*/
public static void main(String[] args) {
- System.setProperty("poi.deserialize.escher", "true");
-
- if (args.length == 0) {
- System.out.println( "Biff viewer needs a filename" );
+ CommandArgs cmdArgs;
+ try {
+ cmdArgs = CommandArgs.parse(args);
+ } catch (CommandParseException e) {
+ e.printStackTrace();
return;
}
+ System.setProperty("poi.deserialize.escher", "true");
+
+
try {
- String inFileName = args[0];
- File inputFile = new File(inFileName);
- if(!inputFile.exists()) {
- throw new RuntimeException("specified inputFile '" + inFileName + "' does not exist");
- }
+
PrintStream ps;
- if (false) { // set to true to output to file
- OutputStream os = new FileOutputStream(inFileName + ".out");
+ if (cmdArgs.shouldOutputToFile()) {
+ OutputStream os = new FileOutputStream(cmdArgs.getFile().getAbsolutePath() + ".out");
ps = new PrintStream(os);
} else {
ps = System.out;
}
-
- if (args.length > 1 && args[1].equals("bfd")) {
- POIFSFileSystem fs = new POIFSFileSystem(new FileInputStream(inputFile));
- InputStream stream = fs.createDocumentInputStream("Workbook");
- int size = stream.available();
+
+ POIFSFileSystem fs = new POIFSFileSystem(new FileInputStream(cmdArgs.getFile()));
+ InputStream is = fs.createDocumentInputStream("Workbook");
+
+ if (cmdArgs.shouldOutputRawHexOnly()) {
+ int size = is.available();
byte[] data = new byte[size];
- stream.read(data);
+ is.read(data);
HexDump.dump(data, 0, System.out, 0);
} else {
- boolean dumpInterpretedRecords = true;
- boolean dumpHex = args.length > 1 && args[1].equals("on");
-
- POIFSFileSystem fs = new POIFSFileSystem(new FileInputStream(inputFile));
- InputStream is = fs.createDocumentInputStream("Workbook");
- BiffRecordListener recListener = new BiffRecordListener(dumpHex ? new OutputStreamWriter(ps) : null);
+ boolean dumpInterpretedRecords = cmdArgs.shouldDumpRecordInterpretations();
+ boolean dumpHex = cmdArgs.shouldDumpBiffHex();
+ boolean zeroAlignHexDump = dumpInterpretedRecords;
+ BiffRecordListener recListener = new BiffRecordListener(dumpHex ? new OutputStreamWriter(ps) : null, zeroAlignHexDump);
is = new BiffDumpingStream(is, recListener);
createRecords(is, ps, recListener, dumpInterpretedRecords);
}
@@ -295,10 +392,12 @@ public final class BiffViewer {
private static final class BiffRecordListener implements IBiffRecordListener {
private final Writer _hexDumpWriter;
- private final List _headers;
- public BiffRecordListener(Writer hexDumpWriter) {
+ private final List
* Note - this most but not *every* subclass of Record.
*/
- private static final Class[] recordClasses = {
+ @SuppressWarnings("unchecked")
+ private static final Class extends Record>[] recordClasses = new Class[] {
ArrayRecord.class,
BackupRecord.class,
BlankRecord.class,
@@ -148,6 +150,7 @@ public final class RecordFactory {
SupBookRecord.class,
TabIdRecord.class,
TableRecord.class,
+ TableStylesRecord.class,
TextObjectRecord.class,
TopMarginRecord.class,
UncalcedRecord.class,
@@ -161,18 +164,26 @@ public final class RecordFactory {
WriteProtectRecord.class,
WSBoolRecord.class,
- LinkedDataRecord.class,
-
+ // chart records
+ BeginRecord.class,
ChartFRTInfoRecord.class,
ChartStartBlockRecord.class,
ChartEndBlockRecord.class,
ChartStartObjectRecord.class,
ChartEndObjectRecord.class,
CatLabRecord.class,
-
- BeginRecord.class,
EndRecord.class,
+ LinkedDataRecord.class,
SeriesToChartGroupRecord.class,
+
+ // pivot table records
+ DataItemRecord.class,
+ ExtendedPivotTableViewFieldsRecord.class,
+ PageItemRecord.class,
+ StreamIDRecord.class,
+ ViewDefinitionRecord.class,
+ ViewFieldsRecord.class,
+ ViewSourceRecord.class,
};
/**
@@ -291,7 +302,7 @@ public final class RecordFactory {
_allKnownRecordSIDs = results;
}
- return (short[]) _allKnownRecordSIDs.clone();
+ return _allKnownRecordSIDs.clone();
}
/**
@@ -299,13 +310,13 @@ public final class RecordFactory {
* @return map of SIDs to short,short,byte[] constructors for Record classes
* most of org.apache.poi.hssf.record.*
*/
- private static Map recordsToMap(Class [] records) {
- Map result = new HashMap();
- Set uniqueRecClasses = new HashSet(records.length * 3 / 2);
+ private static Map
+ *
+ * @author Patrick Cheng
+ */
+public final class TableStylesRecord extends StandardRecord {
+ public static final short sid = 0x088E;
+
+ private int rt;
+ private int grbitFrt;
+ private byte[] unused = new byte[8];
+ private int cts;
+
+ private String rgchDefListStyle;
+ private String rgchDefPivotStyle;
+
+
+ public TableStylesRecord(RecordInputStream in) {
+ rt = in.readUShort();
+ grbitFrt = in.readUShort();
+ in.readFully(unused);
+ cts = in.readInt();
+ int cchDefListStyle = in.readUShort();
+ int cchDefPivotStyle = in.readUShort();
+
+ rgchDefListStyle = in.readUnicodeLEString(cchDefListStyle);
+ rgchDefPivotStyle = in.readUnicodeLEString(cchDefPivotStyle);
+ }
+
+ @Override
+ protected void serialize(LittleEndianOutput out) {
+ out.writeShort(rt);
+ out.writeShort(grbitFrt);
+ out.write(unused);
+ out.writeInt(cts);
+
+ out.writeShort(rgchDefListStyle.length());
+ out.writeShort(rgchDefPivotStyle.length());
+
+ StringUtil.putUnicodeLE(rgchDefListStyle, out);
+ StringUtil.putUnicodeLE(rgchDefPivotStyle, out);
+ }
+
+ @Override
+ protected int getDataSize() {
+ return 2 + 2 + 8 + 4 + 2 + 2
+ + (2*rgchDefListStyle.length()) + (2*rgchDefPivotStyle.length());
+ }
+
+ @Override
+ public short getSid() {
+ return sid;
+ }
+
+
+ @Override
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+
+ buffer.append("[TABLESTYLES]\n");
+ buffer.append(" .rt =").append(HexDump.shortToHex(rt)).append('\n');
+ buffer.append(" .grbitFrt=").append(HexDump.shortToHex(grbitFrt)).append('\n');
+ buffer.append(" .unused =").append(HexDump.toHex(unused)).append('\n');
+ buffer.append(" .cts=").append(HexDump.intToHex(cts)).append('\n');
+ buffer.append(" .rgchDefListStyle=").append(rgchDefListStyle).append('\n');
+ buffer.append(" .rgchDefPivotStyle=").append(rgchDefPivotStyle).append('\n');
+
+ buffer.append("[/TABLESTYLES]\n");
+ return buffer.toString();
+ }
+}
diff --git a/src/java/org/apache/poi/hssf/record/UnknownRecord.java b/src/java/org/apache/poi/hssf/record/UnknownRecord.java
index bd16fb604..6ece4782f 100644
--- a/src/java/org/apache/poi/hssf/record/UnknownRecord.java
+++ b/src/java/org/apache/poi/hssf/record/UnknownRecord.java
@@ -39,7 +39,6 @@ public final class UnknownRecord extends StandardRecord {
public static final int SHEETPR_0081 = 0x0081;
public static final int STANDARDWIDTH_0099 = 0x0099;
public static final int SCL_00A0 = 0x00A0;
- public static final int SXVIEW_00B0 = 0x00B0;
public static final int BITMAP_00E9 = 0x00E9;
public static final int PHONETICPR_00EF = 0x00EF;
public static final int LABELRANGES_015F = 0x015F;
@@ -122,21 +121,19 @@ public final class UnknownRecord extends StandardRecord {
// this method any time a new Record subclass is created.
switch (sid) {
case PLS_004D: return "PLS";
- case 0x0050: return "DCON";
+ case 0x0050: return "DCON"; // Data Consolidation Information
case 0x007F: return "IMDATA";
case SHEETPR_0081: return "SHEETPR";
- case 0x0090: return "SORT";
- case 0x0094: return "LHRECORD";
- case STANDARDWIDTH_0099: return "STANDARDWIDTH";
- case 0x009D: return "AUTOFILTERINFO";
- case SCL_00A0: return "SCL";
- case 0x00AE: return "SCENMAN";
- case SXVIEW_00B0: return "SXVIEW"; // (pivot table) View Definition
- case 0x00B1: return "SXVD"; // (pivot table) View Fields
+ case 0x0090: return "SORT"; // Sorting Options
+ case 0x0094: return "LHRECORD"; // .WK? File Conversion Information
+ case STANDARDWIDTH_0099: return "STANDARDWIDTH"; //Standard Column Width
+ case 0x009D: return "AUTOFILTERINFO"; // Drop-Down Arrow Count
+ case SCL_00A0: return "SCL"; // Window Zoom Magnification
+ case 0x00AE: return "SCENMAN"; // Scenario Output Data
+
case 0x00B2: return "SXVI"; // (pivot table) View Item
case 0x00B4: return "SXIVD"; // (pivot table) Row/Column Field IDs
case 0x00B5: return "SXLI"; // (pivot table) Line Item Array
- case 0x00C5: return "SXDI"; // (pivot table) Data Item
case 0x00D3: return "OBPROJ";
case 0x00DC: return "PARAMQRY";
@@ -144,7 +141,6 @@ public final class UnknownRecord extends StandardRecord {
case BITMAP_00E9: return "BITMAP";
case PHONETICPR_00EF: return "PHONETICPR";
case 0x00F1: return "SXEX"; // PivotTable View Extended Information
- case 0x0100: return "SXVDEX"; // Extended PivotTable View Fields
case LABELRANGES_015F: return "LABELRANGES";
case 0x01BA: return "CODENAME";
@@ -178,7 +174,6 @@ public final class UnknownRecord extends StandardRecord {
case 0x088B: return "PLV";
case 0x088C: return "COMPAT12";
case 0x088D: return "DXF";
- case 0x088E: return "TABLESTYLES";
case 0x0892: return "STYLEEXT";
case 0x0896: return "THEME";
case 0x0897: return "GUIDTYPELIB";
diff --git a/src/java/org/apache/poi/hssf/record/chart/DataLabelExtensionRecord.java b/src/java/org/apache/poi/hssf/record/chart/DataLabelExtensionRecord.java
new file mode 100644
index 000000000..9fd23c487
--- /dev/null
+++ b/src/java/org/apache/poi/hssf/record/chart/DataLabelExtensionRecord.java
@@ -0,0 +1,72 @@
+/* ====================================================================
+ 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 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;
+
+/**
+ * DATALABEXT - Chart Data Label Extension (0x086A)
+ *
+ * @author Patrick Cheng
+ */
+public final class DataLabelExtensionRecord extends StandardRecord {
+ public static final short sid = 0x086A;
+
+ private int rt;
+ private int grbitFrt;
+ private byte[] unused = new byte[8];
+
+ public DataLabelExtensionRecord(RecordInputStream in) {
+ rt = in.readShort();
+ grbitFrt = in.readShort();
+ in.readFully(unused);
+ }
+
+ @Override
+ protected int getDataSize() {
+ return 2 + 2 + 8;
+ }
+
+ @Override
+ public short getSid() {
+ return sid;
+ }
+
+ @Override
+ protected void serialize(LittleEndianOutput out) {
+ out.writeShort(rt);
+ out.writeShort(grbitFrt);
+ out.write(unused);
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+
+ buffer.append("[DATALABEXT]\n");
+ buffer.append(" .rt =").append(HexDump.shortToHex(rt)).append('\n');
+ buffer.append(" .grbitFrt=").append(HexDump.shortToHex(grbitFrt)).append('\n');
+ buffer.append(" .unused =").append(HexDump.toHex(unused)).append('\n');
+
+ buffer.append("[/DATALABEXT]\n");
+ return buffer.toString();
+ }
+}
diff --git a/src/java/org/apache/poi/hssf/record/pivottable/DataItemRecord.java b/src/java/org/apache/poi/hssf/record/pivottable/DataItemRecord.java
new file mode 100644
index 000000000..05cf6a675
--- /dev/null
+++ b/src/java/org/apache/poi/hssf/record/pivottable/DataItemRecord.java
@@ -0,0 +1,90 @@
+/* ====================================================================
+ 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.pivottable;
+
+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;
+import org.apache.poi.util.StringUtil;
+
+/**
+ * SXDI - Data Item (0x00C5)
+ *
+ * @author Patrick Cheng
+ */
+public final class DataItemRecord extends StandardRecord {
+ public static final short sid = 0x00C5;
+
+ private int isxvdData;
+ private int iiftab;
+ private int df;
+ private int isxvd;
+ private int isxvi;
+ private int ifmt;
+ private String name;
+
+ public DataItemRecord(RecordInputStream in) {
+ isxvdData = in.readUShort();
+ iiftab = in.readUShort();
+ df = in.readUShort();
+ isxvd = in.readUShort();
+ isxvi = in.readUShort();
+ ifmt = in.readUShort();
+
+ name = in.readString();
+ }
+
+ @Override
+ protected void serialize(LittleEndianOutput out) {
+
+ out.writeShort(isxvdData);
+ out.writeShort(iiftab);
+ out.writeShort(df);
+ out.writeShort(isxvd);
+ out.writeShort(isxvi);
+ out.writeShort(ifmt);
+
+ StringUtil.writeUnicodeString(out, name);
+ }
+
+ @Override
+ protected int getDataSize() {
+ return 2 + 2 + 2 + 2 + 2 + 2 + StringUtil.getEncodedSize(name);
+ }
+
+ @Override
+ public short getSid() {
+ return sid;
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+
+ buffer.append("[SXDI]\n");
+ buffer.append(" .isxvdData = ").append(HexDump.shortToHex(isxvdData)).append("\n");
+ buffer.append(" .iiftab = ").append(HexDump.shortToHex(iiftab)).append("\n");
+ buffer.append(" .df = ").append(HexDump.shortToHex(df)).append("\n");
+ buffer.append(" .isxvd = ").append(HexDump.shortToHex(isxvd)).append("\n");
+ buffer.append(" .isxvi = ").append(HexDump.shortToHex(isxvi)).append("\n");
+ buffer.append(" .ifmt = ").append(HexDump.shortToHex(ifmt)).append("\n");
+ buffer.append("[/SXDI]\n");
+ return buffer.toString();
+ }
+}
diff --git a/src/java/org/apache/poi/hssf/record/pivottable/ExtendedPivotTableViewFieldsRecord.java b/src/java/org/apache/poi/hssf/record/pivottable/ExtendedPivotTableViewFieldsRecord.java
new file mode 100644
index 000000000..82cae7ac6
--- /dev/null
+++ b/src/java/org/apache/poi/hssf/record/pivottable/ExtendedPivotTableViewFieldsRecord.java
@@ -0,0 +1,111 @@
+/* ====================================================================
+ 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.pivottable;
+
+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;
+import org.apache.poi.util.StringUtil;
+
+/**
+ * SXVDEX - Extended PivotTable View Fields (0x0100)
+ *
+ * @author Patrick Cheng
+ */
+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;
+
+ public ExtendedPivotTableViewFieldsRecord(RecordInputStream in) {
+
+ 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();
+ if (cchSubName != STRING_NOT_PRESENT_LEN) {
+ 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.writeShort(STRING_NOT_PRESENT_LEN);
+ } else {
+ out.writeShort(subName.length());
+ }
+
+ 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
+ }
+
+ @Override
+ public short getSid() {
+ return sid;
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+
+ 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("[/SXVDEX]\n");
+ return buffer.toString();
+ }
+}
diff --git a/src/java/org/apache/poi/hssf/record/pivottable/PageItemRecord.java b/src/java/org/apache/poi/hssf/record/pivottable/PageItemRecord.java
new file mode 100644
index 000000000..8dd476c2a
--- /dev/null
+++ b/src/java/org/apache/poi/hssf/record/pivottable/PageItemRecord.java
@@ -0,0 +1,72 @@
+/* ====================================================================
+ 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.pivottable;
+
+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;
+
+/**
+ * SXPI - Page Item (0x00B6)
+ *
+ * @author Patrick Cheng
+ */
+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();
+ }
+
+ @Override
+ protected void serialize(LittleEndianOutput out) {
+ out.writeShort(isxvi);
+ out.writeShort(isxvd);
+ out.writeShort(idObj);
+ }
+
+ @Override
+ protected int getDataSize() {
+ return 2 + 2 + 2;
+ }
+
+ @Override
+ public short getSid() {
+ return sid;
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer buffer = 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();
+ }
+}
diff --git a/src/java/org/apache/poi/hssf/record/pivottable/StreamIDRecord.java b/src/java/org/apache/poi/hssf/record/pivottable/StreamIDRecord.java
new file mode 100644
index 000000000..bd7290078
--- /dev/null
+++ b/src/java/org/apache/poi/hssf/record/pivottable/StreamIDRecord.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.pivottable;
+
+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;
+
+/**
+ * SXIDSTM - Stream ID (0x00D5)
+ *
+ * @author Patrick Cheng
+ */
+public final class StreamIDRecord extends StandardRecord {
+ public static final short sid = 0x00D5;
+
+ private int idstm;
+
+ public StreamIDRecord(RecordInputStream in) {
+ idstm = in.readShort();
+ }
+
+ @Override
+ protected void serialize(LittleEndianOutput out) {
+ out.writeShort(idstm);
+ }
+
+ @Override
+ protected int getDataSize() {
+ return 2;
+ }
+
+ @Override
+ public short getSid() {
+ return sid;
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+
+ buffer.append("[SXIDSTM]\n");
+ buffer.append(" .idstm =").append(HexDump.shortToHex(idstm)).append('\n');
+
+ buffer.append("[/SXIDSTM]\n");
+ return buffer.toString();
+ }
+}
diff --git a/src/java/org/apache/poi/hssf/record/pivottable/ViewDefinitionRecord.java b/src/java/org/apache/poi/hssf/record/pivottable/ViewDefinitionRecord.java
new file mode 100644
index 000000000..03c2981fb
--- /dev/null
+++ b/src/java/org/apache/poi/hssf/record/pivottable/ViewDefinitionRecord.java
@@ -0,0 +1,162 @@
+/* ====================================================================
+ 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.pivottable;
+
+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;
+import org.apache.poi.util.StringUtil;
+
+/**
+ * SXVIEW - View Definition (0x00B0)
+ *
+ * @author Patrick Cheng
+ */
+public final class ViewDefinitionRecord extends StandardRecord {
+ public static final short sid = 0x00B0;
+
+ private int rwFirst;
+ private int rwLast;
+ private int colFirst;
+ private int colLast;
+ private int rwFirstHead;
+ private int rwFirstData;
+ private int colFirstData;
+ private int iCache;
+ private int reserved;
+
+ private int sxaxis4Data;
+ private int ipos4Data;
+ private int cDim;
+
+ private int cDimRw;
+
+ private int cDimCol;
+ private int cDimPg;
+
+ private int cDimData;
+ private int cRw;
+ private int cCol;
+ private int grbit;
+ private int itblAutoFmt;
+
+ private String dataField;
+ private String name;
+
+
+ public ViewDefinitionRecord(RecordInputStream in) {
+ rwFirst = in.readUShort();
+ rwLast = in.readUShort();
+ colFirst = in.readUShort();
+ colLast = in.readUShort();
+ rwFirstHead = in.readUShort();
+ rwFirstData = in.readUShort();
+ colFirstData = in.readUShort();
+ iCache = in.readUShort();
+ reserved = in.readUShort();
+ sxaxis4Data = in.readUShort();
+ ipos4Data = in.readUShort();
+ cDim = in.readUShort();
+ cDimRw = in.readUShort();
+ cDimCol = in.readUShort();
+ cDimPg = in.readUShort();
+ cDimData = in.readUShort();
+ cRw = in.readUShort();
+ cCol = in.readUShort();
+ grbit = in.readUShort();
+ itblAutoFmt = in.readUShort();
+ int cchName = in.readUShort();
+ int cchData = in.readUShort();
+
+ name = StringUtil.readUnicodeString(in, cchName);
+ dataField = StringUtil.readUnicodeString(in, cchData);
+ }
+
+ @Override
+ protected void serialize(LittleEndianOutput out) {
+ out.writeShort(rwFirst);
+ out.writeShort(rwLast);
+ out.writeShort(colFirst);
+ out.writeShort(colLast);
+ out.writeShort(rwFirstHead);
+ out.writeShort(rwFirstData);
+ out.writeShort(colFirstData);
+ out.writeShort(iCache);
+ out.writeShort(reserved);
+ out.writeShort(sxaxis4Data);
+ out.writeShort(ipos4Data);
+ out.writeShort(cDim);
+ out.writeShort(cDimRw);
+ out.writeShort(cDimCol);
+ out.writeShort(cDimPg);
+ out.writeShort(cDimData);
+ out.writeShort(cRw);
+ out.writeShort(cCol);
+ out.writeShort(grbit);
+ out.writeShort(itblAutoFmt);
+ out.writeShort(name.length());
+ out.writeShort(dataField.length());
+
+ StringUtil.writeUnicodeStringFlagAndData(out, name);
+ StringUtil.writeUnicodeStringFlagAndData(out, dataField);
+ }
+
+ @Override
+ protected int getDataSize() {
+ return 40 + // 20 short fields (rwFirst ... itblAutoFmt)
+ StringUtil.getEncodedSize(name) + StringUtil.getEncodedSize(dataField) ;
+ }
+
+ @Override
+ public short getSid() {
+ return sid;
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+
+ buffer.append("[SXVIEW]\n");
+ buffer.append(" .rwFirst =").append(HexDump.shortToHex(rwFirst)).append('\n');
+ buffer.append(" .rwLast =").append(HexDump.shortToHex(rwLast)).append('\n');
+ buffer.append(" .colFirst =").append(HexDump.shortToHex(colFirst)).append('\n');
+ buffer.append(" .colLast =").append(HexDump.shortToHex(colLast)).append('\n');
+ buffer.append(" .rwFirstHead =").append(HexDump.shortToHex(rwFirstHead)).append('\n');
+ buffer.append(" .rwFirstData =").append(HexDump.shortToHex(rwFirstData)).append('\n');
+ buffer.append(" .colFirstData =").append(HexDump.shortToHex(colFirstData)).append('\n');
+ buffer.append(" .iCache =").append(HexDump.shortToHex(iCache)).append('\n');
+ buffer.append(" .reserved =").append(HexDump.shortToHex(reserved)).append('\n');
+ buffer.append(" .sxaxis4Data =").append(HexDump.shortToHex(sxaxis4Data)).append('\n');
+ buffer.append(" .ipos4Data =").append(HexDump.shortToHex(ipos4Data)).append('\n');
+ buffer.append(" .cDim =").append(HexDump.shortToHex(cDim)).append('\n');
+ buffer.append(" .cDimRw =").append(HexDump.shortToHex(cDimRw)).append('\n');
+ buffer.append(" .cDimCol =").append(HexDump.shortToHex(cDimCol)).append('\n');
+ buffer.append(" .cDimPg =").append(HexDump.shortToHex(cDimPg)).append('\n');
+ buffer.append(" .cDimData =").append(HexDump.shortToHex(cDimData)).append('\n');
+ buffer.append(" .cRw =").append(HexDump.shortToHex(cRw)).append('\n');
+ buffer.append(" .cCol =").append(HexDump.shortToHex(cCol)).append('\n');
+ buffer.append(" .grbit =").append(HexDump.shortToHex(grbit)).append('\n');
+ buffer.append(" .itblAutoFmt =").append(HexDump.shortToHex(itblAutoFmt)).append('\n');
+ buffer.append(" .name =").append(name).append('\n');
+ buffer.append(" .dataField =").append(dataField).append('\n');
+
+ buffer.append("[/SXVIEW]\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
new file mode 100644
index 000000000..9e477ac84
--- /dev/null
+++ b/src/java/org/apache/poi/hssf/record/pivottable/ViewFieldsRecord.java
@@ -0,0 +1,110 @@
+/* ====================================================================
+ 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.pivottable;
+
+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;
+import org.apache.poi.util.StringUtil;
+
+/**
+ * SXVD - View Fields (0x00B1)
+ *
+ * @author Patrick Cheng
+ */
+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;
+
+ private int sxaxis;
+ private int cSub;
+ private int grbitSub;
+ private int cItm;
+
+ private String name = null;
+
+ /**
+ * values for the {@link ViewFieldsRecord#sxaxis} field
+ */
+ private static final class Axis {
+ public static final int NO_AXIS = 0;
+ public static final int ROW = 1;
+ public static final int COLUMN = 2;
+ public static final int PAGE = 4;
+ public static final int DATA = 8;
+ }
+
+ public ViewFieldsRecord(RecordInputStream in) {
+ sxaxis = in.readShort();
+ cSub = in.readShort();
+ grbitSub = in.readShort();
+ cItm = in.readShort();
+
+ int cchName = in.readShort();
+ if (cchName != STRING_NOT_PRESENT_LEN) {
+ name = in.readCompressedUnicode(cchName);
+ }
+ }
+
+ @Override
+ protected void serialize(LittleEndianOutput out) {
+
+ out.writeShort(sxaxis);
+ out.writeShort(cSub);
+ out.writeShort(grbitSub);
+ out.writeShort(cItm);
+
+ if (name != null) {
+ StringUtil.writeUnicodeString(out, name);
+ } else {
+ out.writeShort(STRING_NOT_PRESENT_LEN);
+ }
+ }
+
+ @Override
+ protected int getDataSize() {
+
+ int cchName = 0;
+ if (name != null) {
+ cchName = name.length();
+ }
+ return 2 +2 + 2 + 2 + 2 + cchName;
+ }
+
+ @Override
+ public short getSid() {
+ return sid;
+ }
+
+ @Override
+ 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("[/SXVD]\n");
+ return buffer.toString();
+ }
+}
diff --git a/src/java/org/apache/poi/hssf/record/pivottable/ViewSourceRecord.java b/src/java/org/apache/poi/hssf/record/pivottable/ViewSourceRecord.java
new file mode 100644
index 000000000..daee00732
--- /dev/null
+++ b/src/java/org/apache/poi/hssf/record/pivottable/ViewSourceRecord.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.pivottable;
+
+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;
+
+/**
+ * SXVS - View Source (0x00E3)
+ *
+ * @author Patrick Cheng
+ */
+public final class ViewSourceRecord extends StandardRecord {
+ public static final short sid = 0x00E3;
+
+ private int vs;
+
+ public ViewSourceRecord(RecordInputStream in) {
+ vs = in.readShort();
+ }
+
+ @Override
+ protected void serialize(LittleEndianOutput out) {
+ out.writeShort(vs);
+ }
+
+ @Override
+ protected int getDataSize() {
+ return 2;
+ }
+
+ @Override
+ public short getSid() {
+ return sid;
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+
+ buffer.append("[SXVS]\n");
+ buffer.append(" .vs =").append(HexDump.shortToHex(vs)).append('\n');
+
+ buffer.append("[/SXVS]\n");
+ return buffer.toString();
+ }
+}
diff --git a/src/java/org/apache/poi/util/StringUtil.java b/src/java/org/apache/poi/util/StringUtil.java
index 287c36b19..c61eb2f64 100644
--- a/src/java/org/apache/poi/util/StringUtil.java
+++ b/src/java/org/apache/poi/util/StringUtil.java
@@ -140,6 +140,25 @@ public class StringUtil {
}
return readUnicodeLE(in, nChars);
}
+ /**
+ * InputStream in is expected to contain:
+ *
+ *
+ * For this encoding, the is16BitFlag is always present even if nChars==0.
+ *
+ * This method should be used when the nChars field is not stored
+ * as a ushort immediately before the is16BitFlag. Otherwise, {@link
+ * #readUnicodeString(LittleEndianInput)} can be used.
+ */
+ public static String readUnicodeString(LittleEndianInput in, int nChars) {
+ byte is16Bit = in.readByte();
+ if ((is16Bit & 0x01) == 0) {
+ return readCompressedUnicode(in, nChars);
+ }
+ return readUnicodeLE(in, nChars);
+ }
/**
* OutputStream out will get:
*
@@ -161,7 +180,28 @@ public class StringUtil {
putCompressedUnicode(value, out);
}
}
-
+ /**
+ * OutputStream out will get:
+ *
+ *
+ * For this encoding, the is16BitFlag is always present even if nChars==0.
+ *
+ * This method should be used when the nChars field is not stored
+ * as a ushort immediately before the is16BitFlag. Otherwise, {@link
+ * #writeUnicodeString(LittleEndianOutput, String)} can be used.
+ */
+ public static void writeUnicodeStringFlagAndData(LittleEndianOutput out, String value) {
+ boolean is16Bit = hasMultibyte(value);
+ out.writeByte(is16Bit ? 0x01 : 0x00);
+ if (is16Bit) {
+ putUnicodeLE(value, out);
+ } else {
+ putCompressedUnicode(value, out);
+ }
+ }
+
/**
* @return the number of bytes that would be written by {@link #writeUnicodeString(LittleEndianOutput, String)}
*/