import org.apache.poi.util.LittleEndian;
-
-
/**
- * common data structure in a Word file. Contains an array of 4 byte ints in
- * the front that relate to an array of abitrary data structures in the back.
- *
- *
+ * Plex of CPs stored in File (PLCF)
+ *
+ * common data structure in a Word file. Contains an array of 4 byte ints in the
+ * front that relate to an array of arbitrary data structures in the back.
+ *
+ * See page 184 of official documentation for details
+ *
* @author Ryan Ackley
*/
public final class PlexOfCps
{
- private int _count;
- private int _offset;
- private int _sizeOfStruct;
- private ArrayList<GenericPropertyNode> _props;
-
-
- public PlexOfCps(int sizeOfStruct)
- {
- _props = new ArrayList<GenericPropertyNode>();
- _sizeOfStruct = sizeOfStruct;
- }
-
- /**
- * Constructor
- *
- * @param size The size in bytes of this PlexOfCps
- * @param sizeOfStruct The size of the data structure type stored in
- * this PlexOfCps.
- */
- public PlexOfCps(byte[] buf, int start, int size, int sizeOfStruct)
- {
- // Figure out the number we hold
- _count = (size - 4)/(4 + sizeOfStruct);
-
- _sizeOfStruct = sizeOfStruct;
- _props = new ArrayList<GenericPropertyNode>(_count);
-
- for (int x = 0; x < _count; x++)
+ private int _iMac;
+ private int _offset;
+ private int _cbStruct;
+ private ArrayList<GenericPropertyNode> _props;
+
+ public PlexOfCps( int sizeOfStruct )
+ {
+ _props = new ArrayList<GenericPropertyNode>();
+ _cbStruct = sizeOfStruct;
+ }
+
+ /**
+ * Constructor
+ *
+ * @param cb
+ * The size of PLCF in bytes
+ * @param cbStruct
+ * The size of the data structure type stored in this PlexOfCps.
+ */
+ public PlexOfCps( byte[] buf, int start, int cb, int cbStruct )
+ {
+ // Figure out the number we hold
+ _iMac = ( cb - 4 ) / ( 4 + cbStruct );
+
+ _cbStruct = cbStruct;
+ _props = new ArrayList<GenericPropertyNode>( _iMac );
+
+ for ( int x = 0; x < _iMac; x++ )
+ {
+ _props.add( getProperty( x, buf, start ) );
+ }
+ }
+
+ public GenericPropertyNode getProperty( int index )
+ {
+ return _props.get( index );
+ }
+
+ public void addProperty( GenericPropertyNode node )
{
- _props.add(getProperty(x, buf, start));
+ _props.add( node );
}
- }
- public GenericPropertyNode getProperty(int index)
- {
- return _props.get(index);
- }
+ public byte[] toByteArray()
+ {
+ int size = _props.size();
+ int cpBufSize = ( ( size + 1 ) * LittleEndian.INT_SIZE );
+ int structBufSize = +( _cbStruct * size );
+ int bufSize = cpBufSize + structBufSize;
+
+ byte[] buf = new byte[bufSize];
+
+ GenericPropertyNode node = null;
+ for ( int x = 0; x < size; x++ )
+ {
+ node = _props.get( x );
+
+ // put the starting offset of the property into the plcf.
+ LittleEndian.putInt( buf, ( LittleEndian.INT_SIZE * x ),
+ node.getStart() );
+
+ // put the struct into the plcf
+ System.arraycopy( node.getBytes(), 0, buf, cpBufSize
+ + ( x * _cbStruct ), _cbStruct );
+ }
+ // put the ending offset of the last property into the plcf.
+ LittleEndian.putInt( buf, LittleEndian.INT_SIZE * size, node.getEnd() );
+
+ return buf;
+
+ }
- public void addProperty(GenericPropertyNode node)
- {
- _props.add(node);
- }
+ private GenericPropertyNode getProperty( int index, byte[] buf, int offset )
+ {
+ int start = LittleEndian.getInt( buf, offset + getIntOffset( index ) );
+ int end = LittleEndian.getInt( buf, offset + getIntOffset( index + 1 ) );
- public byte[] toByteArray()
- {
- int size = _props.size();
- int cpBufSize = ((size + 1) * LittleEndian.INT_SIZE);
- int structBufSize = + (_sizeOfStruct * size);
- int bufSize = cpBufSize + structBufSize;
+ byte[] struct = new byte[_cbStruct];
+ System.arraycopy( buf, offset + getStructOffset( index ), struct, 0,
+ _cbStruct );
- byte[] buf = new byte[bufSize];
+ return new GenericPropertyNode( start, end, struct );
+ }
- GenericPropertyNode node = null;
- for (int x = 0; x < size; x++)
+ private int getIntOffset( int index )
{
- node = _props.get(x);
+ return index * 4;
+ }
- // put the starting offset of the property into the plcf.
- LittleEndian.putInt(buf, (LittleEndian.INT_SIZE * x), node.getStart());
+ /**
+ * returns the number of data structures in this PlexofCps.
+ *
+ * @return The number of data structures in this PlexofCps
+ */
+ public int length()
+ {
+ return _iMac;
+ }
- // put the struct into the plcf
- System.arraycopy(node.getBytes(), 0, buf, cpBufSize + (x * _sizeOfStruct),
- _sizeOfStruct);
+ /**
+ * Returns the offset, in bytes, from the beginning if this PlexOfCps to the
+ * data structure at index.
+ *
+ * @param index
+ * The index of the data structure.
+ *
+ * @return The offset, in bytes, from the beginning if this PlexOfCps to the
+ * data structure at index.
+ */
+ private int getStructOffset( int index )
+ {
+ return ( 4 * ( _iMac + 1 ) ) + ( _cbStruct * index );
}
- // put the ending offset of the last property into the plcf.
- LittleEndian.putInt(buf, LittleEndian.INT_SIZE * size, node.getEnd());
-
- return buf;
-
- }
-
- private GenericPropertyNode getProperty(int index, byte[] buf, int offset)
- {
- int start = LittleEndian.getInt(buf, offset + getIntOffset(index));
- int end = LittleEndian.getInt(buf, offset + getIntOffset(index+1));
-
- byte[] struct = new byte[_sizeOfStruct];
- System.arraycopy(buf, offset + getStructOffset(index), struct, 0, _sizeOfStruct);
-
- return new GenericPropertyNode(start, end, struct);
- }
-
- private int getIntOffset(int index)
- {
- return index * 4;
- }
-
- /**
- * returns the number of data structures in this PlexOfCps.
- *
- * @return The number of data structures in this PlexOfCps
- */
- public int length()
- {
- return _count;
- }
-
- /**
- * Returns the offset, in bytes, from the beginning if this PlexOfCps to
- * the data structure at index.
- *
- * @param index The index of the data structure.
- *
- * @return The offset, in bytes, from the beginning if this PlexOfCps to
- * the data structure at index.
- */
- private int getStructOffset(int index)
- {
- return (4 * (_count + 1)) + (_sizeOfStruct * index);
- }
}
return;
}
- // Handle the PlcfHdd
- plcfHdd = new PlexOfCps(
- doc.getTableStream(), fib.getPlcfHddOffset(),
- fib.getPlcfHddSize(), 0
- );
- }
+ // Handle the PlcfHdd
+ /*
+ * Page 88:
+ *
+ * "The plcfhdd, a table whose location and length within the file is
+ * stored in fib.fcPlcfhdd and fib.cbPlcfhdd, describes where the text
+ * of each header/footer begins. If there are n headers/footers stored
+ * in the Word file, the plcfhdd consists of n+2 CP entries. The
+ * beginning CP of the ith header/footer is the ith CP in the plcfhdd.
+ * The limit CP (the CP of character 1 position past the end of a
+ * header/footer) of the ith header/footer is the i+1st CP in the
+ * plcfhdd. Note: at the limit CP - 1, Word always places a chEop as a
+ * placeholder which is never displayed as part of the header/footer.
+ * This allows Word to change an existing header/footer to be empty.
+ *
+ * If there are n header/footers, the n+2nd CP entry value is always 1
+ * greater than the n+1st CP entry value. A paragraph end (ASCII 13) is
+ * always stored at the file position marked by the n+1st CP value.
+ *
+ * The transformation in a full saved file from a header/footer CP to an
+ * offset from the beginning of a file (fc) is
+ * fc=fib.fcMin+ccpText+ccpFtn+cp."
+ */
+ plcfHdd = new PlexOfCps( doc.getTableStream(), fib.getPlcfHddOffset(),
+ fib.getPlcfHddSize(), 0 );
+ }
public String getFootnoteSeparator() {
return getAt(0);