git-svn-id: https://svn.apache.org/repos/asf/jakarta/poi/trunk@431320 13f79535-47bb-0310-9956-ffa450edef68tags/REL_3_0_ALPHA3
@@ -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); |
@@ -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); |
@@ -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() + "]"; | |||
} | |||
} |
@@ -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); | |||
} | |||
} | |||
@@ -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()); | |||
} | |||
} |