Reached first milestone

git-svn-id: https://svn.apache.org/repos/asf/jakarta/poi/trunk@353212 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Said Ryan Ackley 2003-07-15 03:23:40 +00:00
parent 9aae367586
commit 7132ebe1c5
11 changed files with 709 additions and 113 deletions

View File

@ -57,14 +57,23 @@ package org.apache.poi.hwpf;
import java.io.InputStream; import java.io.InputStream;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.IOException; 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.POIFSFileSystem;
import org.apache.poi.poifs.filesystem.DocumentEntry; 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.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 * @author Ryan Ackley
*/ */
public class HWPFDocument public class HWPFDocument
@ -76,11 +85,40 @@ public class HWPFDocument
private FileInformationBlock _fib; private FileInformationBlock _fib;
/** main document stream buffer*/ /** main document stream buffer*/
byte[] _mainStream; private byte[] _mainStream;
/** table stream buffer*/ /** 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 public HWPFDocument(InputStream istream) throws IOException
{ {
//do Ole stuff //do Ole stuff
@ -110,23 +148,148 @@ public class HWPFDocument
// get the start of text in the main stream // get the start of text in the main stream
int fcMin = _fib.getFcMin(); int fcMin = _fib.getFcMin();
DocumentProperties dop = new DocumentProperties(_tableStream, _fib.getFcDop()); // load up our standard structures.
ComplexFileTable cft = new ComplexFileTable(_mainStream, _tableStream, _fib.getFcClx(), fcMin); _dop = new DocumentProperties(_tableStream, _fib.getFcDop());
CHPBinTable cbt = new CHPBinTable(_mainStream, _tableStream, _fib.getFcPlcfbteChpx(), _fib.getLcbPlcfbteChpx(), fcMin); _cft = new ComplexFileTable(_mainStream, _tableStream, _fib.getFcClx(), fcMin);
PAPBinTable pbt = new PAPBinTable(_mainStream, _tableStream, _fib.getFcPlcfbtePapx(), _fib.getLcbPlcfbtePapx(), fcMin); _cbt = new CHPBinTable(_mainStream, _tableStream, _fib.getFcPlcfbteChpx(), _fib.getLcbPlcfbteChpx(), fcMin);
SectionTable st = new SectionTable(_mainStream, _tableStream, _fib.getFcPlcfsed(), _fib.getLcbPlcfsed(), fcMin); _pbt = new PAPBinTable(_mainStream, _tableStream, _fib.getFcPlcfbtePapx(), _fib.getLcbPlcfbtePapx(), fcMin);
StyleSheet ss = new StyleSheet(_tableStream, _fib.getFcStshf()); _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; 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) public static void main(String[] args)
{ {
try try
{ {
HWPFDocument doc = new HWPFDocument(new FileInputStream(args[0])); HWPFDocument doc = new HWPFDocument(new FileInputStream(args[0]));
OutputStream out = new FileOutputStream(args[1]);
doc.write(out);
out.flush();
out.close();
} }
catch (Throwable t) catch (Throwable t)
{ {

View File

@ -142,7 +142,7 @@ public class CHPBinTable
int end = endingFc; int end = endingFc;
if (overflow != null) if (overflow != null)
{ {
end = ((PropertyNode)overflow.get(0)).getStart(); end = ((PropertyNode)overflow.get(0)).getStart() + fcMin;
} }
byte[] intHolder = new byte[4]; byte[] intHolder = new byte[4];

View File

@ -56,93 +56,212 @@ package org.apache.poi.hwpf.model.hdftypes;
import org.apache.poi.util.BitField; import org.apache.poi.util.BitField;
import org.apache.poi.util.LittleEndian; 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 public class Ffn
{ {
private int field1_cbFfnM1; //total length of FFN - 1. private int field_1_cbFfnM1;//total length of FFN - 1.
private byte field2; private byte field_2;
private static BitField _prq = new BitField(0x0003);// pitch request 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 _fTrueType = new BitField(0x0004);// when 1, font is a TrueType font
private static BitField _ff = new BitField(0x0070); private static BitField _ff = new BitField(0x0070);
private short field3_wWeight;// base weight of font private short field_3_wWeight;// base weight of font
private byte field4_chs;// character set identifier private byte field_4_chs;// character set identifier
private byte field5_ixchSzAlt; // index into ffn.szFfn to the name of private byte field_5_ixchSzAlt; // index into ffn.szFfn to the name of
// the alternate font // the alternate font
private byte [] panose = new byte[10]; //???? private byte [] field_6_panose = new byte[10];//????
private byte [] fontSig = new byte[24]; //???? private byte [] field_7_fontSig = new byte[24];//????
// zero terminated string that records name of font, cuurently not // zero terminated string that records name of font, cuurently not
// supporting Extended chars // supporting Extended chars
private char [] xszFfn; private char [] field_8_xszFfn;
// extra facilitator members
private int xszFfnLength; private int xszFfnLength;
public Ffn(byte[] buf, int offset) 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; offset += LittleEndian.BYTE_SIZE;
field2 = buf[offset]; field_2 = buf[offset];
offset += LittleEndian.BYTE_SIZE; offset += LittleEndian.BYTE_SIZE;
field3_wWeight = LittleEndian.getShort(buf, offset); field_3_wWeight = LittleEndian.getShort(buf, offset);
offset += LittleEndian.SHORT_SIZE; offset += LittleEndian.SHORT_SIZE;
field4_chs = buf[offset]; field_4_chs = buf[offset];
offset += LittleEndian.BYTE_SIZE; offset += LittleEndian.BYTE_SIZE;
field5_ixchSzAlt = buf[offset]; field_5_ixchSzAlt = buf[offset];
offset += LittleEndian.BYTE_SIZE; offset += LittleEndian.BYTE_SIZE;
// read panose and fs so we can write them back out. // read panose and fs so we can write them back out.
System.arraycopy(buf, offset, panose, 0, panose.length); System.arraycopy(buf, offset, field_6_panose, 0, field_6_panose.length);
offset += panose.length; offset += field_6_panose.length;
System.arraycopy(buf, offset, fontSig, 0, fontSig.length); System.arraycopy(buf, offset, field_7_fontSig, 0, field_7_fontSig.length);
offset += fontSig.length; offset += field_7_fontSig.length;
xszFfnLength = this.getSize() - offset; offsetTmp = offset - offsetTmp;
xszFfn = new char[xszFfnLength]; xszFfnLength = this.getSize() - offsetTmp;
field_8_xszFfn = new char[xszFfnLength];
for(int i = 0; i < xszFfnLength; i++) 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; offset += LittleEndian.BYTE_SIZE;
} }
} }
public int getField1_cbFfnM1() public int getField_1_cbFfnM1()
{ {
return field1_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 field_8_xszFfn;
} }
public int getSize() public int getSize()
{ {
return (field1_cbFfnM1 + 1); return (field_1_cbFfnM1 + 1);
} }
public char [] getMainFontName() public char [] getMainFontName()
{ {
char [] temp = new char[field5_ixchSzAlt]; char [] temp = new char[field_5_ixchSzAlt];
System.arraycopy(xszFfn,0,temp,0,temp.length); System.arraycopy(field_8_xszFfn,0,temp,0,temp.length);
return temp; return temp;
} }
public char [] getAltFontName() public char [] getAltFontName()
{ {
char [] temp = new char[xszFfnLength - field5_ixchSzAlt]; char [] temp = new char[xszFfnLength - field_5_ixchSzAlt];
System.arraycopy(xszFfn, field5_ixchSzAlt, temp, 0, temp.length); System.arraycopy(field_8_xszFfn, field_5_ixchSzAlt, temp, 0, temp.length);
return temp; 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; int offset = 0;
return null; 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;
} }
} }

View File

@ -55,6 +55,9 @@
package org.apache.poi.hwpf.model.hdftypes; 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.BitField;
import org.apache.poi.util.LittleEndian; import org.apache.poi.util.LittleEndian;
@ -66,6 +69,7 @@ import org.apache.poi.hwpf.model.hdftypes.definitions.FIBAbstractType;
* @author andy * @author andy
*/ */
public class FileInformationBlock extends FIBAbstractType public class FileInformationBlock extends FIBAbstractType
implements Cloneable
{ {
/** Creates a new instance of FileInformationBlock */ /** Creates a new instance of FileInformationBlock */
@ -74,5 +78,48 @@ public class FileInformationBlock extends FIBAbstractType
fillFields(mainDocument, (short)0, (short)0); 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;
}
}
} }

View File

@ -54,67 +54,64 @@
package org.apache.poi.hwpf.model.hdftypes; 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; 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 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 stringCount; // how many strings are included in the string table private short _extraDataSz;// size in bytes of the extra data
private short extraDataSz; // size in bytes of the extra data
private int lcbSttbfffn; // count of bytes in sttbfffn
private boolean isExtndChar;
// 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 // FFN structure containing strings of font names
private Ffn [] fontNames = null; private Ffn[] _fontNames = null;
public FontTable(byte[] buf, int offset, int lcbSttbfffn) public FontTable(byte[] buf, int offset, int lcbSttbfffn)
{ {
this.lcbSttbfffn = lcbSttbfffn; this.lcbSttbfffn = lcbSttbfffn;
this.fcSttbfffn = offset;
exntdChar = LittleEndian.getShort(buf, offset); _stringCount = LittleEndian.getShort(buf, offset);
offset += LittleEndian.SHORT_SIZE; 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; offset += LittleEndian.SHORT_SIZE;
if ((exntdChar & 0xFFFF) == 0xFFFF) _fontNames = new Ffn[_stringCount]; //Ffn corresponds to a Pascal style String in STTBF.
for(int i = 0;i<_stringCount; i++)
{ {
isExtndChar = true; _fontNames[i] = new Ffn(buf,offset);
offset += _fontNames[i].getSize();
} }
else
{
isExtndChar = false;
}
fontNames = new Ffn[stringCount]; //Ffn corresponds to a Pascal style String in STTBF.
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();
}
}
public boolean isExtndChar()
{
return isExtndChar;
} }
public short getStringCount() public short getStringCount()
{ {
return stringCount; return _stringCount;
}
public short getExtraDataSz()
{
return _extraDataSz;
}
public Ffn[] getFontNames()
{
return _fontNames;
} }
public int getSize() public int getSize()
@ -124,31 +121,76 @@ public class FontTable
public char [] getMainFont(int chpFtc ) public char [] getMainFont(int chpFtc )
{ {
if(chpFtc >= stringCount) if(chpFtc >= _stringCount)
{ {
System.out.println("Mismatch in chpFtc with stringCount"); System.out.println("Mismatch in chpFtc with stringCount");
return null; return null;
} }
return fontNames[chpFtc].getMainFontName(); return _fontNames[chpFtc].getMainFontName();
} }
public char [] getAltFont(int chpFtc ) public char [] getAltFont(int chpFtc )
{ {
if(chpFtc >= stringCount) if(chpFtc >= _stringCount)
{ {
System.out.println("Mismatch in chpFtc with stringCount"); System.out.println("Mismatch in chpFtc with stringCount");
return null; return null;
} }
return fontNames[chpFtc].getAltFontName(); return _fontNames[chpFtc].getAltFontName();
} }
public void setStringCount(short stringCount) 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;
}
} }

View File

@ -141,7 +141,7 @@ public class PAPBinTable
int end = endingFc; int end = endingFc;
if (overflow != null) if (overflow != null)
{ {
end = ((PropertyNode)overflow.get(0)).getStart(); end = ((PropertyNode)overflow.get(0)).getStart() + fcMin;
} }
byte[] intHolder = new byte[4]; byte[] intHolder = new byte[4];

View File

@ -58,6 +58,7 @@ import org.apache.poi.util.LittleEndian;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Arrays;
/** /**
* Represents a PAP FKP. The style properties for paragraph and character runs * Represents a PAP FKP. The style properties for paragraph and character runs
@ -152,6 +153,7 @@ public class PAPFormattedDiskPage extends FormattedDiskPage
int grpprlOffset = 0; int grpprlOffset = 0;
int bxOffset = 0; int bxOffset = 0;
int fcOffset = 0; int fcOffset = 0;
byte[] lastGrpprl = new byte[0];
// total size is currently the size of one FC // total size is currently the size of one FC
int totalSize = FC_SIZE; int totalSize = FC_SIZE;
@ -159,16 +161,28 @@ public class PAPFormattedDiskPage extends FormattedDiskPage
int index = 0; int index = 0;
for (; index < size; index++) 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 // check to see if we have enough room for an FC, a BX, and the grpprl
// and the 1 byte size of 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 // if size is uneven we will have to add one so the first grpprl falls
// on a word boundary // on a word boundary
if (totalSize > 511 + (index % 2)) if (totalSize > 511 + (index % 2))
{ {
totalSize -= (FC_SIZE + BX_SIZE + grpprlLength); totalSize -= addition;
break; break;
} }
@ -181,6 +195,7 @@ public class PAPFormattedDiskPage extends FormattedDiskPage
{ {
totalSize += 2; totalSize += 2;
} }
lastGrpprl = grpprl;
} }
// see if we couldn't fit some // see if we couldn't fit some
@ -197,14 +212,19 @@ public class PAPFormattedDiskPage extends FormattedDiskPage
grpprlOffset = 511; grpprlOffset = 511;
PAPX papx = null; PAPX papx = null;
lastGrpprl = new byte[0];
for (int x = 0; x < index; x++) for (int x = 0; x < index; x++)
{ {
papx = (PAPX)_papxList.get(x); papx = (PAPX)_papxList.get(x);
byte[] phe = papx.getParagraphHeight().toByteArray(); byte[] phe = papx.getParagraphHeight().toByteArray();
byte[] grpprl = papx.getGrpprl(); byte[] grpprl = papx.getGrpprl();
grpprlOffset -= (grpprl.length + (2 - grpprl.length % 2)); boolean same = Arrays.equals(lastGrpprl, grpprl);
grpprlOffset -= (grpprlOffset % 2); if (!same)
{
grpprlOffset -= (grpprl.length + (2 - grpprl.length % 2));
grpprlOffset -= (grpprlOffset % 2);
}
LittleEndian.putInt(buf, fcOffset, papx.getStart() + fcMin); LittleEndian.putInt(buf, fcOffset, papx.getStart() + fcMin);
buf[bxOffset] = (byte)(grpprlOffset/2); buf[bxOffset] = (byte)(grpprlOffset/2);
System.arraycopy(phe, 0, buf, bxOffset + 1, phe.length); System.arraycopy(phe, 0, buf, bxOffset + 1, phe.length);
@ -212,20 +232,25 @@ public class PAPFormattedDiskPage extends FormattedDiskPage
// refer to the section on PAPX in the spec. Places a size on the front // 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 // of the PAPX. Has to do with how the grpprl stays on word
// boundaries. // boundaries.
int copyOffset = grpprlOffset; if (!same)
if ((grpprl.length % 2) > 0)
{ {
buf[copyOffset++] = (byte)((grpprl.length + 1)/2); 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;
} }
else
{
buf[++copyOffset] = (byte)((grpprl.length)/2);
copyOffset++;
}
System.arraycopy(grpprl, 0, buf, copyOffset, grpprl.length);
bxOffset += BX_SIZE; bxOffset += BX_SIZE;
fcOffset += FC_SIZE; fcOffset += FC_SIZE;
} }
// put the last papx's end in // put the last papx's end in
LittleEndian.putInt(buf, fcOffset, papx.getEnd() + fcMin); LittleEndian.putInt(buf, fcOffset, papx.getEnd() + fcMin);

View File

@ -146,38 +146,42 @@ public class StyleDescription implements HDFType
// the spec only refers to two possible upxs but it mentions // the spec only refers to two possible upxs but it mentions
// that more may be added in the future // that more may be added in the future
int add = 0; int varOffset = grupxStart;
int numUPX = _numUPX.getValue(_infoShort3); int numUPX = _numUPX.getValue(_infoShort3);
for(int x = 0; x < numUPX; x++) 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(_styleTypeCode.getValue(_infoShort2) == PARAGRAPH_STYLE)
{ {
if(x == 0) if(x == 0)
{ {
_istd = LittleEndian.getShort(std, grupxStart + add + 2); _istd = LittleEndian.getShort(std, varOffset);
varOffset += LittleEndian.SHORT_SIZE;
int grrprlSize = upxSize - 2; int grrprlSize = upxSize - 2;
_papx = new byte[upxSize]; _papx = new byte[grrprlSize];
System.arraycopy(std, grupxStart + add + 4, _papx, 0, grrprlSize); System.arraycopy(std, varOffset, _papx, 0, grrprlSize);
varOffset += grrprlSize;
} }
else if(x == 1) else if(x == 1)
{ {
_chpx = new byte[upxSize]; _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) else if(_styleTypeCode.getValue(_infoShort2) == CHARACTER_STYLE && x == 0)
{ {
_chpx = new byte[upxSize]; _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. // the upx will always start on a word boundary.
if(upxSize % 2 == 1) if(upxSize % 2 == 1)
{ {
++upxSize; ++varOffset;
} }
add += 2 + upxSize;
} }
@ -259,7 +263,7 @@ public class StyleDescription implements HDFType
//only worry about papx and chpx for upxs //only worry about papx and chpx for upxs
if(_styleTypeCode.getValue(_infoShort2) == PARAGRAPH_STYLE) 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; offset += LittleEndian.SHORT_SIZE;
LittleEndian.putShort(buf, offset, (short)_istd); LittleEndian.putShort(buf, offset, (short)_istd);
offset += LittleEndian.SHORT_SIZE; offset += LittleEndian.SHORT_SIZE;

View File

@ -161,7 +161,7 @@ public class StyleSheet implements HDFType
throws IOException throws IOException
{ {
int offset = 0; 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]; byte[] buf = new byte[_stshiLength + 2];
LittleEndian.putShort(buf, offset, (short)_stshiLength); LittleEndian.putShort(buf, offset, (short)_stshiLength);
offset += LittleEndian.SHORT_SIZE; offset += LittleEndian.SHORT_SIZE;

View File

@ -0,0 +1,75 @@
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();
}
}

View File

@ -0,0 +1,121 @@
/* ====================================================================
* 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();
}
}