From d2d927df6a756b95b95ec92ce47602397255c9dd Mon Sep 17 00:00:00 2001 From: Yegor Kozlov Date: Mon, 14 Mar 2011 09:10:12 +0000 Subject: [PATCH] support for getting HWPFDocument fields, see Bugzilla 50313 git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1081291 13f79535-47bb-0310-9956-ffa450edef68 --- src/documentation/content/xdocs/status.xml | 1 + .../src/org/apache/poi/hwpf/HWPFDocument.java | 21 +-- .../poi/hwpf/model/FieldDescriptor.java | 143 ++++++++++++++++-- .../apache/poi/hwpf/model/FieldsTables.java | 116 ++++++++++++++ .../poi/hwpf/model/FileInformationBlock.java | 66 ++++++++ .../apache/poi/hwpf/model/PlexOfField.java | 60 ++++++++ .../org/apache/poi/hwpf/AllHWPFTests.java | 1 + .../org/apache/poi/hwpf/HWPFDocFixture.java | 9 +- .../org/apache/poi/hwpf/HWPFTestCase.java | 7 +- .../org/apache/poi/hwpf/TestFieldsTables.java | 91 +++++++++++ .../poi/hwpf/model/TestCHPBinTable.java | 2 +- .../hwpf/model/TestDocumentProperties.java | 2 +- .../hwpf/model/TestFileInformationBlock.java | 2 +- .../apache/poi/hwpf/model/TestFontTable.java | 2 +- .../poi/hwpf/model/TestPAPBinTable.java | 2 +- .../apache/poi/hwpf/model/TestPlexOfCps.java | 2 +- .../poi/hwpf/model/TestSectionTable.java | 2 +- .../apache/poi/hwpf/model/TestStyleSheet.java | 2 +- .../poi/hwpf/model/TestTextPieceTable.java | 2 +- test-data/document/test-fields.doc | Bin 0 -> 30720 bytes 20 files changed, 501 insertions(+), 32 deletions(-) create mode 100644 src/scratchpad/src/org/apache/poi/hwpf/model/FieldsTables.java create mode 100644 src/scratchpad/src/org/apache/poi/hwpf/model/PlexOfField.java create mode 100644 src/scratchpad/testcases/org/apache/poi/hwpf/TestFieldsTables.java create mode 100644 test-data/document/test-fields.doc diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml index 67b632793f..ea0a8a14da 100644 --- a/src/documentation/content/xdocs/status.xml +++ b/src/documentation/content/xdocs/status.xml @@ -34,6 +34,7 @@ + 50313 - support for getting HWPFDocument fields 50912 - fixed setting named styles to HSSFCells 50779 - fixed RecordFormatException when reading unicode strings with photenic data 50718 - More helpful error message when you try to create a CellReference with #REF! diff --git a/src/scratchpad/src/org/apache/poi/hwpf/HWPFDocument.java b/src/scratchpad/src/org/apache/poi/hwpf/HWPFDocument.java index b64c796c4d..98fbfbe96d 100644 --- a/src/scratchpad/src/org/apache/poi/hwpf/HWPFDocument.java +++ b/src/scratchpad/src/org/apache/poi/hwpf/HWPFDocument.java @@ -32,12 +32,11 @@ import org.apache.poi.hwpf.model.ComplexFileTable; import org.apache.poi.hwpf.model.DocumentProperties; import org.apache.poi.hwpf.model.EscherRecordHolder; import org.apache.poi.hwpf.model.FSPATable; +import org.apache.poi.hwpf.model.FieldsTables; import org.apache.poi.hwpf.model.FontTable; -import org.apache.poi.hwpf.model.GenericPropertyNode; import org.apache.poi.hwpf.model.ListTables; import org.apache.poi.hwpf.model.PAPBinTable; import org.apache.poi.hwpf.model.PicturesTable; -import org.apache.poi.hwpf.model.PlexOfCps; import org.apache.poi.hwpf.model.PropertyNode; import org.apache.poi.hwpf.model.RevisionMarkAuthorTable; import org.apache.poi.hwpf.model.SavedByTable; @@ -100,6 +99,9 @@ public final class HWPFDocument extends HWPFDocumentCore /** Holds Office Art objects */ protected ShapesTable _officeArts; + + /** Holds the fields PLCFs */ + protected FieldsTables _fieldsTables; protected HWPFDocument() { @@ -264,13 +266,7 @@ public final class HWPFDocument extends HWPFDocumentCore _rmat = new RevisionMarkAuthorTable(_tableStream, rmarkOffset, rmarkLength); } - PlexOfCps plc = new PlexOfCps(_tableStream, _fib.getFcPlcffldMom(), _fib.getLcbPlcffldMom(), 2); - for (int x = 0; x < plc.length(); x++) - { - GenericPropertyNode node = plc.getProperty(x); - byte[] fld = node.getBytes(); - int breakpoint = 0; - } + _fieldsTables = new FieldsTables(_tableStream, _fib); } public TextPieceTable getTextTable() @@ -415,6 +411,13 @@ public final class HWPFDocument extends HWPFDocumentCore return _officeArts; } + /** + * @return FieldsTables object, that is able to extract fields descriptors from this document + */ + public FieldsTables getFieldsTables() { + return _fieldsTables; + } + /** * Writes out the word file that is represented by an instance of this class. * diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/FieldDescriptor.java b/src/scratchpad/src/org/apache/poi/hwpf/model/FieldDescriptor.java index 5bf14adf6b..4c0238f5dd 100644 --- a/src/scratchpad/src/org/apache/poi/hwpf/model/FieldDescriptor.java +++ b/src/scratchpad/src/org/apache/poi/hwpf/model/FieldDescriptor.java @@ -17,23 +17,146 @@ package org.apache.poi.hwpf.model; -import org.apache.poi.util.BitField; -import org.apache.poi.util.BitFieldFactory; +import java.text.MessageFormat; +import org.apache.poi.util.HexDump; + +/** + * Class for the FLD structure. + * + * @author Cedric Bosdonnat + * + */ public final class FieldDescriptor { + public static final int FIELD_BEGIN_MARK = 0x13; + public static final int FIELD_SEPARATOR_MARK = 0x14; + public static final int FIELD_END_MARK = 0x15; + + private static final short BOUNDARY_MASK = 0x1F; + private static final short TYPE_MASK = 0xFF; + private static final short ZOMBIE_EMBED_MASK = 0x02; + private static final short RESULT_DIRTY_MASK = 0x04; + private static final short RESULT_EDITED_MASK = 0x08; + private static final short LOCKED_MASK = 0x10; + private static final short PRIVATE_RESULT_MASK = 0x20; + private static final short NESTED_MASK = 0x40; + private static final short HAS_SEP_MASK = 0x80; + byte _fieldBoundaryType; byte _info; - private final static BitField fZombieEmbed = BitFieldFactory.getInstance(0x02); - private final static BitField fResultDiry = BitFieldFactory.getInstance(0x04); - private final static BitField fResultEdited = BitFieldFactory.getInstance(0x08); - private final static BitField fLocked = BitFieldFactory.getInstance(0x10); - private final static BitField fPrivateResult = BitFieldFactory.getInstance(0x20); - private final static BitField fNested = BitFieldFactory.getInstance(0x40); - private final static BitField fHasSep = BitFieldFactory.getInstance(0x80); + private int fieldType; + private boolean zombieEmbed; + private boolean resultDirty; + private boolean resultEdited; + private boolean locked; + private boolean privateResult; + private boolean nested; + private boolean hasSep; - public FieldDescriptor() + public FieldDescriptor(byte[] data) { + _fieldBoundaryType = (byte) (data[0] & BOUNDARY_MASK); + _info = data[1]; + + if (_fieldBoundaryType == FIELD_BEGIN_MARK) + { + fieldType = _info & TYPE_MASK; + } else if (_fieldBoundaryType == FIELD_END_MARK) + { + zombieEmbed = ((_info & ZOMBIE_EMBED_MASK) == 1); + resultDirty = ((_info & RESULT_DIRTY_MASK) == 1); + resultEdited = ((_info & RESULT_EDITED_MASK) == 1); + locked = ((_info & LOCKED_MASK) == 1); + privateResult = ((_info & PRIVATE_RESULT_MASK) == 1); + nested = ((_info & NESTED_MASK) == 1); + hasSep = ((_info & HAS_SEP_MASK) == 1); + } + } + + public int getBoundaryType() + { + return _fieldBoundaryType; + } + + public int getFieldType() + { + if (_fieldBoundaryType != FIELD_BEGIN_MARK) + throw new UnsupportedOperationException( + "This field is only defined for begin marks."); + return fieldType; + } + + public boolean isZombieEmbed() + { + if (_fieldBoundaryType != FIELD_END_MARK) + throw new UnsupportedOperationException( + "This field is only defined for end marks."); + return zombieEmbed; + } + + public boolean isResultDirty() + { + if (_fieldBoundaryType != FIELD_END_MARK) + throw new UnsupportedOperationException( + "This field is only defined for end marks."); + return resultDirty; + } + + public boolean isResultEdited() + { + if (_fieldBoundaryType != FIELD_END_MARK) + throw new UnsupportedOperationException( + "This field is only defined for end marks."); + return resultEdited; + } + + public boolean isLocked() + { + if (_fieldBoundaryType != FIELD_END_MARK) + throw new UnsupportedOperationException( + "This field is only defined for end marks."); + return locked; + } + + public boolean isPrivateResult() + { + if (_fieldBoundaryType != FIELD_END_MARK) + throw new UnsupportedOperationException( + "This field is only defined for end marks."); + return privateResult; + } + + public boolean isNested() + { + if (_fieldBoundaryType != FIELD_END_MARK) + throw new UnsupportedOperationException( + "This field is only defined for end marks."); + return nested; + } + + public boolean isHasSep() + { + if (_fieldBoundaryType != FIELD_END_MARK) + throw new UnsupportedOperationException( + "This field is only defined for end marks."); + return hasSep; + } + + public String toString() + { + String details = new String(); + if (_fieldBoundaryType == FIELD_BEGIN_MARK) + { + details = " type: " + fieldType; + } + else if (_fieldBoundaryType == FIELD_END_MARK) + { + details = " flags: 0x" + HexDump.toHex(_info); + } + + return MessageFormat.format("FLD - 0x{0}{1}", HexDump + .toHex((byte) _fieldBoundaryType), details); } } diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/FieldsTables.java b/src/scratchpad/src/org/apache/poi/hwpf/model/FieldsTables.java new file mode 100644 index 0000000000..826bc30a7d --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hwpf/model/FieldsTables.java @@ -0,0 +1,116 @@ +/* + * ==================================================================== + * 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.util.ArrayList; +import java.util.HashMap; + + +/** + * This class provides access to all the fields Plex. + * + * @author Cedric Bosdonnat + * + */ +public class FieldsTables +{ + public static final int PLCFFLDATN = 0; + public static final int PLCFFLDEDN = 1; + public static final int PLCFFLDFTN = 2; + public static final int PLCFFLDHDR = 3; + public static final int PLCFFLDHDRTXBX = 4; + public static final int PLCFFLDMOM = 5; + public static final int PLCFFLDTXBX = 6; + + // The size in bytes of the FLD data structure + private static final int FLD_SIZE = 2; + + private HashMap> _tables; + + public FieldsTables(byte[] tableStream, FileInformationBlock fib) + { + _tables = new HashMap>(); + + for (int i = PLCFFLDATN; i <= PLCFFLDTXBX; i++ ) + { + _tables.put(i, readPLCF(tableStream, fib, i)); + } + } + + public ArrayList getFieldsPLCF( int type ) + { + return _tables.get(type); + } + + private ArrayList readPLCF(byte[] tableStream, FileInformationBlock fib, int type) + { + int start = 0; + int length = 0; + + switch (type) + { + case PLCFFLDATN: + start = fib.getFcPlcffldAtn(); + length = fib.getLcbPlcffldAtn(); + break; + case PLCFFLDEDN: + start = fib.getFcPlcffldEdn(); + length = fib.getLcbPlcffldEdn(); + break; + case PLCFFLDFTN: + start = fib.getFcPlcffldFtn(); + length = fib.getLcbPlcffldFtn(); + break; + case PLCFFLDHDR: + start = fib.getFcPlcffldHdr(); + length = fib.getLcbPlcffldHdr(); + break; + case PLCFFLDHDRTXBX: + start = fib.getFcPlcffldHdrtxbx(); + length = fib.getLcbPlcffldHdrtxbx(); + break; + case PLCFFLDMOM: + start = fib.getFcPlcffldMom(); + length = fib.getLcbPlcffldMom(); + break; + case PLCFFLDTXBX: + start = fib.getFcPlcffldTxbx(); + length = fib.getLcbPlcffldTxbx(); + default: + break; + } + + ArrayList fields = new ArrayList(); + + if (start > 0 && length > 0) + { + PlexOfCps plcf = new PlexOfCps(tableStream, start, length, FLD_SIZE); + fields.ensureCapacity(plcf.length()); + + for ( int i = 0; i < plcf.length(); i ++ ) { + GenericPropertyNode propNode = plcf.getProperty( i ); + PlexOfField plex = new PlexOfField( propNode.getStart(), propNode.getEnd(), propNode.getBytes() ); + fields.add( plex ); + } + } + + return fields; + } +} 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 01ccec19b5..a726f0a7a7 100644 --- a/src/scratchpad/src/org/apache/poi/hwpf/model/FileInformationBlock.java +++ b/src/scratchpad/src/org/apache/poi/hwpf/model/FileInformationBlock.java @@ -66,7 +66,13 @@ public final class FileInformationBlock extends FIBAbstractType fieldSet.add(Integer.valueOf(FIBFieldHandler.PLCFSED)); fieldSet.add(Integer.valueOf(FIBFieldHandler.PLCFLST)); fieldSet.add(Integer.valueOf(FIBFieldHandler.PLFLFO)); + fieldSet.add(Integer.valueOf(FIBFieldHandler.PLCFFLDATN)); + fieldSet.add(Integer.valueOf(FIBFieldHandler.PLCFFLDEDN)); + fieldSet.add(Integer.valueOf(FIBFieldHandler.PLCFFLDFTN)); + fieldSet.add(Integer.valueOf(FIBFieldHandler.PLCFFLDHDR)); + fieldSet.add(Integer.valueOf(FIBFieldHandler.PLCFFLDHDRTXBX)); fieldSet.add(Integer.valueOf(FIBFieldHandler.PLCFFLDMOM)); + fieldSet.add(Integer.valueOf(FIBFieldHandler.PLCFFLDTXBX)); fieldSet.add(Integer.valueOf(FIBFieldHandler.STTBFFFN)); fieldSet.add(Integer.valueOf(FIBFieldHandler.STTBFRMARK)); fieldSet.add(Integer.valueOf(FIBFieldHandler.STTBSAVEDBY)); @@ -456,6 +462,56 @@ public final class FileInformationBlock extends FIBAbstractType _fieldHandler.clearFields(); } + public int getFcPlcffldAtn() + { + return _fieldHandler.getFieldOffset(FIBFieldHandler.PLCFFLDATN); + } + + public int getLcbPlcffldAtn() + { + return _fieldHandler.getFieldSize(FIBFieldHandler.PLCFFLDATN); + } + + public int getFcPlcffldEdn() + { + return _fieldHandler.getFieldOffset(FIBFieldHandler.PLCFFLDEDN); + } + + public int getLcbPlcffldEdn() + { + return _fieldHandler.getFieldSize(FIBFieldHandler.PLCFFLDEDN); + } + + public int getFcPlcffldFtn() + { + return _fieldHandler.getFieldOffset(FIBFieldHandler.PLCFFLDFTN); + } + + public int getLcbPlcffldFtn() + { + return _fieldHandler.getFieldSize(FIBFieldHandler.PLCFFLDFTN); + } + + public int getFcPlcffldHdr() + { + return _fieldHandler.getFieldOffset(FIBFieldHandler.PLCFFLDHDR); + } + + public int getLcbPlcffldHdr() + { + return _fieldHandler.getFieldSize(FIBFieldHandler.PLCFFLDHDR); + } + + public int getFcPlcffldHdrtxbx() + { + return _fieldHandler.getFieldOffset(FIBFieldHandler.PLCFFLDHDRTXBX); + } + + public int getLcbPlcffldHdrtxbx() + { + return _fieldHandler.getFieldSize(FIBFieldHandler.PLCFFLDHDRTXBX); + } + public int getFcPlcffldMom() { return _fieldHandler.getFieldOffset(FIBFieldHandler.PLCFFLDMOM); @@ -465,6 +521,16 @@ public final class FileInformationBlock extends FIBAbstractType { return _fieldHandler.getFieldSize(FIBFieldHandler.PLCFFLDMOM); } + + public int getFcPlcffldTxbx() + { + return _fieldHandler.getFieldOffset(FIBFieldHandler.PLCFFLDTXBX); + } + + public int getLcbPlcffldTxbx() + { + return _fieldHandler.getFieldSize(FIBFieldHandler.PLCFFLDTXBX); + } public int getFcPlcspaMom() { diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/PlexOfField.java b/src/scratchpad/src/org/apache/poi/hwpf/model/PlexOfField.java new file mode 100644 index 0000000000..d6596bb603 --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hwpf/model/PlexOfField.java @@ -0,0 +1,60 @@ +/* + * ==================================================================== + * 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.text.MessageFormat; + +/** + * Structure describing the Plex for fields (contained plclfd* in the spec). + * + * @author Cedric Bosdonnat + * + */ +public class PlexOfField +{ + private int fcStart; + private int fcEnd; + private FieldDescriptor fld; + + public PlexOfField( int fcStart, int fcEnd, byte[] data ) { + this.fcStart = fcStart; + this.fcEnd = fcEnd; + + fld = new FieldDescriptor( data ); + } + + public int getFcStart() { + return fcStart; + } + + public int getFcEnd() { + return fcEnd; + } + + public FieldDescriptor getFld() { + return fld; + } + + public String toString() { + return MessageFormat.format( "[{0}, {1}) - {2}", + fcStart, fcEnd, fld.toString() ); + + } +} diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/AllHWPFTests.java b/src/scratchpad/testcases/org/apache/poi/hwpf/AllHWPFTests.java index 6b4dd4514a..61346670a5 100644 --- a/src/scratchpad/testcases/org/apache/poi/hwpf/AllHWPFTests.java +++ b/src/scratchpad/testcases/org/apache/poi/hwpf/AllHWPFTests.java @@ -69,6 +69,7 @@ public final class AllHWPFTests { suite.addTestSuite(TestSectionTable.class); suite.addTestSuite(TestStyleSheet.class); suite.addTestSuite(TestTextPieceTable.class); + suite.addTestSuite(TestFieldsTables.class); suite.addTestSuite(TestBug46610.class); suite.addTestSuite(TestHeaderStories.class); diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/HWPFDocFixture.java b/src/scratchpad/testcases/org/apache/poi/hwpf/HWPFDocFixture.java index 1f7d4c6ff9..5afb0ee42a 100644 --- a/src/scratchpad/testcases/org/apache/poi/hwpf/HWPFDocFixture.java +++ b/src/scratchpad/testcases/org/apache/poi/hwpf/HWPFDocFixture.java @@ -25,13 +25,16 @@ import org.apache.poi.POIDataSamples; public final class HWPFDocFixture { + public static final String DEFAULT_TEST_FILE = "test.doc"; + public byte[] _tableStream; public byte[] _mainStream; public FileInformationBlock _fib; + private String _testFile; - public HWPFDocFixture(Object obj) + public HWPFDocFixture(Object obj, String testFile) { - + _testFile = testFile; } public void setUp() @@ -39,7 +42,7 @@ public final class HWPFDocFixture try { POIFSFileSystem filesystem = new POIFSFileSystem( - POIDataSamples.getDocumentInstance().openResourceAsStream("test.doc")); + POIDataSamples.getDocumentInstance().openResourceAsStream(_testFile)); DocumentEntry documentProps = (DocumentEntry) filesystem.getRoot().getEntry("WordDocument"); diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/HWPFTestCase.java b/src/scratchpad/testcases/org/apache/poi/hwpf/HWPFTestCase.java index 0f71e22ad7..76fab8a8cb 100644 --- a/src/scratchpad/testcases/org/apache/poi/hwpf/HWPFTestCase.java +++ b/src/scratchpad/testcases/org/apache/poi/hwpf/HWPFTestCase.java @@ -32,11 +32,16 @@ public abstract class HWPFTestCase extends TestCase { protected void setUp() throws Exception { super.setUp(); /** @todo verify the constructors */ - _hWPFDocFixture = new HWPFDocFixture(this); + _hWPFDocFixture = new HWPFDocFixture(this, getTestFile()); _hWPFDocFixture.setUp(); } + protected String getTestFile() + { + return HWPFDocFixture.DEFAULT_TEST_FILE; + } + protected void tearDown() throws Exception { if (_hWPFDocFixture != null) { _hWPFDocFixture.tearDown(); diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/TestFieldsTables.java b/src/scratchpad/testcases/org/apache/poi/hwpf/TestFieldsTables.java new file mode 100644 index 0000000000..d59b6f05b9 --- /dev/null +++ b/src/scratchpad/testcases/org/apache/poi/hwpf/TestFieldsTables.java @@ -0,0 +1,91 @@ +/* + * ==================================================================== + * 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; + +import java.util.ArrayList; + +import org.apache.poi.hwpf.model.FieldsTables; +import org.apache.poi.hwpf.model.FileInformationBlock; +import org.apache.poi.hwpf.model.PlexOfField; + +/** + * Test case for the fields tables, this test is based on the test-fields.doc file + * instead of the usual test.doc. + * + * @author Cedric Bosdonnat + * + */ +public class TestFieldsTables extends HWPFTestCase +{ + private static final int ALL_TYPES[] = { + FieldsTables.PLCFFLDATN, + FieldsTables.PLCFFLDEDN, + FieldsTables.PLCFFLDFTN, + FieldsTables.PLCFFLDHDR, + FieldsTables.PLCFFLDHDRTXBX, + FieldsTables.PLCFFLDMOM, + FieldsTables.PLCFFLDTXBX + }; + + private static final String EXPECTED[] = { + "[19, 43) - FLD - 0x13 type: 31\n[43, 54) - FLD - 0x14\n[54, 59) - FLD - 0x15 flags: 0x81\n", + "[31, 59) - FLD - 0x13 type: 69\n[59, 61) - FLD - 0x14\n[61, 66) - FLD - 0x15 flags: 0x80\n", + "[23, 49) - FLD - 0x13 type: 17\n[49, 64) - FLD - 0x14\n[64, 69) - FLD - 0x15 flags: 0x80\n", + "[18, 42) - FLD - 0x13 type: 33\n[42, 44) - FLD - 0x14\n[44, 47) - FLD - 0x15 flags: 0x81\n" + + "[47, 75) - FLD - 0x13 type: 29\n[75, 85) - FLD - 0x14\n[85, 91) - FLD - 0x15 flags: 0x81\n", + "[30, 54) - FLD - 0x13 type: 32\n[54, 62) - FLD - 0x14\n[62, 68) - FLD - 0x15 flags: 0x81\n", + "[1, 31) - FLD - 0x13 type: 21\n[31, 51) - FLD - 0x14\n[51, 541) - FLD - 0x15 flags: 0x81\n", + "[19, 47) - FLD - 0x13 type: 25\n[47, 49) - FLD - 0x14\n[49, 55) - FLD - 0x15 flags: 0x81\n" + }; + + public TestFieldsTables() + { + } + + protected String getTestFile() + { + return "test-fields.doc"; + } + + public void testReadFields() + { + FileInformationBlock fib = _hWPFDocFixture._fib; + byte[] tableStream = _hWPFDocFixture._tableStream; + + FieldsTables fieldsTables = new FieldsTables(tableStream, fib); + + for (int i = 0; i < ALL_TYPES.length; i++) + { + ArrayList fieldsPlexes = fieldsTables.getFieldsPLCF( ALL_TYPES[i] ); + String result = dumpPlexes(fieldsPlexes); + assertEquals(EXPECTED[i], result); + } + } + + private String dumpPlexes(ArrayList fieldsPlexes) + { + String dump = new String(); + for ( int i=0; iNZiQ3UKI4luwNU~m{)6veI>BWg5ij0H=K zijvqh7Sy1|h865sutgJ$MllxNf1R0w145#H_q}(&duQ|epSA1SYp-3-KI`l=6rM6K zS@A=I8?2i9gz2z16^2YtBVGVMfpcbz3E`pen~I7GRU~8ZYTf@L4ZMb|9_l_6f$9R( z=lXyFU_6jR6zD6u=N*=70rY30MKvfDJ(TZ9(e;4S==>Tp!e^VDYF+&f?f`)FNf6sO^1S1FS++Bk?3T-ltq$Wb&dx z3g^LMn1sc$WYqgH&IGkny)2{_ zWv%h*sIH&p?)%o?ia4qDPkqMgkLE~C^Pl2LXWBVL8vf66?PL9-<--+m(sXgOG+7#_ zl*UIZM<+`=*bnR?Pgi!Aq)1)+Mt8FpbFmccVBe)jbd1nQzYrG@-%5G(h}r~6p0c+MWUNLAwd==4VK3ZPm!i7-P*Xjd%MNT zVv}X^M1>?RX|$Tzzl4>4d$-Ew`O~0(*R>CTeBu#OMY>F$+QHt#)!kk!O^uVs%Tg0N z*!PO*?BZiDPFG4&<0Z-RR5U(SZXe)pT&I0}x?j9RDM?q#71A)JG)0UE8E9B=2m3K? zJl)+pcMkD!>FgQO$;HDXxHB%k!7lFZZM-}Bw)6G%XzQK9t1UkLV;dVc9Mz}vO-Z)* zCwWv_kCG;&R}GSA!xgfRt))uuxIw4Ys-kceRn(&Dca@JA0ag_qY%pk6RnI_sfCyQf zLY^*9P>OqS14rCPu80@=wsXP2@f7pJh})t>L{l1~I6hB(e;ihwp*F15fK~%q4QMq` zsR08^ai^$|pqP+gKr9vybP`8|M0E-2+#@O?C`N4M;p^t%fxEPayV%3a&&$`(-QC(a zRH~4QW$9vxI9ZnZnOG?oOHy&yj8By-rNWw0#R+n`l1mjEN6WEokfb6cQR1GL+lp048M2GdSNdl<*ZN*CID5W@7K8nhO1c$}Mgw-f@ z8lsvP8>ZUM5TN3Q!8?f|3QAcl;A&KH|w~ zQXhn0Af7DJ)-X|1IX?Xy%+niT7HfrgG7<)Wk|jD(9nMhG^PuFK5|bKeH29EZtrsY{ z_n~9~pD1Q52L&CPG1w&;8;$a0Rj=;4LVjXR^^*m@y1NRKyFDT+)YKFCNKXNvWZ5Ua znr^;YzsuD6ou_UmpNHCO0J*+IIns-cx_ouo1^g!>eLeV)p1)V~d8rQXQ-?`EnvUnA z8TUSZUjP5ZkLQ02azJ&=6BnW%>v(?D9&-G6WAiTEE}wRc46B^u$JJ5jAsc%og-0K>bYpN&QIu z$M?^9_^E%20qUR20QJu`fci&(!$Cs831|&C1Mz?qSOu&Gih+y3Yt3#d*9=rid7_!} zSTj&1+ui?1DW$d6bF0>rDuUjqHQV)CQ!dq-!Y5!~l^D+r6#*V*1bDy`;2f3!PuI}2 zMSL0Fs#>jjo2Lnm?NEptl$?(nZuEpwpZc)`CRKGuQ1G0+5X1X=-_ z{qB!&01ycD0r~>5Kpeo2i3Io)fyuxWU^%b?$N^RY{FvDR|4!f>a2~h-6aoBLx?g&= z^y;~*rG+4eK@RTQn!7J|Rqnoni%aKDojY~R)U< z#?>^3&25rMz5Eoz)T*496t6k+DO_!(;8!Scp}IA=Amv=$6r8i;*B#Ybpvhk?Ex&qH z&i^asZ_w`6V}GaGYnlJfG&e5+4X}%E2-pE+_o*_9YoD)GvQ?S9{8-h}e+LazoBuQ@ zut?xxjqm?*jDZ(`8T#HFum$P^nq%Tsd0Bbc-LmpqRo1S5hvxma%78h~E$XyNn5A*6 zgk7_Gn(Ig9Dx_Wqkdy0tDuH#SP8;Ttoh0x}qYX!syos*jyn>*ndCPU}fo9pubsd1_ zd5qP|D-_xSM%jh10czcUiUv|e_OS8^SY7NM^l^$-1PF1Z+y6pf=|8|*59h7_0V6PC z{t315@JHF&(*AG6uSI)#zGUU*{k72@?~$i^*(9vIp+NQc|Hg2hj!F-0FotZQ%l!x! z0wq8hKs#46Kn%D8fj}fM1V{rifo!0*a>UmWW2hMVz6Xer_hb0{x0myQ?)n1d0KEmW z1$qPH00(qak8m9p87^WyK?jEm*{7k#c-}NLNDVcoM`{BlD6+Bc=(@)hLQo?!#<<5^ zriT!H1wbd>laYtsQdz`X3Fs;22;R|k3b*0-NkD7jNqpbBU=}pwkBSxeqQFRffW-{& ztLO`d1n?h@8k9`TBH>p6iQF}fB_Xaech+9Xv5LaU`zIBf@fCzoBNcCVJtK{81;o{4 zwqy04VYqr-&|`u+I>{=JE@C7UEo5|l-jRJKep-=FZxhv$x$Eh3e8j99>PzRodk}K% zXUv~92^6qDK#h#e7;W<1_4HUM+9ARB5>m*GyE4ARF)lD*!WHHnn+b$(AN`Q#%HEjf zFoD388DVW#m9JZ+ycln5lQ=z43;mfG^;rn0K8wowNGEd0#n)&45A`+W>NBsbPqTd0 z`nt14Ou*U*FcOTd)cK9@o|wi!GFNLV`XmN5kK*)Vgl~-AHqZ>C!VIHM7b8xWN#GCX z+8ZPYM|&;R{LE|Rrzy+3yd2OU0`!^#WV2E85@8I{7a3CMO31yDb>eE22%J!(wK|t! zWiHJc7{*p>XjdWV434&ytqsAq9r1ul!&O^bPouR4Xss1mX@&MsuTBtjM4k02TUi?) zO&Q+u@MlheIcyHs)2vn=QD|ub*YEU2P8`>69Tw^&fDA2Beg(;Zam+o=>X~CK$uWcZ z?{~zQIq#My8O*reYR?)&A3qA(gNL1(htWGc-uAu_Uy!|Rfgh)Ze1RXd(6Cks_|lqM zz#W7QWj_dh6a=E?#_F=B@6=3R<-{VV6fLI}L5MHc^k6BQFwkH^XViW`aD)0%&`8a} z>K{00%0PSs0}Y`6M$o|@TtA2zXC%}!=2jsZ4>gSnA-gT5IPhzQJ1&) zoAR16kRDo~7tMvF2dwL4qSULYbWQ!J8V8YGbwpOs3hfn}vWZzgS<)d9JKPcIYrp}W zXv^(1z zfBWLkL!nC^A1WOF!l`a>(elqH9dUEdI-Iw>?Bxq1hs=d_`>sFiDe0ec#_T|eb6&8! z{?KvvJg;v%8GGx|I4ha|q zWHjyfDSIZJ&ggmOpl$OJZmY99xvk7#Hyp<&**Co0@Yl;d4(rv~Z7_M&@6W&Q@Mh!8 z7dO7TE4Ep@PVeB&P65Y~Zj9)#Z~VlgQ&xS~++e_{w5cn{T;BTWPm!lrwm;#~aCPW5 z_xTp4(=Yb;DQaWK_|r$t&V+|t_KI~F|J|HnpB6P)xU_zWcek^D+C&w#8?tfs+M^Yl z54s;;+9QAbCg;)+QEI!dy2)XmA)EkEnA{Y!-MUW5vkqi|yieJBGymcx>bDXROnb20@3H zpILUfsPxvPb|w(6Ry*@myLD)uHo8Cp>{tzC*L@1edqot+oM}% zSzZr2lHN0;+4<}#xm&M_FKlgnzUlAIR|oHO7}{ZGmp=E-K5un1Ii*m7Jk9j z+?xxqeT;;Cl^z8x%IgT#K=uZR4yx79w=;*mHA9oKS11O4Gy#Xo%G64CHb>a@nP z84HRda{|wVWi-5WD^qZAmt>lCamqBwfC)Cmt6zFu^h<73xGAqo)ZCx@4xZ~>oR#bE zVDaMC%ZkQLzF%MT+hL`=Vi&XMPo4^!0*OrU&~DzSAmfNb2#BFRXvcN^50SZg8(4 zS+=wHfI(Rv5$(S!u|0CF!R+sQ6h_W_>aDohL2uKHxu5S(j9ngPnK&h1Pk;EV?C6V9 zVWZd!&oX=LpFQ>V-apI^M&$=zUcYGB_ASGP8*WORxv+oUwk;dw<1X$>4ob^Q9+j0A z?W#An@6+r6aaq*wA+1 z*coqrS#mtL`*&xPr9bw~(Ti`=Fui>1rJ-@@7xNot|J?3w*{qWZ+jl=GF+Os$&)u@u zt#i*$o!M^r^wYP8nB+FP^n2pDx#lNFe>xQUtRx`+sAe`JyAF8)54godrYH^>U*qw{@}&) zO-lnp4x27*6i|M@{Kmms`T_kro?Mr*WO8XQw|%c4o;uuQWx&#LPyRSv@BFBK1r>iC zY`O2%tI=)E&Lp-tIn!;~t7i|7&fMhx`t|NE)@2bBx=72j3xadLxoz<1iLI4q?_teb zHXF9r`k=wtKeA3ZeC3nBxU25#rCD}QPqa!{G}6x3@6gtgMuO6nbw*_~UlYRqZ`b)YzaauImC+xt`JF!s(kK)Gm{dxCH%ftKjgw+}DY1*~RUD?z8^P=QHhgg&wJM+-Y(Xi#rP+`z>{}>odph=EC{L<8;=q4L_0}Q!X9Y z!>LReYTIQ`W@x{ycNVaWuHCQaNB-b+b?>n?Kg_hsY8-R=rwP7p&9;{ZwL37Z|CC0B z4o-0a+4^QVwvUGO(!E}qI`!VjGM(-=yIz_!|8jSaO?um9_ojQ*HS6GMe(CGTb>G&p zJA3>0Up!Vu&Q38JIM8>hu>9t)hpp%Qxy|NgMDe_JZ6q&)UksZ3Nk8T8fug66HtifR zYVJdGgC{R$-5qo^qmN=w#n_{RzB-lYvSst7I?_JRjkmS(c2WG4*Qs%If!@$xju^`p z#~Z#3E}Ry$=j0NTuwk*`%|;!6uxnCXUGLAbOCB^^mlHHOIw|khr7bLe`9kT~^Oxp! z509rcPnk8X#h{CElISM3$sMx$KKf(7$)#I zDw6ar>iF%V0avFdgnxT5H?sa%pG^&nY%WaJ69rus_8vUt$<730eaqva%O9mazjno? zpl-eU_VsUM#`~Z7{M5^}sY|{(oVC+1v-tb6IsUi5jooUoeL;(tdRI=~T-9cGfpEmm z=hqH(9W6Tb)2b)Wg8hD6wPcBNP?wZV=Le>Ke&n$1a>Ij*Y#QIP`pI?pscHQT>UG*{ z;r*~jM8dpMPx&^*&sQAQ9&9^h>&qnvx;F})5;LH0XK%0LF*ZWy(@QqIIu_ynYe=gh z&0e=%)wkcIA>~D@*eAO-HoxWZxYxyttIbnBdAWFglz-1)qnr|hS;fH*{K{z-dP}?+RVta}_Bk`!#5hdt?81&t%g@Q(lLLOw8`!*tNx9-JAA4^~|;FT=lCy=kpScBZDDL&>^UdwAk2#igZ$`gw&L7z@ZEAJEcYFT< zKiu&eoO$-UrIa5*LK=#y45;=nqGv_0ll2R=BBjI zcFi77d&X(}@S7{gl-zUKaebM4^9c9+cFiZO_|tA-`^?+h z?M|GTMMrqw-ESD5&R(_+DGhOxrjIH$?_{dI2N$DpGgj|KBI+D)x0?KX;z$Fz{Om5X zIW4YEFU&osGx>H~WA6Zmo(~@xZ*(?rohI44NVfayZ;x8WwYlbzw61}H-~IW+7U!qz zc=%;tluh>;7e9&58#3`rdAmo}iF3L-MznBbteKrCURv8hf|u1*`9V z-WIgN9$B*!s;j>`r|Mggx13Jb#EILOROeBB5WMB_4c_}`O7k~EBC@M4c0_c@PnQis z>lfe^5srs`=ttC}rRl1#s3m@J$%+U`n)(ZJ$@_ex9Iud!#0O(3$*PaXQzWufdvR={ zM+f_4rH8#(ISRh`&)|zqY(sHvC=R~(&)}29#o?I*In*9L2I;Dp$~>NYj3=MRi;wZ* zW7_gDZTT2)KE~T#oJ3#8p+!XO@d;dVs49Z@*}M76p}j`vLZ}k1BM<`g1m4C5s8c|= zpE!A&LNRolRLGgucrJV_QQmpM(~b|I4DSts=UsjRdZL3QpckO@!kfxdv$+AS5wDLp;z_z_ z0(b%>gQfMkiun`hfV30f3{Xv7fnEUBVA<3PIV>B|6~{F2QzP`yt?FS*b7jT+OnOXi z4R{08KFcPEoj|ovr~}ZEVnd#)^HL4Og?iGm{yF5Ov*J|RAE5rQgn@DX1XI|~0}(>2 z%EY(|p$O6u4HJmYfx^@#3J0>rk712f_hSXi%*QYz=g|09sNpwEV?BJXa1AX~nYn3(&{!oImO?lX?gNC)l{qS)9TY_tnxC`|WFat@ zV&G_2^Zso3&#G}AlyE_fV$h4gW#9^M4Y&@_9n=|+0%^cVU^Q?FXpDyI<4?qaUP|(Q z6%}%+cHC7pE=Yniz=ujvf-<)OO=%J#!Kinnc`L)a@_0fLl}zNLKXN3~Y2ah!Dn(gd zt~kg;np&xrs|b`dRUevCX-ii_OYcgk%SlLAP0+BX*+G3zwUHw~ot~uA1Y{Z{BQL!| zpfdw>(tuvvaOVh+k6Or&0SLn?0$CM$*)X*9b6X#t{w`dC6! z@oQ9M0Ue1e#gah0Q{_@ESM=*k6i-*)Pm1qiL#u{RsHdYV(iQ56ra3V&qBD6uTt$e8 z!3~RS*6B#@4muJvinC-(P&3X(3W<-du0SZz*AwdM)3T}QkjS}c{B~0cZgg_)4VGsM zuJ*cmA|bh2YY*aXm8!R1?Nkz*>QVt6q3CxZTRuiiT2Z-WYT5}m(_}~;%auh-+hz+g z>!78EBB8E%=U95d#TxDn%-JIp%=ThNWA!a5CjS|t)N|~WD z5m$d^e~tR-7DkSKFN;dk+d6CnR8os{QAkfM^{-;?zQyI%l$!KI8w3d_2fa&4LLPez zJ`aO0Y*`tdETMPfjQxOZK$&_gpvOJ3SR-}}pc+azr9cYizL&CwM-_|WoNKDXxVsU@ zN*$*q@2i33y32L9uq|xD1Pk}7Wo9E7{6ADG-$!88W|BGelY#gZ*m@@2)tX4n_@+U1s_z?zu)Tq zeQGsU|DS_zux?^;dq)cDk&-FP{&>+N$!t9i^tW!g`63O6u}ClnrSxooN-hLwU0el_ zg7W~VjU53lS=?vf1d($(=h@Q(yT2gZ83a6X+uI|j9!pOf?~_Y27+Qs%i=-J zK$Agf>#PK&`e{tio{sO_>V7Iy^;bgvK0nFOoqn<`*)?9SOyPL{9S_=oQ=PUzjlWlg z_&|WI+ovGCaDLZglgsdxDCdtnet^Ch<+tQSX}u##YaUUp(`rDg0j&nK8qjJ$s{ySB zv>MQAK&t_*2DBQ`YT$pO0bRT{s`|_OANG6nK6nC$EvC}Fk1U*Rh90QlB4BxyLk6-2 zN?@U+|3ILC9rk@)16U%+mOui$wc`AJY5E;|KF1||32+6kGsEyo;w=7(V5|>;1^6&t z!UnMdb`mcQ3lQ$j_Tz;dy^^cy+Ms^E@nqw8AE#M=7+NfaE%jqv9ku?+u0nFWFP{hM zjDKhU5uQJBeu-;Cvw2^`{^R^&qdUrw?S||lFuicrTe8cf0c6*h4p1Lt17ss2yAWB8 zmjiUnbuB>Mo(GWqW(Qyc><7r+a|9sX^x{aCj&}u-d0j&nK z8qjJ$s{ySBv>MQAK&yfO-5Q95wT1rYBYodb|80;?!hMLd`3U