mirror of https://github.com/apache/poi.git
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:
parent
99100df679
commit
6d2bc8aea9
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
Binary file not shown.
|
@ -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());
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue