diff options
author | Nick Burch <nick@apache.org> | 2006-08-14 10:29:49 +0000 |
---|---|---|
committer | Nick Burch <nick@apache.org> | 2006-08-14 10:29:49 +0000 |
commit | 6d2bc8aea9c5039413d1674d4c71ce87a6ca0f3f (patch) | |
tree | 60446bcdf3fcc24ea02cd7cabd80e602c7bd762d /src | |
parent | 99100df6792b677af0467fa249caa1054dcdd61f (diff) | |
download | poi-6d2bc8aea9c5039413d1674d4c71ce87a6ca0f3f.tar.gz poi-6d2bc8aea9c5039413d1674d4c71ce87a6ca0f3f.zip |
Access to Saved By Information - patch from Trejkaz in bug #38647
git-svn-id: https://svn.apache.org/repos/asf/jakarta/poi/trunk@431320 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src')
6 files changed, 349 insertions, 0 deletions
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/HWPFDocument.java b/src/scratchpad/src/org/apache/poi/hwpf/HWPFDocument.java index c525c57236..7657019e7f 100644 --- a/src/scratchpad/src/org/apache/poi/hwpf/HWPFDocument.java +++ b/src/scratchpad/src/org/apache/poi/hwpf/HWPFDocument.java @@ -86,6 +86,9 @@ public class HWPFDocument extends POIDocument /** Hold list tables */ protected ListTables _lt; + /** Holds the save history for this document. */ + protected SavedByTable _sbt; + protected HWPFDocument() { @@ -212,6 +215,13 @@ public class HWPFDocument extends POIDocument _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++) { @@ -267,6 +277,17 @@ public class HWPFDocument extends POIDocument { 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. * @@ -347,6 +368,16 @@ public class HWPFDocument extends POIDocument 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); diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/FileInformationBlock.java b/src/scratchpad/src/org/apache/poi/hwpf/model/FileInformationBlock.java index 773ff080da..16bd3a39ba 100644 --- a/src/scratchpad/src/org/apache/poi/hwpf/model/FileInformationBlock.java +++ b/src/scratchpad/src/org/apache/poi/hwpf/model/FileInformationBlock.java @@ -61,6 +61,7 @@ public class FileInformationBlock extends FIBAbstractType 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)); @@ -251,6 +252,26 @@ public class FileInformationBlock extends FIBAbstractType _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); diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/SavedByEntry.java b/src/scratchpad/src/org/apache/poi/hwpf/model/SavedByEntry.java new file mode 100644 index 0000000000..82fbacd6b2 --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hwpf/model/SavedByEntry.java @@ -0,0 +1,85 @@ +/* ====================================================================
+ Copyright 2002-2004 Apache Software Foundation
+
+ Licensed 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.hwpf.model;
+
+
+/**
+ * A single entry in the {@link SavedByTable}.
+ *
+ * @author Daniel Noll
+ */
+public class SavedByEntry
+{
+ private String userName;
+ private String saveLocation;
+
+ public SavedByEntry(String userName, String saveLocation)
+ {
+ this.userName = userName;
+ this.saveLocation = saveLocation;
+ }
+
+ public String getUserName()
+ {
+ return userName;
+ }
+
+ public String getSaveLocation()
+ {
+ return saveLocation;
+ }
+
+ /**
+ * Compares this object with another, for equality.
+ *
+ * @param other the object to compare to this one.
+ * @return <code>true</code> iff the other object is equal to this one.
+ */
+ public boolean equals(Object other)
+ {
+ if (other == this) return true;
+ if (!(other instanceof SavedByEntry)) return false;
+ SavedByEntry that = (SavedByEntry) other;
+ return that.userName.equals(userName) &&
+ that.saveLocation.equals(saveLocation);
+ }
+
+ /**
+ * Generates a hash code for consistency with {@link #equals(Object)}.
+ *
+ * @return the hash code.
+ */
+ public int hashCode()
+ {
+ int hash = 29;
+ hash = hash * 13 + userName.hashCode();
+ hash = hash * 13 + saveLocation.hashCode();
+ return hash;
+ }
+
+ /**
+ * Returns a string for display.
+ *
+ * @return the string.
+ */
+ public String toString()
+ {
+ return "SavedByEntry[userName=" + getUserName() +
+ ",saveLocation=" + getSaveLocation() + "]";
+ }
+}
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/SavedByTable.java b/src/scratchpad/src/org/apache/poi/hwpf/model/SavedByTable.java new file mode 100644 index 0000000000..d24a8ecc83 --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hwpf/model/SavedByTable.java @@ -0,0 +1,121 @@ +/* ====================================================================
+ Copyright 2002-2004 Apache Software Foundation
+
+ Licensed 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.hwpf.model;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.StringUtil;
+
+import org.apache.poi.hwpf.model.io.HWPFOutputStream;
+
+/**
+ * String table containing the history of the last few revisions ("saves") of the document.
+ * Read-only for the time being.
+ *
+ * @author Daniel Noll
+ */
+public class SavedByTable
+{
+ /**
+ * A value that I don't know what it does, but is maintained for accuracy.
+ */
+ private short unknownValue = -1;
+
+ /**
+ * Array of entries.
+ */
+ private SavedByEntry[] entries;
+
+ /**
+ * Constructor to read the table from the table stream.
+ *
+ * @param tableStream the table stream.
+ * @param offset the offset into the byte array.
+ * @param size the size of the table in the byte array.
+ */
+ public SavedByTable(byte[] tableStream, int offset, int size)
+ {
+ // Read the value that I don't know what it does. :-)
+ unknownValue = LittleEndian.getShort(tableStream, offset);
+ offset += 2;
+
+ // The stored int is the number of strings, and there are two strings per entry.
+ int numEntries = LittleEndian.getInt(tableStream, offset) / 2;
+ offset += 4;
+
+ entries = new SavedByEntry[numEntries];
+ for (int i = 0; i < numEntries; i++)
+ {
+ int len = LittleEndian.getShort(tableStream, offset);
+ offset += 2;
+ String userName = StringUtil.getFromUnicodeLE(tableStream, offset, len);
+ offset += len * 2;
+ len = LittleEndian.getShort(tableStream, offset);
+ offset += 2;
+ String saveLocation = StringUtil.getFromUnicodeLE(tableStream, offset, len);
+ offset += len * 2;
+
+ entries[i] = new SavedByEntry(userName, saveLocation);
+ }
+ }
+
+ /**
+ * Gets the entries. The returned list cannot be modified.
+ *
+ * @return the list of entries.
+ */
+ public List getEntries()
+ {
+ return Collections.unmodifiableList(Arrays.asList(entries));
+ }
+
+ /**
+ * Writes this table to the table stream.
+ *
+ * @param tableStream the table stream to write to.
+ * @throws IOException if an error occurs while writing.
+ */
+ public void writeTo(HWPFOutputStream tableStream)
+ throws IOException
+ {
+ byte[] header = new byte[6];
+ LittleEndian.putShort(header, 0, unknownValue);
+ LittleEndian.putInt(header, 2, entries.length * 2);
+ tableStream.write(header);
+
+ for (int i = 0; i < entries.length; i++)
+ {
+ writeStringValue(tableStream, entries[i].getUserName());
+ writeStringValue(tableStream, entries[i].getSaveLocation());
+ }
+ }
+
+ private void writeStringValue(HWPFOutputStream tableStream, String value)
+ throws IOException
+ {
+ byte[] buf = new byte[value.length() * 2 + 2];
+ LittleEndian.putShort(buf, 0, (short) value.length());
+ StringUtil.putUnicodeLE(value, buf, 2);
+ tableStream.write(buf);
+ }
+}
+
diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/data/saved-by-table.doc b/src/scratchpad/testcases/org/apache/poi/hwpf/data/saved-by-table.doc Binary files differnew file mode 100644 index 0000000000..c3ea6bc861 --- /dev/null +++ b/src/scratchpad/testcases/org/apache/poi/hwpf/data/saved-by-table.doc diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/model/TestSavedByTable.java b/src/scratchpad/testcases/org/apache/poi/hwpf/model/TestSavedByTable.java new file mode 100644 index 0000000000..bc0a6c0bee --- /dev/null +++ b/src/scratchpad/testcases/org/apache/poi/hwpf/model/TestSavedByTable.java @@ -0,0 +1,91 @@ +
+/* ====================================================================
+ Copyright 2002-2004 Apache Software Foundation
+
+ Licensed 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.hwpf.model;
+
+import java.io.*;
+import java.util.*;
+import junit.framework.*;
+
+import org.apache.poi.hwpf.*;
+import org.apache.poi.hwpf.model.*;
+import org.apache.poi.util.*;
+
+/**
+ * Unit test for {@link SavedByTable} and {@link SavedByEntry}.
+ *
+ * @author Daniel Noll
+ */
+public class TestSavedByTable
+ extends TestCase
+{
+ /** Data dir */
+ private File testFile = new File(new File(System.getProperty("HWPF.testdata.path")), "saved-by-table.doc");
+
+ /** The expected entries in the test document. */
+ private List expected = Arrays.asList(new Object[] {
+ new SavedByEntry("cic22", "C:\\DOCUME~1\\phamill\\LOCALS~1\\Temp\\AutoRecovery save of Iraq - security.asd"),
+ new SavedByEntry("cic22", "C:\\DOCUME~1\\phamill\\LOCALS~1\\Temp\\AutoRecovery save of Iraq - security.asd"),
+ new SavedByEntry("cic22", "C:\\DOCUME~1\\phamill\\LOCALS~1\\Temp\\AutoRecovery save of Iraq - security.asd"),
+ new SavedByEntry("JPratt", "C:\\TEMP\\Iraq - security.doc"),
+ new SavedByEntry("JPratt", "A:\\Iraq - security.doc"),
+ new SavedByEntry("ablackshaw", "C:\\ABlackshaw\\Iraq - security.doc"),
+ new SavedByEntry("ablackshaw", "C:\\ABlackshaw\\A;Iraq - security.doc"),
+ new SavedByEntry("ablackshaw", "A:\\Iraq - security.doc"),
+ new SavedByEntry("MKhan", "C:\\TEMP\\Iraq - security.doc"),
+ new SavedByEntry("MKhan", "C:\\WINNT\\Profiles\\mkhan\\Desktop\\Iraq.doc")
+ });
+
+ /**
+ * Tests reading in the entries, comparing them against the expected entries.
+ * Then tests writing the document out and reading the entries yet again.
+ *
+ * @throws Exception if an unexpected error occurs.
+ */
+ public void testReadWrite()
+ throws Exception
+ {
+ // This document is widely available on the internet as "blair.doc".
+ // I tried stripping the content and saving the document but my version
+ // of Word (from Office XP) strips this table out.
+ InputStream stream = new BufferedInputStream(new FileInputStream(testFile));
+ HWPFDocument doc;
+ try
+ {
+ doc = new HWPFDocument(stream);
+ }
+ finally
+ {
+ stream.close();
+ }
+
+ // Check what we just read.
+ assertEquals("List of saved-by entries was not as expected",
+ expected, doc.getSavedByTable().getEntries());
+
+ // Now write the entire document out, and read it back in...
+ ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
+ doc.write(byteStream);
+ InputStream copyStream = new ByteArrayInputStream(byteStream.toByteArray());
+ HWPFDocument copy = new HWPFDocument(copyStream);
+
+ // And check again.
+ assertEquals("List of saved-by entries was incorrect after writing",
+ expected, copy.getSavedByTable().getEntries());
+ }
+}
|