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
This commit is contained in:
Nick Burch 2006-08-14 10:29:49 +00:00
parent 99100df679
commit 6d2bc8aea9
6 changed files with 349 additions and 0 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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() + "]";
}
}

View File

@ -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);
}
}

View File

@ -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());
}
}