in poi-scratchpad/src/main/java/org/apache/poi/hwpf/HWPFDocument.java [641:973]
private void write(POIFSFileSystem pfs, boolean copyOtherEntries) throws IOException {
// clear the offsets and sizes in our FileInformationBlock.
_fib.clearOffsetsSizes();
// determine the FileInformationBLock size
int fibSize = _fib.getSize();
fibSize += POIFSConstants.SMALLER_BIG_BLOCK_SIZE - (fibSize % POIFSConstants.SMALLER_BIG_BLOCK_SIZE);
// initialize our streams for writing.
HWPFFileSystem docSys = new HWPFFileSystem();
ByteArrayOutputStream wordDocumentStream = docSys.getStream(STREAM_WORD_DOCUMENT);
ByteArrayOutputStream tableStream = docSys.getStream(STREAM_TABLE_1);
// preserve space for the FileInformationBlock because we will be writing
// it after we write everything else.
byte[] placeHolder = IOUtils.safelyAllocate(fibSize, MAX_RECORD_LENGTH);
wordDocumentStream.write(placeHolder);
int mainOffset = wordDocumentStream.size();
int tableOffset = 0;
// write out EncryptionInfo
updateEncryptionInfo();
EncryptionInfo ei = getEncryptionInfo();
if (ei != null) {
byte[] buf = new byte[1000];
LittleEndianByteArrayOutputStream leos = new LittleEndianByteArrayOutputStream(buf, 0);
leos.writeShort(ei.getVersionMajor());
leos.writeShort(ei.getVersionMinor());
if (ei.getEncryptionMode() == EncryptionMode.cryptoAPI) {
leos.writeInt(ei.getEncryptionFlags());
}
((EncryptionRecord) ei.getHeader()).write(leos);
((EncryptionRecord) ei.getVerifier()).write(leos);
tableStream.write(buf, 0, leos.getWriteIndex());
tableOffset += leos.getWriteIndex();
_fib.getFibBase().setLKey(tableOffset);
}
// write out the StyleSheet.
_fib.setFcStshf(tableOffset);
_ss.writeTo(tableStream);
_fib.setLcbStshf(tableStream.size() - tableOffset);
tableOffset = tableStream.size();
// get fcMin and fcMac because we will be writing the actual text with the
// complex table.
/*
* clx (encoding of the sprm lists for a complex file and piece table
* for an any file) Written immediately after the end of the previously
* recorded structure. This is recorded in all Word documents
*
* Microsoft Office Word 97-2007 Binary File Format (.doc)
* Specification; Page 23 of 210
*/
// write out the Complex table, includes text.
_fib.setFcClx(tableOffset);
_cft.writeTo(wordDocumentStream, tableStream);
_fib.setLcbClx(tableStream.size() - tableOffset);
tableOffset = tableStream.size();
int fcMac = wordDocumentStream.size();
/*
* dop (document properties record) Written immediately after the end of
* the previously recorded structure. This is recorded in all Word
* documents
*
* Microsoft Office Word 97-2007 Binary File Format (.doc)
* Specification; Page 23 of 210
*/
// write out the DocumentProperties.
_fib.setFcDop(tableOffset);
_dop.writeTo(tableStream);
_fib.setLcbDop(tableStream.size() - tableOffset);
tableOffset = tableStream.size();
/*
* plcfBkmkf (table recording beginning CPs of bookmarks) Written
* immediately after the sttbfBkmk, if the document contains bookmarks.
*
* Microsoft Office Word 97-2007 Binary File Format (.doc)
* Specification; Page 24 of 210
*/
if (_bookmarksTables != null) {
_bookmarksTables.writePlcfBkmkf(_fib, tableStream);
tableOffset = tableStream.size();
}
/*
* plcfBkmkl (table recording limit CPs of bookmarks) Written
* immediately after the plcfBkmkf, if the document contains bookmarks.
*
* Microsoft Office Word 97-2007 Binary File Format (.doc)
* Specification; Page 24 of 210
*/
if (_bookmarksTables != null) {
_bookmarksTables.writePlcfBkmkl(_fib, tableStream);
tableOffset = tableStream.size();
}
/*
* plcfbteChpx (bin table for CHP FKPs) Written immediately after the
* previously recorded table. This is recorded in all Word documents.
*
* Microsoft Office Word 97-2007 Binary File Format (.doc)
* Specification; Page 24 of 210
*/
// write out the CHPBinTable.
_fib.setFcPlcfbteChpx(tableOffset);
_cbt.writeTo(wordDocumentStream, tableStream, mainOffset, _cft.getTextPieceTable());
_fib.setLcbPlcfbteChpx(tableStream.size() - tableOffset);
tableOffset = tableStream.size();
/*
* plcfbtePapx (bin table for PAP FKPs) Written immediately after the
* plcfbteChpx. This is recorded in all Word documents.
*
* Microsoft Office Word 97-2007 Binary File Format (.doc)
* Specification; Page 24 of 210
*/
// write out the PAPBinTable.
_fib.setFcPlcfbtePapx(tableOffset);
// Right now we don't know how to save dataStream modifications, so we can just pipe them to a black hole.
_pbt.writeTo(wordDocumentStream, tableStream, new ByteArrayOutputStream(), _cft.getTextPieceTable());
_fib.setLcbPlcfbtePapx(tableStream.size() - tableOffset);
tableOffset = tableStream.size();
/*
* plcfendRef (endnote reference position table) Written immediately
* after the previously recorded table if the document contains endnotes
*
* plcfendTxt (endnote text position table) Written immediately after
* the plcfendRef if the document contains endnotes
*
* Microsoft Office Word 97-2007 Binary File Format (.doc)
* Specification; Page 24 of 210
*/
_endnotesTables.writeRef(_fib, tableStream);
_endnotesTables.writeTxt(_fib, tableStream);
tableOffset = tableStream.size();
/*
* plcffld*** (table of field positions and statuses for annotation
* subdocument) Written immediately after the previously recorded table,
* if the ******* subdocument contains fields.
*
* Microsoft Office Word 97-2007 Binary File Format (.doc)
* Specification; Page 24 of 210
*/
if (_fieldsTables != null) {
_fieldsTables.write(_fib, tableStream);
tableOffset = tableStream.size();
}
/*
* plcffndRef (footnote reference position table) Written immediately
* after the stsh if the document contains footnotes
*
* plcffndTxt (footnote text position table) Written immediately after
* the plcffndRef if the document contains footnotes
*
* Microsoft Office Word 97-2007 Binary File Format (.doc)
* Specification; Page 24 of 210
*/
_footnotesTables.writeRef(_fib, tableStream);
_footnotesTables.writeTxt(_fib, tableStream);
tableOffset = tableStream.size();
/*
* plcfsed (section table) Written immediately after the previously
* recorded table. Recorded in all Word documents
*
* Microsoft Office Word 97-2007 Binary File Format (.doc)
* Specification; Page 25 of 210
*/
// write out the SectionTable.
_fib.setFcPlcfsed(tableOffset);
_st.writeTo(wordDocumentStream, tableStream);
_fib.setLcbPlcfsed(tableStream.size() - tableOffset);
tableOffset = tableStream.size();
// write out the list tables
if (_lt != null) {
/*
* plcflst (list formats) Written immediately after the end of the
* previously recorded, if there are any lists defined in the
* document. This begins with a short count of LSTF structures
* followed by those LSTF structures. This is immediately followed
* by the allocated data hanging off the LSTFs. This data consists
* of the array of LVLs for each LSTF. (Each LVL consists of an LVLF
* followed by two grpprls and an XST.)
*
* Microsoft Office Word 97-2007 Binary File Format (.doc)
* Specification; Page 25 of 210
*/
_lt.writeListDataTo(_fib, tableStream);
tableOffset = tableStream.size();
/*
* plflfo (more list formats) Written immediately after the end of
* the plcflst and its accompanying data, if there are any lists
* defined in the document. This consists first of a PL of LFO
* records, followed by the allocated data (if any) hanging off the
* LFOs. The allocated data consists of the array of LFOLVLFs for
* each LFO (and each LFOLVLF is immediately followed by some LVLs).
*
* Microsoft Office Word 97-2007 Binary File Format (.doc)
* Specification; Page 26 of 210
*/
_lt.writeListOverridesTo(_fib, tableStream);
tableOffset = tableStream.size();
}
/*
* sttbfBkmk (table of bookmark name strings) Written immediately after
* the previously recorded table, if the document contains bookmarks.
*
* Microsoft Office Word 97-2007 Binary File Format (.doc)
* Specification; Page 27 of 210
*/
if (_bookmarksTables != null) {
_bookmarksTables.writeSttbfBkmk(_fib, tableStream);
tableOffset = tableStream.size();
}
/*
* sttbSavedBy (last saved by string table) Written immediately after
* the previously recorded table.
*
* Microsoft Office Word 97-2007 Binary File Format (.doc)
* Specification; Page 27 of 210
*/
// write out the saved-by table.
if (_sbt != null) {
_fib.setFcSttbSavedBy(tableOffset);
_sbt.writeTo(tableStream);
_fib.setLcbSttbSavedBy(tableStream.size() - tableOffset);
tableOffset = tableStream.size();
}
// write out the revision mark authors table.
if (_rmat != null) {
_fib.setFcSttbfRMark(tableOffset);
_rmat.writeTo(tableStream);
_fib.setLcbSttbfRMark(tableStream.size() - tableOffset);
tableOffset = tableStream.size();
}
// write out the FontTable.
_fib.setFcSttbfffn(tableOffset);
_ft.writeTo(tableStream);
_fib.setLcbSttbfffn(tableStream.size() - tableOffset);
tableOffset = tableStream.size();
// set some variables in the FileInformationBlock.
_fib.getFibBase().setFcMin(mainOffset);
_fib.getFibBase().setFcMac(fcMac);
_fib.setCbMac(wordDocumentStream.size());
// make sure that the table, doc and data streams use big blocks.
byte[] mainBuf = fillUp4096(wordDocumentStream);
// Table1 stream will be used
_fib.getFibBase().setFWhichTblStm(true);
// write out the FileInformationBlock.
//_fib.serialize(mainBuf, 0);
_fib.writeTo(mainBuf, tableStream);
byte[] tableBuf = fillUp4096(tableStream);
byte[] dataBuf = fillUp4096(_dataStream);
// Create a new document - ignoring the order of the old entries
if (ei == null) {
write(pfs, mainBuf, STREAM_WORD_DOCUMENT);
write(pfs, tableBuf, STREAM_TABLE_1);
write(pfs, dataBuf, STREAM_DATA);
} else {
ByteArrayOutputStream bos = new ByteArrayOutputStream(100000);
encryptBytes(mainBuf, FIB_BASE_LEN, bos);
write(pfs, bos.toByteArray(), STREAM_WORD_DOCUMENT);
bos.reset();
encryptBytes(tableBuf, _fib.getFibBase().getLKey(), bos);
write(pfs, bos.toByteArray(), STREAM_TABLE_1);
bos.reset();
encryptBytes(dataBuf, 0, bos);
write(pfs, bos.toByteArray(), STREAM_DATA);
bos.reset();
}
writeProperties(pfs);
if (copyOtherEntries && ei == null) {
// For encrypted files:
// The ObjectPool storage MUST NOT be present and if the file contains OLE objects, the storage
// objects for the OLE objects MUST be stored in the Data stream as specified in sprmCPicLocation.
DirectoryNode newRoot = pfs.getRoot();
_objectPool.writeTo(newRoot);
for (Entry entry : getDirectory()) {
String entryName = entry.getName();
if (!(
STREAM_WORD_DOCUMENT.equals(entryName) ||
STREAM_TABLE_0.equals(entryName) ||
STREAM_TABLE_1.equals(entryName) ||
STREAM_DATA.equals(entryName) ||
STREAM_OBJECT_POOL.equals(entryName) ||
SummaryInformation.DEFAULT_STREAM_NAME.equals(entryName) ||
DocumentSummaryInformation.DEFAULT_STREAM_NAME.equals(entryName)
)) {
EntryUtils.copyNodeRecursively(entry, newRoot);
}
}
}
/*
* since we updated all references in FIB and etc, using new arrays to
* access data
*/
replaceDirectory(pfs.getRoot());
this._tableStream = tableStream.toByteArray();
this._dataStream = dataBuf;
}