import java.io.InputStream;
import java.io.FileInputStream;
import java.io.IOException;
+import java.io.OutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.FileOutputStream;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.poifs.filesystem.DocumentEntry;
+import org.apache.poi.poifs.common.POIFSConstants;
import org.apache.poi.hwpf.model.hdftypes.*;
+import org.apache.poi.hwpf.model.io.*;
/**
+ *
+ * This class acts as the bucket that we throw all of the Word data structures
+ * into.
+ *
* @author Ryan Ackley
*/
public class HWPFDocument
private FileInformationBlock _fib;
/** main document stream buffer*/
- byte[] _mainStream;
+ private byte[] _mainStream;
/** table stream buffer*/
- byte[] _tableStream;
+ private byte[] _tableStream;
+
+ /** Document wide Properties*/
+ private DocumentProperties _dop;
+
+ /** Contains text of the document wrapped in a obfuscated Wod data structure*/
+ private ComplexFileTable _cft;
+
+ /** Contains formatting properties for text*/
+ private CHPBinTable _cbt;
+
+ /** Contains formatting properties for paragraphs*/
+ private PAPBinTable _pbt;
+
+ /** Contains formatting properties for sections.*/
+ private SectionTable _st;
+
+ /** Holds styles for this document.*/
+ private StyleSheet _ss;
+
+ /** Holds fonts for this document.*/
+ private FontTable _ft;
+
+ /**
+ * This constructor loads a Word document from an InputStream.
+ *
+ * @param istream The InputStream that contains the Word document.
+ * @throws IOException If there is an unexpected IOException from the passed
+ * in InputStream.
+ */
public HWPFDocument(InputStream istream) throws IOException
{
//do Ole stuff
// get the start of text in the main stream
int fcMin = _fib.getFcMin();
- DocumentProperties dop = new DocumentProperties(_tableStream, _fib.getFcDop());
- ComplexFileTable cft = new ComplexFileTable(_mainStream, _tableStream, _fib.getFcClx(), fcMin);
- CHPBinTable cbt = new CHPBinTable(_mainStream, _tableStream, _fib.getFcPlcfbteChpx(), _fib.getLcbPlcfbteChpx(), fcMin);
- PAPBinTable pbt = new PAPBinTable(_mainStream, _tableStream, _fib.getFcPlcfbtePapx(), _fib.getLcbPlcfbtePapx(), fcMin);
- SectionTable st = new SectionTable(_mainStream, _tableStream, _fib.getFcPlcfsed(), _fib.getLcbPlcfsed(), fcMin);
- StyleSheet ss = new StyleSheet(_tableStream, _fib.getFcStshf());
+ // load up our standard structures.
+ _dop = new DocumentProperties(_tableStream, _fib.getFcDop());
+ _cft = new ComplexFileTable(_mainStream, _tableStream, _fib.getFcClx(), fcMin);
+ _cbt = new CHPBinTable(_mainStream, _tableStream, _fib.getFcPlcfbteChpx(), _fib.getLcbPlcfbteChpx(), fcMin);
+ _pbt = new PAPBinTable(_mainStream, _tableStream, _fib.getFcPlcfbtePapx(), _fib.getLcbPlcfbtePapx(), fcMin);
+ _st = new SectionTable(_mainStream, _tableStream, _fib.getFcPlcfsed(), _fib.getLcbPlcfsed(), fcMin);
+ _ss = new StyleSheet(_tableStream, _fib.getFcStshf());
+ _ft = new FontTable(_tableStream, _fib.getFcSttbfffn(), _fib.getLcbSttbfffn());
int x = 0;
}
+ /**
+ * Writes out the word file that is represented by an instance of this class.
+ *
+ * @param out The OutputStream to write to.
+ * @throws IOException If there is an unexpected IOException from the passed
+ * in OutputStream.
+ */
+ public void write(OutputStream out)
+ throws IOException
+ {
+ // initialize our streams for writing.
+ HWPFFileSystem docSys = new HWPFFileSystem();
+ HWPFOutputStream mainStream = docSys.getStream("WordDocument");
+ HWPFOutputStream tableStream = docSys.getStream("1Table");
+ int tableOffset = 0;
+
+ // clear the offsets and sizes in our FileInformationBlock.
+ _fib.clearOffsetsSizes();
+
+ // determine the FileInformationBLock size
+ int fibSize = _fib.getSize();
+ fibSize += POIFSConstants.BIG_BLOCK_SIZE -
+ (fibSize % POIFSConstants.BIG_BLOCK_SIZE);
+
+ // preserve space for the FileInformationBlock because we will be writing
+ // it after we write everything else.
+ byte[] placeHolder = new byte[fibSize];
+ mainStream.write(placeHolder);
+ int mainOffset = mainStream.getOffset();
+
+ // write out the StyleSheet.
+ _fib.setFcStshf(tableOffset);
+ _ss.writeTo(tableStream);
+ _fib.setLcbStshf(tableStream.getOffset() - tableOffset);
+ tableOffset = tableStream.getOffset();
+
+ // get fcMin and fcMac because we will be writing the actual text with the
+ // complex table.
+ int fcMin = mainOffset;
+
+ // write out the Complex table, includes text.
+ _fib.setFcClx(tableOffset);
+ _cft.writeTo(docSys);
+ _fib.setLcbClx(tableStream.getOffset() - tableOffset);
+ tableOffset = tableStream.getOffset();
+ int fcMac = mainStream.getOffset();
+
+ // write out the CHPBinTable.
+ _fib.setFcPlcfbteChpx(tableOffset);
+ _cbt.writeTo(docSys, fcMin);
+ _fib.setLcbPlcfbteChpx(tableStream.getOffset() - tableOffset);
+ tableOffset = tableStream.getOffset();
+
+ // write out the PAPBinTable.
+ _fib.setFcPlcfbtePapx(tableOffset);
+ _pbt.writeTo(docSys, fcMin);
+ _fib.setLcbPlcfbtePapx(tableStream.getOffset() - tableOffset);
+ tableOffset = tableStream.getOffset();
+
+ // write out the SectionTable.
+ _fib.setFcPlcfsed(tableOffset);
+ _st.writeTo(docSys, fcMin);
+ _fib.setLcbPlcfsed(tableStream.getOffset() - tableOffset);
+ tableOffset = tableStream.getOffset();
+
+ // write out the FontTable.
+ _fib.setFcSttbfffn(tableOffset);
+ _ft.writeTo(docSys);
+ _fib.setLcbSttbfffn(tableStream.getOffset() - tableOffset);
+ tableOffset = tableStream.getOffset();
+
+ // write out the DocumentProperties.
+ _fib.setFcDop(tableOffset);
+ byte[] buf = new byte[_dop.getSize()];
+ _fib.setLcbDop(_dop.getSize());
+ _dop.serialize(buf, 0);
+ tableStream.write(buf);
+
+ // set some variables in the FileInformationBlock.
+ _fib.setFcMin(fcMin);
+ _fib.setFcMac(fcMac);
+ _fib.setCbMac(mainStream.getOffset());
+
+ // make sure that the table and doc stream use big blocks.
+ byte[] mainBuf = mainStream.toByteArray();
+ if (mainBuf.length < 4096)
+ {
+ byte[] tempBuf = new byte[4096];
+ System.arraycopy(mainBuf, 0, tempBuf, 0, mainBuf.length);
+ mainBuf = tempBuf;
+ }
+ byte[] tableBuf = tableStream.toByteArray();
+ if (tableBuf.length < 4096)
+ {
+ byte[] tempBuf = new byte[4096];
+ System.arraycopy(tableBuf, 0, tempBuf, 0, tableBuf.length);
+ tableBuf = tempBuf;
+ }
+
+ // write out the FileInformationBlock.
+ _fib.serialize(mainBuf, 0);
+
+ // spit out the Word document.
+ POIFSFileSystem pfs = new POIFSFileSystem();
+ pfs.createDocument(new ByteArrayInputStream(mainBuf), "WordDocument");
+ pfs.createDocument(new ByteArrayInputStream(tableBuf), "1Table");
+
+ pfs.writeFilesystem(out);
+ }
+
+ /**
+ * Takes two arguments, 1) name of the Word file to read in 2) location to
+ * write it out at.
+ * @param args
+ */
public static void main(String[] args)
{
+
try
{
HWPFDocument doc = new HWPFDocument(new FileInputStream(args[0]));
+ OutputStream out = new FileOutputStream(args[1]);
+ doc.write(out);
+
+ out.flush();
+ out.close();
+
+
}
catch (Throwable t)
{
int end = endingFc;
if (overflow != null)
{
- end = ((PropertyNode)overflow.get(0)).getStart();
+ end = ((PropertyNode)overflow.get(0)).getStart() + fcMin;
}
byte[] intHolder = new byte[4];
import org.apache.poi.util.BitField;
import org.apache.poi.util.LittleEndian;
+import java.util.Arrays;
-
+/**
+ * FFN - Font Family Name. FFN is a data structure that stores the names of the Main
+ * Font and that of Alternate font as an array of characters. It has also a header
+ * that stores info about the whole structure and the fonts
+ *
+ * @author Praveen Mathew
+ */
public class Ffn
{
- private int field1_cbFfnM1; //total length of FFN - 1.
- private byte field2;
+ private int field_1_cbFfnM1;//total length of FFN - 1.
+ private byte field_2;
private static BitField _prq = new BitField(0x0003);// pitch request
private static BitField _fTrueType = new BitField(0x0004);// when 1, font is a TrueType font
private static BitField _ff = new BitField(0x0070);
- private short field3_wWeight;// base weight of font
- private byte field4_chs;// character set identifier
- private byte field5_ixchSzAlt; // index into ffn.szFfn to the name of
+ private short field_3_wWeight;// base weight of font
+ private byte field_4_chs;// character set identifier
+ private byte field_5_ixchSzAlt; // index into ffn.szFfn to the name of
// the alternate font
- private byte [] panose = new byte[10]; //????
- private byte [] fontSig = new byte[24]; //????
+ private byte [] field_6_panose = new byte[10];//????
+ private byte [] field_7_fontSig = new byte[24];//????
// zero terminated string that records name of font, cuurently not
// supporting Extended chars
- private char [] xszFfn;
+ private char [] field_8_xszFfn;
+
+ // extra facilitator members
private int xszFfnLength;
public Ffn(byte[] buf, int offset)
{
- field1_cbFfnM1 = LittleEndian.getUnsignedByte(buf, offset);
+ int offsetTmp = offset;
+
+ field_1_cbFfnM1 = LittleEndian.getUnsignedByte(buf,offset);
offset += LittleEndian.BYTE_SIZE;
- field2 = buf[offset];
+ field_2 = buf[offset];
offset += LittleEndian.BYTE_SIZE;
- field3_wWeight = LittleEndian.getShort(buf, offset);
+ field_3_wWeight = LittleEndian.getShort(buf, offset);
offset += LittleEndian.SHORT_SIZE;
- field4_chs = buf[offset];
+ field_4_chs = buf[offset];
offset += LittleEndian.BYTE_SIZE;
- field5_ixchSzAlt = buf[offset];
+ field_5_ixchSzAlt = buf[offset];
offset += LittleEndian.BYTE_SIZE;
// read panose and fs so we can write them back out.
- System.arraycopy(buf, offset, panose, 0, panose.length);
- offset += panose.length;
- System.arraycopy(buf, offset, fontSig, 0, fontSig.length);
- offset += fontSig.length;
+ System.arraycopy(buf, offset, field_6_panose, 0, field_6_panose.length);
+ offset += field_6_panose.length;
+ System.arraycopy(buf, offset, field_7_fontSig, 0, field_7_fontSig.length);
+ offset += field_7_fontSig.length;
- xszFfnLength = this.getSize() - offset;
- xszFfn = new char[xszFfnLength];
+ offsetTmp = offset - offsetTmp;
+ xszFfnLength = this.getSize() - offsetTmp;
+ field_8_xszFfn = new char[xszFfnLength];
for(int i = 0; i < xszFfnLength; i++)
{
- xszFfn[i] = (char)LittleEndian.getUnsignedByte(buf, offset);
+ field_8_xszFfn[i] = (char)LittleEndian.getUnsignedByte(buf, offset);
offset += LittleEndian.BYTE_SIZE;
}
}
- public int getField1_cbFfnM1()
+ public int getField_1_cbFfnM1()
+ {
+ return field_1_cbFfnM1;
+ }
+
+ public byte getField_2()
+ {
+ return field_2;
+ }
+
+ public short getField_3_wWeight()
+ {
+ return field_3_wWeight;
+ }
+
+ public byte getField_4_chs()
+ {
+ return field_4_chs;
+ }
+
+ public byte getField_5_ixchSzAlt()
+ {
+ return field_5_ixchSzAlt;
+ }
+
+ public byte [] getField_6_panose()
+ {
+ return field_6_panose;
+ }
+
+ public byte [] getField_7_fontSig()
+ {
+ return field_7_fontSig;
+ }
+
+ public char [] getField_8_xszFfn()
{
- return field1_cbFfnM1;
+ return field_8_xszFfn;
}
public int getSize()
{
- return (field1_cbFfnM1 + 1);
+ return (field_1_cbFfnM1 + 1);
}
public char [] getMainFontName()
{
- char [] temp = new char[field5_ixchSzAlt];
- System.arraycopy(xszFfn,0,temp,0,temp.length);
+ char [] temp = new char[field_5_ixchSzAlt];
+ System.arraycopy(field_8_xszFfn,0,temp,0,temp.length);
return temp;
}
public char [] getAltFontName()
{
- char [] temp = new char[xszFfnLength - field5_ixchSzAlt];
- System.arraycopy(xszFfn, field5_ixchSzAlt, temp, 0, temp.length);
+ char [] temp = new char[xszFfnLength - field_5_ixchSzAlt];
+ System.arraycopy(field_8_xszFfn, field_5_ixchSzAlt, temp, 0, temp.length);
return temp;
}
- public void setField1_cbFfnM1(short field1_cbFfnM1)
+ public void setField_1_cbFfnM1(int field_1_cbFfnM1)
{
- this.field1_cbFfnM1 = field1_cbFfnM1;
+ this.field_1_cbFfnM1 = field_1_cbFfnM1;
}
- protected byte[] toByteArray()
+ // changed protected to public
+ public byte[] toByteArray()
{
- //return buf;
- return null;
+ int offset = 0;
+ byte[] buf = new byte[this.getSize()];
+
+ buf[offset] = (byte)field_1_cbFfnM1;
+ offset += LittleEndian.BYTE_SIZE;
+ buf[offset] = field_2;
+ offset += LittleEndian.BYTE_SIZE;
+ LittleEndian.putShort(buf, offset, field_3_wWeight);
+ offset += LittleEndian.SHORT_SIZE;
+ buf[offset] = field_4_chs;
+ offset += LittleEndian.BYTE_SIZE;
+ buf[offset] = field_5_ixchSzAlt;
+ offset += LittleEndian.BYTE_SIZE;
+
+ System.arraycopy(field_6_panose,0,buf, offset,field_6_panose.length);
+ offset += field_6_panose.length;
+ System.arraycopy(field_7_fontSig,0,buf, offset, field_7_fontSig.length);
+ offset += field_7_fontSig.length;
+
+ for(int i = 0; i < field_8_xszFfn.length; i++)
+ {
+ buf[offset] = (byte)field_8_xszFfn[i];
+ offset += LittleEndian.BYTE_SIZE;
+ }
+
+ return buf;
+
+ }
+
+ public boolean equals(Object o)
+ {
+ boolean retVal = true;
+
+ if (((Ffn)o).getField_1_cbFfnM1() == field_1_cbFfnM1)
+ {
+ if(((Ffn)o).getField_2() == field_2)
+ {
+ if(((Ffn)o).getField_3_wWeight() == field_3_wWeight)
+ {
+ if(((Ffn)o).getField_4_chs() == field_4_chs)
+ {
+ if(((Ffn)o).getField_5_ixchSzAlt() == field_5_ixchSzAlt)
+ {
+ if(Arrays.equals(((Ffn)o).getField_6_panose(),field_6_panose))
+ {
+ if(Arrays.equals(((Ffn)o).getField_7_fontSig(),field_7_fontSig))
+ {
+ if(!(Arrays.equals(((Ffn)o).getField_8_xszFfn(),field_8_xszFfn)))
+ retVal = false;
+ }
+ else
+ retVal = false;
+ }
+ else
+ retVal = false;
+ }
+ else
+ retVal = false;
+ }
+ else
+ retVal = false;
+ }
+ else
+ retVal = false;
+ }
+ else
+ retVal = false;
+ }
+ else
+ retVal = false;
+
+ return retVal;
}
}
+
package org.apache.poi.hwpf.model.hdftypes;
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Field;
+
import org.apache.poi.util.BitField;
import org.apache.poi.util.LittleEndian;
* @author andy
*/
public class FileInformationBlock extends FIBAbstractType
+ implements Cloneable
{
/** Creates a new instance of FileInformationBlock */
fillFields(mainDocument, (short)0, (short)0);
}
+ public void clearOffsetsSizes()
+ {
+ try
+ {
+ Field[] fields = FileInformationBlock.class.getSuperclass().getDeclaredFields();
+ AccessibleObject.setAccessible(fields, true);
+
+ for (int x = 0; x < fields.length; x++)
+ {
+ String name = fields[x].getName();
+ int index = name.indexOf('_');
+ if (index != -1)
+ {
+ int nextIndex = name.indexOf('_', index + 1);
+ if (nextIndex != -1)
+ {
+ // clear any field greater than field_53
+ if (Integer.parseInt(name.substring(index + 1, nextIndex)) > 53)
+ {
+ fields[x].setInt(this, 0);
+ }
+ }
+ }
+ }
+ }
+ catch (IllegalAccessException iae)
+ {
+ iae.printStackTrace();
+ }
+ }
+
+ public Object clone()
+ {
+ try
+ {
+ return super.clone();
+ }
+ catch (CloneNotSupportedException e)
+ {
+ e.printStackTrace();
+ return null;
+ }
+ }
}
package org.apache.poi.hwpf.model.hdftypes;
-import org.apache.poi.util.BitField;
+import java.io.IOException;
+import org.apache.poi.hwpf.model.io.HWPFFileSystem;
+import org.apache.poi.hwpf.model.io.HWPFOutputStream;
import org.apache.poi.util.LittleEndian;
-
+/**
+ * FontTable or in MS terminology sttbfffn is a common data structure written in all
+ * Word files. The sttbfffn is an sttbf where each string is an FFN structure instead
+ * of pascal-style strings. An sttbf is a string Table stored in file. Thus sttbffn
+ * is like an Sttbf with an array of FFN structures that stores the font name strings
+ *
+ * @author Praveen Mathew
+ */
public class FontTable
{
- private short exntdChar; // strings are extended character if = 0xFFFF
- private short stringCount; // how many strings are included in the string table
- private short extraDataSz; // size in bytes of the extra data
-
- private int lcbSttbfffn; // count of bytes in sttbfffn
- private boolean isExtndChar;
+ private short _stringCount;// how many strings are included in the string table
+ private short _extraDataSz;// size in bytes of the extra data
+ // added extra facilitator members
+ private int lcbSttbfffn;// count of bytes in sttbfffn
+ private int fcSttbfffn;// table stream offset for sttbfffn
// FFN structure containing strings of font names
- private Ffn [] fontNames = null;
+ private Ffn[] _fontNames = null;
+
public FontTable(byte[] buf, int offset, int lcbSttbfffn)
{
this.lcbSttbfffn = lcbSttbfffn;
+ this.fcSttbfffn = offset;
- exntdChar = LittleEndian.getShort(buf, offset);
+ _stringCount = LittleEndian.getShort(buf, offset);
offset += LittleEndian.SHORT_SIZE;
- stringCount = LittleEndian.getShort(buf, offset);
+ _extraDataSz = LittleEndian.getShort(buf, offset);
offset += LittleEndian.SHORT_SIZE;
- extraDataSz = LittleEndian.getShort(buf, offset);
- offset += LittleEndian.SHORT_SIZE;
-
- if ((exntdChar & 0xFFFF) == 0xFFFF)
- {
- isExtndChar = true;
- }
- else
- {
- isExtndChar = false;
- }
- fontNames = new Ffn[stringCount]; //Ffn corresponds to a Pascal style String in STTBF.
+ _fontNames = new Ffn[_stringCount]; //Ffn corresponds to a Pascal style String in STTBF.
- for(int i = 0;i<stringCount; i++)
+ for(int i = 0;i<_stringCount; i++)
{
- // some mistake in the fields we have chosen
- if(offset >= this.getSize())
- {
- System.out.println("Total size of Sttbfn mismatched with calculated size");
- break;
- }
-
- fontNames[i] = new Ffn(buf,offset);
- offset += fontNames[i].getSize();
+ _fontNames[i] = new Ffn(buf,offset);
+ offset += _fontNames[i].getSize();
}
}
- public boolean isExtndChar()
+ public short getStringCount()
{
- return isExtndChar;
+ return _stringCount;
}
- public short getStringCount()
+ public short getExtraDataSz()
+ {
+ return _extraDataSz;
+ }
+
+ public Ffn[] getFontNames()
{
- return stringCount;
+ return _fontNames;
}
public int getSize()
public char [] getMainFont(int chpFtc )
{
- if(chpFtc >= stringCount)
+ if(chpFtc >= _stringCount)
{
System.out.println("Mismatch in chpFtc with stringCount");
return null;
}
- return fontNames[chpFtc].getMainFontName();
+ return _fontNames[chpFtc].getMainFontName();
}
public char [] getAltFont(int chpFtc )
{
- if(chpFtc >= stringCount)
+ if(chpFtc >= _stringCount)
{
System.out.println("Mismatch in chpFtc with stringCount");
return null;
}
- return fontNames[chpFtc].getAltFontName();
+ return _fontNames[chpFtc].getAltFontName();
}
public void setStringCount(short stringCount)
{
- this.stringCount = stringCount;
+ this._stringCount = stringCount;
}
+ public void writeTo(HWPFFileSystem sys)
+ throws IOException
+ {
+ HWPFOutputStream tableStream = sys.getStream("1Table");
+
+ byte[] buf = new byte[LittleEndian.SHORT_SIZE];
+ LittleEndian.putShort(buf, _stringCount);
+ tableStream.write(buf);
+ LittleEndian.putShort(buf, _extraDataSz);
+ tableStream.write(buf);
+
+ for(int i = 0; i < _fontNames.length; i++)
+ {
+ tableStream.write(_fontNames[i].toByteArray());
+ }
+
+ }
+
+ public boolean equals(Object o)
+ {
+ boolean retVal = true;
+
+ if(((FontTable)o).getStringCount() == _stringCount)
+ {
+ if(((FontTable)o).getExtraDataSz() == _extraDataSz)
+ {
+ Ffn[] fontNamesNew = ((FontTable)o).getFontNames();
+ for(int i = 0;i<_stringCount; i++)
+ {
+ if(!(_fontNames[i].equals(fontNamesNew[i])))
+ retVal = false;
+ }
+ }
+ else
+ retVal = false;
+ }
+ else
+ retVal = false;
+
+
+ return retVal;
+ }
+
+
}
+
int end = endingFc;
if (overflow != null)
{
- end = ((PropertyNode)overflow.get(0)).getStart();
+ end = ((PropertyNode)overflow.get(0)).getStart() + fcMin;
}
byte[] intHolder = new byte[4];
import java.util.ArrayList;
import java.util.List;
+import java.util.Arrays;
/**
* Represents a PAP FKP. The style properties for paragraph and character runs
int grpprlOffset = 0;
int bxOffset = 0;
int fcOffset = 0;
+ byte[] lastGrpprl = new byte[0];
// total size is currently the size of one FC
int totalSize = FC_SIZE;
int index = 0;
for (; index < size; index++)
{
- int grpprlLength = ((PAPX)_papxList.get(index)).getGrpprl().length;
+ byte[] grpprl = ((PAPX)_papxList.get(index)).getGrpprl();
+ int grpprlLength = grpprl.length;
// check to see if we have enough room for an FC, a BX, and the grpprl
// and the 1 byte size of the grpprl.
- totalSize += (FC_SIZE + BX_SIZE + grpprlLength + 1);
+ int addition = 0;
+ if (!Arrays.equals(grpprl, lastGrpprl))
+ {
+ addition = (FC_SIZE + BX_SIZE + grpprlLength + 1);
+ }
+ else
+ {
+ addition = (FC_SIZE + BX_SIZE);
+ }
+
+ totalSize += addition;
+
// if size is uneven we will have to add one so the first grpprl falls
// on a word boundary
if (totalSize > 511 + (index % 2))
{
- totalSize -= (FC_SIZE + BX_SIZE + grpprlLength);
+ totalSize -= addition;
break;
}
{
totalSize += 2;
}
+ lastGrpprl = grpprl;
}
// see if we couldn't fit some
grpprlOffset = 511;
PAPX papx = null;
+ lastGrpprl = new byte[0];
for (int x = 0; x < index; x++)
{
papx = (PAPX)_papxList.get(x);
byte[] phe = papx.getParagraphHeight().toByteArray();
byte[] grpprl = papx.getGrpprl();
- grpprlOffset -= (grpprl.length + (2 - grpprl.length % 2));
- grpprlOffset -= (grpprlOffset % 2);
+ boolean same = Arrays.equals(lastGrpprl, grpprl);
+ if (!same)
+ {
+ grpprlOffset -= (grpprl.length + (2 - grpprl.length % 2));
+ grpprlOffset -= (grpprlOffset % 2);
+ }
LittleEndian.putInt(buf, fcOffset, papx.getStart() + fcMin);
buf[bxOffset] = (byte)(grpprlOffset/2);
System.arraycopy(phe, 0, buf, bxOffset + 1, phe.length);
// refer to the section on PAPX in the spec. Places a size on the front
// of the PAPX. Has to do with how the grpprl stays on word
// boundaries.
- int copyOffset = grpprlOffset;
- if ((grpprl.length % 2) > 0)
- {
- buf[copyOffset++] = (byte)((grpprl.length + 1)/2);
- }
- else
+ if (!same)
{
- buf[++copyOffset] = (byte)((grpprl.length)/2);
- copyOffset++;
+ int copyOffset = grpprlOffset;
+ if ( (grpprl.length % 2) > 0)
+ {
+ buf[copyOffset++] = (byte) ( (grpprl.length + 1) / 2);
+ }
+ else
+ {
+ buf[++copyOffset] = (byte) ( (grpprl.length) / 2);
+ copyOffset++;
+ }
+ System.arraycopy(grpprl, 0, buf, copyOffset, grpprl.length);
+ lastGrpprl = grpprl;
}
- System.arraycopy(grpprl, 0, buf, copyOffset, grpprl.length);
bxOffset += BX_SIZE;
fcOffset += FC_SIZE;
+
}
// put the last papx's end in
LittleEndian.putInt(buf, fcOffset, papx.getEnd() + fcMin);
// the spec only refers to two possible upxs but it mentions
// that more may be added in the future
- int add = 0;
+ int varOffset = grupxStart;
int numUPX = _numUPX.getValue(_infoShort3);
for(int x = 0; x < numUPX; x++)
{
- int upxSize = LittleEndian.getShort(std, grupxStart + add);
+ int upxSize = LittleEndian.getShort(std, varOffset);
+ varOffset += LittleEndian.SHORT_SIZE;
if(_styleTypeCode.getValue(_infoShort2) == PARAGRAPH_STYLE)
{
if(x == 0)
{
- _istd = LittleEndian.getShort(std, grupxStart + add + 2);
+ _istd = LittleEndian.getShort(std, varOffset);
+ varOffset += LittleEndian.SHORT_SIZE;
int grrprlSize = upxSize - 2;
- _papx = new byte[upxSize];
- System.arraycopy(std, grupxStart + add + 4, _papx, 0, grrprlSize);
+ _papx = new byte[grrprlSize];
+ System.arraycopy(std, varOffset, _papx, 0, grrprlSize);
+ varOffset += grrprlSize;
}
else if(x == 1)
{
_chpx = new byte[upxSize];
- System.arraycopy(std, grupxStart + add + 2, _chpx, 0, upxSize);
+ System.arraycopy(std, varOffset, _chpx, 0, upxSize);
+ varOffset += upxSize;
}
}
else if(_styleTypeCode.getValue(_infoShort2) == CHARACTER_STYLE && x == 0)
{
_chpx = new byte[upxSize];
- System.arraycopy(std, grupxStart + add + 2, _chpx, 0, upxSize);
+ System.arraycopy(std, varOffset, _chpx, 0, upxSize);
}
// the upx will always start on a word boundary.
if(upxSize % 2 == 1)
{
- ++upxSize;
+ ++varOffset;
}
- add += 2 + upxSize;
+
}
//only worry about papx and chpx for upxs
if(_styleTypeCode.getValue(_infoShort2) == PARAGRAPH_STYLE)
{
- LittleEndian.putShort(buf, offset, (short)_papx.length);
+ LittleEndian.putShort(buf, offset, (short)(_papx.length + 2));
offset += LittleEndian.SHORT_SIZE;
LittleEndian.putShort(buf, offset, (short)_istd);
offset += LittleEndian.SHORT_SIZE;
throws IOException
{
int offset = 0;
- // add two bytes so we can prepend the styelsheet w/ its size
+ // add two bytes so we can prepend the stylesheet w/ its size
byte[] buf = new byte[_stshiLength + 2];
LittleEndian.putShort(buf, offset, (short)_stshiLength);
offset += LittleEndian.SHORT_SIZE;
--- /dev/null
+package org.apache.poi.hwpf.model.hdftypes;
+
+import junit.framework.*;
+import org.apache.poi.hwpf.*;
+
+import java.lang.reflect.*;
+import java.util.Arrays;
+
+public class TestDocumentProperties
+ extends TestCase
+{
+ private DocumentProperties _documentProperties = null;
+ private HWPFDocFixture _hWPFDocFixture;
+
+ public TestDocumentProperties(String name)
+ {
+ super(name);
+ }
+
+
+ public void testReadWrite()
+ throws Exception
+ {
+ int size = _documentProperties.getSize();
+ byte[] buf = new byte[size];
+
+ _documentProperties.serialize(buf, 0);
+
+ DocumentProperties newDocProperties =
+ new DocumentProperties(buf, 0);
+
+ Field[] fields = DocumentProperties.class.getSuperclass().getDeclaredFields();
+ AccessibleObject.setAccessible(fields, true);
+
+ for (int x = 0; x < fields.length; x++)
+ {
+ if (!fields[x].getType().isArray())
+ {
+ assertEquals(fields[x].get(_documentProperties),
+ fields[x].get(newDocProperties));
+ }
+ else
+ {
+ byte[] buf1 = (byte[])fields[x].get(_documentProperties);
+ byte[] buf2 = (byte[])fields[x].get(newDocProperties);
+ Arrays.equals(buf1, buf2);
+ }
+ }
+
+ }
+
+ protected void setUp()
+ throws Exception
+ {
+ super.setUp();
+ /**@todo verify the constructors*/
+
+ _hWPFDocFixture = new HWPFDocFixture(this);
+
+ _hWPFDocFixture.setUp();
+
+ _documentProperties = new DocumentProperties(_hWPFDocFixture._tableStream, _hWPFDocFixture._fib.getFcDop());
+ }
+
+ protected void tearDown()
+ throws Exception
+ {
+ _documentProperties = null;
+ _hWPFDocFixture.tearDown();
+
+ _hWPFDocFixture = null;
+ super.tearDown();
+ }
+
+}
--- /dev/null
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2003 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache POI" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache POI", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+package org.apache.poi.hwpf.model.hdftypes;
+
+import junit.framework.*;
+import org.apache.poi.hwpf.*;
+import org.apache.poi.hwpf.model.io.*;
+
+import java.io.*;
+import java.util.*;
+
+public class TestFontTable
+ extends TestCase
+{
+ private FontTable _fontTable = null;
+ private HWPFDocFixture _hWPFDocFixture;
+
+ public TestFontTable(String name)
+ {
+ super(name);
+ }
+
+ public void testReadWrite()
+ throws Exception
+ {
+ FileInformationBlock fib = _hWPFDocFixture._fib;
+ byte[] tableStream = _hWPFDocFixture._tableStream;
+
+ int fcSttbfffn = fib.getFcSttbfffn();
+ int lcbSttbfffn = fib.getLcbSttbfffn();
+
+ _fontTable = new FontTable(tableStream, fcSttbfffn, lcbSttbfffn);
+
+ HWPFFileSystem fileSys = new HWPFFileSystem();
+
+ _fontTable.writeTo(fileSys);
+ HWPFOutputStream tableOut = fileSys.getStream("1Table");
+
+
+ byte[] newTableStream = tableOut.toByteArray();
+
+
+ FontTable newFontTable = new FontTable(newTableStream, 0, newTableStream.length);
+
+ assertTrue(_fontTable.equals(newFontTable));
+
+ }
+
+ protected void setUp()
+ throws Exception
+ {
+ super.setUp();
+ /**@todo verify the constructors*/
+ _hWPFDocFixture = new HWPFDocFixture(this);
+
+ _hWPFDocFixture.setUp();
+ }
+
+ protected void tearDown()
+ throws Exception
+ {
+ _hWPFDocFixture.tearDown();
+
+ _hWPFDocFixture = null;
+ super.tearDown();
+ }
+
+}
+