diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml index acbd7e78b8..d1f3899f13 100644 --- a/src/documentation/content/xdocs/status.xml +++ b/src/documentation/content/xdocs/status.xml @@ -34,6 +34,7 @@ + 48926 - Initial support for the HWPF revision marks authors list 49160 - Ensure that CTDigSigBlob is included in poi-ooxml jar 49189 - Detect w:tab and w:cr entries in XWPF paragraphs, even when the XSD is silly and maps them to CTEmpty 49273 - Correct handling for Font Character Sets with indicies greater than 127 diff --git a/src/scratchpad/src/org/apache/poi/hwpf/HWPFDocument.java b/src/scratchpad/src/org/apache/poi/hwpf/HWPFDocument.java index 289044474a..f0d8b1d8ee 100644 --- a/src/scratchpad/src/org/apache/poi/hwpf/HWPFDocument.java +++ b/src/scratchpad/src/org/apache/poi/hwpf/HWPFDocument.java @@ -92,6 +92,9 @@ public final class HWPFDocument extends POIDocument /** Holds the save history for this document. */ protected SavedByTable _sbt; + + /** Holds the revision mark authors for this document. */ + protected RevisionMarkAuthorTable _rmat; /** Holds pictures table */ protected PicturesTable _pictures; @@ -274,6 +277,13 @@ public final class HWPFDocument extends POIDocument _sbt = new SavedByTable(_tableStream, sbtOffset, sbtLength); } + int rmarkOffset = _fib.getFcSttbfRMark(); + int rmarkLength = _fib.getLcbSttbfRMark(); + if (rmarkOffset != 0 && rmarkLength != 0) + { + _rmat = new RevisionMarkAuthorTable(_tableStream, rmarkOffset, rmarkLength); + } + PlexOfCps plc = new PlexOfCps(_tableStream, _fib.getFcPlcffldMom(), _fib.getLcbPlcffldMom(), 2); for (int x = 0; x < plc.length(); x++) { @@ -411,6 +421,16 @@ public final class HWPFDocument extends POIDocument return _sbt; } + /** + * Gets a reference to the revision mark author table, which holds the revision mark authors for the document. + * + * @return the saved-by table. + */ + public RevisionMarkAuthorTable getRevisionMarkAuthorTable() + { + return _rmat; + } + /** * @return PicturesTable object, that is able to extract images from this document */ @@ -514,6 +534,16 @@ public final class HWPFDocument extends POIDocument tableOffset = tableStream.getOffset(); } + + // write out the revision mark authors table. + if (_rmat != null) + { + _fib.setFcSttbfRMark(tableOffset); + _rmat.writeTo(tableStream); + _fib.setLcbSttbfRMark(tableStream.getOffset() - tableOffset); + + tableOffset = tableStream.getOffset(); + } // write out the FontTable. _fib.setFcSttbfffn(tableOffset); 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 6c09b49aca..01ccec19b5 100644 --- a/src/scratchpad/src/org/apache/poi/hwpf/model/FileInformationBlock.java +++ b/src/scratchpad/src/org/apache/poi/hwpf/model/FileInformationBlock.java @@ -68,6 +68,7 @@ public final class FileInformationBlock extends FIBAbstractType fieldSet.add(Integer.valueOf(FIBFieldHandler.PLFLFO)); fieldSet.add(Integer.valueOf(FIBFieldHandler.PLCFFLDMOM)); fieldSet.add(Integer.valueOf(FIBFieldHandler.STTBFFFN)); + fieldSet.add(Integer.valueOf(FIBFieldHandler.STTBFRMARK)); fieldSet.add(Integer.valueOf(FIBFieldHandler.STTBSAVEDBY)); fieldSet.add(Integer.valueOf(FIBFieldHandler.MODIFIED)); @@ -258,6 +259,26 @@ public final class FileInformationBlock extends FIBAbstractType { _fieldHandler.setFieldSize(FIBFieldHandler.STTBFFFN, lcbSttbFffn); } + + public int getFcSttbfRMark() + { + return _fieldHandler.getFieldOffset(FIBFieldHandler.STTBFRMARK); + } + + public int getLcbSttbfRMark() + { + return _fieldHandler.getFieldSize(FIBFieldHandler.STTBFRMARK); + } + + public void setFcSttbfRMark(int fcSttbfRMark) + { + _fieldHandler.setFieldOffset(FIBFieldHandler.STTBFRMARK, fcSttbfRMark); + } + + public void setLcbSttbfRMark(int lcbSttbfRMark) + { + _fieldHandler.setFieldSize(FIBFieldHandler.STTBFRMARK, lcbSttbfRMark); + } /** * Return the offset to the PlcfHdd, in the table stream, diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/RevisionMarkAuthorTable.java b/src/scratchpad/src/org/apache/poi/hwpf/model/RevisionMarkAuthorTable.java new file mode 100644 index 0000000000..c8b98734ad --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hwpf/model/RevisionMarkAuthorTable.java @@ -0,0 +1,147 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You 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 names of authors of revision marks, e-mails and + * comments in this document. + * + * @author Ryan Lauck + */ +public final class RevisionMarkAuthorTable { + /** + * must be 0xFFFF + */ + private short fExtend = (short) 0xFFFF; + + /** + * the number of entries in the table + */ + private short cData = 0; + + /** + * must be 0 + */ + private short cbExtra = 0; + + /** + * Array of entries. + */ + private String[] 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 RevisionMarkAuthorTable(byte[] tableStream, int offset, int size) throws IOException { + // Read fExtend - it isn't used + fExtend = LittleEndian.getShort(tableStream, offset); + if(fExtend != 0xFFFF) { + //TODO: throw an exception here? + } + offset += 2; + + // Read the number of entries + cData = LittleEndian.getShort(tableStream, offset); + offset += 2; + + // Read cbExtra - it isn't used + cbExtra = LittleEndian.getShort(tableStream, offset); + if(cbExtra != 0) { + //TODO: throw an exception here? + } + offset += 2; + + entries = new String[cData]; + for (int i = 0; i < cData; i++) { + int len = LittleEndian.getShort(tableStream, offset); + offset += 2; + + String name = StringUtil.getFromUnicodeLE(tableStream, offset, len); + offset += len * 2; + + entries[i] = name; + } + } + + /** + * Gets the entries. The returned list cannot be modified. + * + * @return the list of entries. + */ + public List getEntries() { + return Collections.unmodifiableList(Arrays.asList(entries)); + } + + /** + * Get an author by its index. Returns null if it does not exist. + * + * @return the revision mark author + */ + public String getAuthor(int index) { + String auth = null; + if(index >= 0 && index < entries.length) { + auth = entries[index]; + } + return auth; + } + + /** + * Gets the number of entries. + * + * @return the number of entries. + */ + public int getSize() { + return cData; + } + + /** + * 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, fExtend); + LittleEndian.putShort(header, 2, cData); + LittleEndian.putShort(header, 4, cbExtra); + tableStream.write(header); + + for (String name : entries) { + byte[] buf = new byte[name.length() * 2 + 2]; + LittleEndian.putShort(buf, 0, (short) name.length()); + StringUtil.putUnicodeLE(name, buf, 2); + tableStream.write(buf); + } + } + +}