/** Hold list tables */
protected ListTables _lt;
+ /** Holds the save history for this document. */
+ protected SavedByTable _sbt;
+
protected HWPFDocument()
{
_lt = new ListTables(_tableStream, _fib.getFcPlcfLst(), _fib.getFcPlfLfo());
}
+ int sbtOffset = _fib.getFcSttbSavedBy();
+ int sbtLength = _fib.getLcbSttbSavedBy();
+ if (sbtOffset != 0 && sbtLength != 0)
+ {
+ _sbt = new SavedByTable(_tableStream, sbtOffset, sbtLength);
+ }
+
PlexOfCps plc = new PlexOfCps(_tableStream, _fib.getFcPlcffldMom(), _fib.getLcbPlcffldMom(), 2);
for (int x = 0; x < plc.length(); x++)
{
{
return _lt;
}
+
+ /**
+ * Gets a reference to the saved -by table, which holds the save history for the document.
+ *
+ * @return the saved-by table.
+ */
+ public SavedByTable getSavedByTable()
+ {
+ return _sbt;
+ }
+
/**
* Writes out the word file that is represented by an instance of this class.
*
tableOffset = tableStream.getOffset();
}
+ // write out the saved-by table.
+ if (_sbt != null)
+ {
+ _fib.setFcSttbSavedBy(tableOffset);
+ _sbt.writeTo(tableStream);
+ _fib.setLcbSttbSavedBy(tableStream.getOffset() - tableOffset);
+
+ tableOffset = tableStream.getOffset();
+ }
+
// write out the FontTable.
_fib.setFcSttbfffn(tableOffset);
_ft.writeTo(docSys);
fieldSet.add(new Integer(FIBFieldHandler.PLFLFO));
fieldSet.add(new Integer(FIBFieldHandler.PLCFFLDMOM));
fieldSet.add(new Integer(FIBFieldHandler.STTBFFFN));
+ fieldSet.add(new Integer(FIBFieldHandler.STTBSAVEDBY));
fieldSet.add(new Integer(FIBFieldHandler.MODIFIED));
_fieldHandler.setFieldSize(FIBFieldHandler.STTBFFFN, lcbSttbFffn);
}
+ public int getFcSttbSavedBy()
+ {
+ return _fieldHandler.getFieldOffset(FIBFieldHandler.STTBSAVEDBY);
+ }
+
+ public int getLcbSttbSavedBy()
+ {
+ return _fieldHandler.getFieldSize(FIBFieldHandler.STTBSAVEDBY);
+ }
+
+ public void setFcSttbSavedBy(int fcSttbSavedBy)
+ {
+ _fieldHandler.setFieldOffset(FIBFieldHandler.STTBSAVEDBY, fcSttbSavedBy);
+ }
+
+ public void setLcbSttbSavedBy(int fcSttbSavedBy)
+ {
+ _fieldHandler.setFieldSize(FIBFieldHandler.STTBSAVEDBY, fcSttbSavedBy);
+ }
+
public int getModifiedLow()
{
return _fieldHandler.getFieldOffset(FIBFieldHandler.PLFLFO);
--- /dev/null
+/* ====================================================================\r
+ Copyright 2002-2004 Apache Software Foundation\r
+\r
+ Licensed under the Apache License, Version 2.0 (the "License");\r
+ you may not use this file except in compliance with the License.\r
+ You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+==================================================================== */\r
+\r
+\r
+package org.apache.poi.hwpf.model;\r
+\r
+\r
+/**\r
+ * A single entry in the {@link SavedByTable}.\r
+ * \r
+ * @author Daniel Noll\r
+ */\r
+public class SavedByEntry\r
+{\r
+ private String userName;\r
+ private String saveLocation;\r
+\r
+ public SavedByEntry(String userName, String saveLocation)\r
+ {\r
+ this.userName = userName;\r
+ this.saveLocation = saveLocation;\r
+ }\r
+\r
+ public String getUserName()\r
+ {\r
+ return userName;\r
+ }\r
+\r
+ public String getSaveLocation()\r
+ {\r
+ return saveLocation;\r
+ }\r
+\r
+ /**\r
+ * Compares this object with another, for equality.\r
+ *\r
+ * @param other the object to compare to this one.\r
+ * @return <code>true</code> iff the other object is equal to this one.\r
+ */\r
+ public boolean equals(Object other)\r
+ {\r
+ if (other == this) return true;\r
+ if (!(other instanceof SavedByEntry)) return false;\r
+ SavedByEntry that = (SavedByEntry) other;\r
+ return that.userName.equals(userName) &&\r
+ that.saveLocation.equals(saveLocation);\r
+ }\r
+\r
+ /**\r
+ * Generates a hash code for consistency with {@link #equals(Object)}.\r
+ *\r
+ * @return the hash code.\r
+ */\r
+ public int hashCode()\r
+ {\r
+ int hash = 29;\r
+ hash = hash * 13 + userName.hashCode();\r
+ hash = hash * 13 + saveLocation.hashCode();\r
+ return hash;\r
+ }\r
+\r
+ /**\r
+ * Returns a string for display.\r
+ *\r
+ * @return the string.\r
+ */\r
+ public String toString()\r
+ {\r
+ return "SavedByEntry[userName=" + getUserName() +\r
+ ",saveLocation=" + getSaveLocation() + "]";\r
+ }\r
+}\r
--- /dev/null
+/* ====================================================================\r
+ Copyright 2002-2004 Apache Software Foundation\r
+\r
+ Licensed under the Apache License, Version 2.0 (the "License");\r
+ you may not use this file except in compliance with the License.\r
+ You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+==================================================================== */\r
+\r
+\r
+package org.apache.poi.hwpf.model;\r
+\r
+import java.io.IOException;\r
+import java.util.Arrays;\r
+import java.util.Collections;\r
+import java.util.List;\r
+\r
+import org.apache.poi.util.LittleEndian;\r
+import org.apache.poi.util.StringUtil;\r
+\r
+import org.apache.poi.hwpf.model.io.HWPFOutputStream;\r
+\r
+/**\r
+ * String table containing the history of the last few revisions ("saves") of the document.\r
+ * Read-only for the time being.\r
+ * \r
+ * @author Daniel Noll\r
+ */\r
+public class SavedByTable\r
+{\r
+ /**\r
+ * A value that I don't know what it does, but is maintained for accuracy.\r
+ */\r
+ private short unknownValue = -1;\r
+\r
+ /**\r
+ * Array of entries.\r
+ */\r
+ private SavedByEntry[] entries;\r
+\r
+ /**\r
+ * Constructor to read the table from the table stream.\r
+ *\r
+ * @param tableStream the table stream.\r
+ * @param offset the offset into the byte array.\r
+ * @param size the size of the table in the byte array.\r
+ */\r
+ public SavedByTable(byte[] tableStream, int offset, int size)\r
+ {\r
+ // Read the value that I don't know what it does. :-)\r
+ unknownValue = LittleEndian.getShort(tableStream, offset);\r
+ offset += 2;\r
+\r
+ // The stored int is the number of strings, and there are two strings per entry.\r
+ int numEntries = LittleEndian.getInt(tableStream, offset) / 2;\r
+ offset += 4;\r
+\r
+ entries = new SavedByEntry[numEntries];\r
+ for (int i = 0; i < numEntries; i++)\r
+ {\r
+ int len = LittleEndian.getShort(tableStream, offset);\r
+ offset += 2;\r
+ String userName = StringUtil.getFromUnicodeLE(tableStream, offset, len);\r
+ offset += len * 2;\r
+ len = LittleEndian.getShort(tableStream, offset);\r
+ offset += 2;\r
+ String saveLocation = StringUtil.getFromUnicodeLE(tableStream, offset, len);\r
+ offset += len * 2;\r
+\r
+ entries[i] = new SavedByEntry(userName, saveLocation);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Gets the entries. The returned list cannot be modified.\r
+ *\r
+ * @return the list of entries.\r
+ */\r
+ public List getEntries()\r
+ {\r
+ return Collections.unmodifiableList(Arrays.asList(entries));\r
+ }\r
+\r
+ /**\r
+ * Writes this table to the table stream.\r
+ *\r
+ * @param tableStream the table stream to write to.\r
+ * @throws IOException if an error occurs while writing.\r
+ */\r
+ public void writeTo(HWPFOutputStream tableStream)\r
+ throws IOException\r
+ {\r
+ byte[] header = new byte[6];\r
+ LittleEndian.putShort(header, 0, unknownValue);\r
+ LittleEndian.putInt(header, 2, entries.length * 2);\r
+ tableStream.write(header);\r
+\r
+ for (int i = 0; i < entries.length; i++)\r
+ {\r
+ writeStringValue(tableStream, entries[i].getUserName());\r
+ writeStringValue(tableStream, entries[i].getSaveLocation());\r
+ }\r
+ }\r
+\r
+ private void writeStringValue(HWPFOutputStream tableStream, String value)\r
+ throws IOException\r
+ {\r
+ byte[] buf = new byte[value.length() * 2 + 2];\r
+ LittleEndian.putShort(buf, 0, (short) value.length());\r
+ StringUtil.putUnicodeLE(value, buf, 2);\r
+ tableStream.write(buf);\r
+ }\r
+}\r
+\r
--- /dev/null
+\r
+/* ====================================================================\r
+ Copyright 2002-2004 Apache Software Foundation\r
+\r
+ Licensed under the Apache License, Version 2.0 (the "License");\r
+ you may not use this file except in compliance with the License.\r
+ You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+==================================================================== */\r
+\r
+\r
+package org.apache.poi.hwpf.model;\r
+\r
+import java.io.*;\r
+import java.util.*;\r
+import junit.framework.*;\r
+\r
+import org.apache.poi.hwpf.*;\r
+import org.apache.poi.hwpf.model.*;\r
+import org.apache.poi.util.*;\r
+\r
+/**\r
+ * Unit test for {@link SavedByTable} and {@link SavedByEntry}.\r
+ *\r
+ * @author Daniel Noll\r
+ */\r
+public class TestSavedByTable\r
+ extends TestCase\r
+{\r
+ /** Data dir */\r
+ private File testFile = new File(new File(System.getProperty("HWPF.testdata.path")), "saved-by-table.doc");\r
+\r
+ /** The expected entries in the test document. */\r
+ private List expected = Arrays.asList(new Object[] {\r
+ new SavedByEntry("cic22", "C:\\DOCUME~1\\phamill\\LOCALS~1\\Temp\\AutoRecovery save of Iraq - security.asd"),\r
+ new SavedByEntry("cic22", "C:\\DOCUME~1\\phamill\\LOCALS~1\\Temp\\AutoRecovery save of Iraq - security.asd"),\r
+ new SavedByEntry("cic22", "C:\\DOCUME~1\\phamill\\LOCALS~1\\Temp\\AutoRecovery save of Iraq - security.asd"),\r
+ new SavedByEntry("JPratt", "C:\\TEMP\\Iraq - security.doc"),\r
+ new SavedByEntry("JPratt", "A:\\Iraq - security.doc"),\r
+ new SavedByEntry("ablackshaw", "C:\\ABlackshaw\\Iraq - security.doc"),\r
+ new SavedByEntry("ablackshaw", "C:\\ABlackshaw\\A;Iraq - security.doc"),\r
+ new SavedByEntry("ablackshaw", "A:\\Iraq - security.doc"),\r
+ new SavedByEntry("MKhan", "C:\\TEMP\\Iraq - security.doc"),\r
+ new SavedByEntry("MKhan", "C:\\WINNT\\Profiles\\mkhan\\Desktop\\Iraq.doc")\r
+ });\r
+\r
+ /**\r
+ * Tests reading in the entries, comparing them against the expected entries.\r
+ * Then tests writing the document out and reading the entries yet again.\r
+ *\r
+ * @throws Exception if an unexpected error occurs.\r
+ */\r
+ public void testReadWrite()\r
+ throws Exception\r
+ {\r
+ // This document is widely available on the internet as "blair.doc".\r
+ // I tried stripping the content and saving the document but my version\r
+ // of Word (from Office XP) strips this table out.\r
+ InputStream stream = new BufferedInputStream(new FileInputStream(testFile));\r
+ HWPFDocument doc;\r
+ try\r
+ {\r
+ doc = new HWPFDocument(stream);\r
+ }\r
+ finally\r
+ {\r
+ stream.close();\r
+ }\r
+\r
+ // Check what we just read.\r
+ assertEquals("List of saved-by entries was not as expected",\r
+ expected, doc.getSavedByTable().getEntries());\r
+\r
+ // Now write the entire document out, and read it back in...\r
+ ByteArrayOutputStream byteStream = new ByteArrayOutputStream();\r
+ doc.write(byteStream);\r
+ InputStream copyStream = new ByteArrayInputStream(byteStream.toByteArray());\r
+ HWPFDocument copy = new HWPFDocument(copyStream);\r
+\r
+ // And check again.\r
+ assertEquals("List of saved-by entries was incorrect after writing",\r
+ expected, copy.getSavedByTable().getEntries());\r
+ }\r
+}\r