aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSergey Vladimirov <sergey@apache.org>2012-11-06 16:26:43 +0000
committerSergey Vladimirov <sergey@apache.org>2012-11-06 16:26:43 +0000
commite9b4aa87f0a5492ae5b0a66f5cc96ba394a36a3e (patch)
treeb1815daf9b7a2cfa5775f6a6037aeee8e546b116
parent932099875b755338cd832bbb6a1e07a4839a019e (diff)
downloadpoi-e9b4aa87f0a5492ae5b0a66f5cc96ba394a36a3e.tar.gz
poi-e9b4aa87f0a5492ae5b0a66f5cc96ba394a36a3e.zip
Bug 52583 - Conversion to html : Problem with combobox
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1406208 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--src/documentation/content/xdocs/status.xml1
-rw-r--r--src/scratchpad/src/org/apache/poi/hwpf/converter/AbstractWordConverter.java35
-rw-r--r--src/scratchpad/src/org/apache/poi/hwpf/converter/HtmlDocumentFacade.java17
-rw-r--r--src/scratchpad/src/org/apache/poi/hwpf/converter/WordToHtmlConverter.java14
-rw-r--r--src/scratchpad/src/org/apache/poi/hwpf/model/FFData.java214
-rw-r--r--src/scratchpad/src/org/apache/poi/hwpf/model/FFDataBase.java33
-rw-r--r--src/scratchpad/src/org/apache/poi/hwpf/model/FIBFieldHandler.java3
-rw-r--r--src/scratchpad/src/org/apache/poi/hwpf/model/NilPICFAndBinData.java59
-rw-r--r--src/scratchpad/src/org/apache/poi/hwpf/model/Sttb.java232
-rw-r--r--src/scratchpad/src/org/apache/poi/hwpf/model/SttbUtils.java155
-rw-r--r--src/scratchpad/src/org/apache/poi/hwpf/model/Xstz.java69
-rw-r--r--src/scratchpad/src/org/apache/poi/hwpf/model/types/FFDataBaseAbstractType.java428
-rw-r--r--src/scratchpad/src/org/apache/poi/hwpf/sprm/CharacterSprmUncompressor.java13
-rw-r--r--src/scratchpad/src/org/apache/poi/hwpf/usermodel/CharacterRun.java41
-rw-r--r--src/scratchpad/testcases/org/apache/poi/hwpf/converter/TestWordToHtmlConverter.java8
-rw-r--r--src/types/definitions/FFData_type.xml81
-rw-r--r--src/types/styles/hdftype.xsl67
-rw-r--r--test-data/document/Bug52583.docbin0 -> 26112 bytes
18 files changed, 1290 insertions, 180 deletions
diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml
index ad3b0f62b9..f297c50612 100644
--- a/src/documentation/content/xdocs/status.xml
+++ b/src/documentation/content/xdocs/status.xml
@@ -34,6 +34,7 @@
<changes>
<release version="3.9-beta1" date="2012-??-??">
+ <action dev="poi-developers" type="add">52583 - add support for drop-down lists in doc to html convertion</action>
<action dev="poi-developers" type="add">52863 - add workaround for files with broken CHP SPRMs</action>
<action dev="poi-developers" type="fix">53182 - Reading combined character styling and direct formatting of a character run</action>
<action dev="poi-developers" type="fix">52311 - Conversion to html : Problem in titles number </action>
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/converter/AbstractWordConverter.java b/src/scratchpad/src/org/apache/poi/hwpf/converter/AbstractWordConverter.java
index 64a1900abe..95da850200 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/converter/AbstractWordConverter.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/converter/AbstractWordConverter.java
@@ -167,6 +167,7 @@ public abstract class AbstractWordConverter
}
structures.add( structure );
}
+
private final Set<Bookmark> bookmarkStack = new LinkedHashSet<Bookmark>();
private FontReplacer fontReplacer = new DefaultFontReplacer();
@@ -778,6 +779,12 @@ public abstract class AbstractWordConverter
CharacterRun characterRun, OfficeDrawing officeDrawing,
String path, Element block );
+ protected void processDropDownList( Element block,
+ CharacterRun characterRun, String[] values, int defaultIndex )
+ {
+ outputCharacters( block, characterRun, values[defaultIndex] );
+ }
+
protected abstract void processEndnoteAutonumbered(
HWPFDocument wordDocument, int noteIndex, Element block,
Range endnoteTextRange );
@@ -835,6 +842,22 @@ public abstract class AbstractWordConverter
break;
}
+ case 83: // drop down
+ {
+ Range fieldContent = field.firstSubrange( parentRange );
+ CharacterRun cr = fieldContent.getCharacterRun( fieldContent
+ .numCharacterRuns() - 1 );
+ String[] values = cr.getDropDownListValues();
+ Integer defIndex = cr.getDropDownListDefaultItemIndex();
+
+ if ( values != null )
+ {
+ processDropDownList( currentBlock, cr, values,
+ defIndex == null ? -1 : defIndex.intValue() );
+ return;
+ }
+ break;
+ }
case 88: // hyperlink
{
final Range firstSubrange = field.firstSubrange( parentRange );
@@ -1010,12 +1033,6 @@ public abstract class AbstractWordConverter
return false;
}
}
-
- protected void processSymbol( HWPFDocument doc, CharacterRun characterRun,
- Element block )
- {
-
- }
@SuppressWarnings( "unused" )
protected boolean processOle2( HWPFDocument wordDocument, Element block,
@@ -1109,6 +1126,12 @@ public abstract class AbstractWordConverter
processSection( wordDocument, section, 0 );
}
+ protected void processSymbol( HWPFDocument doc, CharacterRun characterRun,
+ Element block )
+ {
+
+ }
+
protected abstract void processTable( HWPFDocumentCore wordDocument,
Element flow, Table table );
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/converter/HtmlDocumentFacade.java b/src/scratchpad/src/org/apache/poi/hwpf/converter/HtmlDocumentFacade.java
index b405b2cb6a..67f6ea1cd8 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/converter/HtmlDocumentFacade.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/converter/HtmlDocumentFacade.java
@@ -161,11 +161,28 @@ public class HtmlDocumentFacade
return document.createElement( "li" );
}
+ public Element createOption( String value, boolean selected )
+ {
+ Element result = document.createElement( "option" );
+ result.appendChild( createText( value ) );
+ if ( selected )
+ {
+ result.setAttribute( "selected", "selected" );
+ }
+ return result;
+ }
+
public Element createParagraph()
{
return document.createElement( "p" );
}
+ public Element createSelect()
+ {
+ Element result = document.createElement( "select" );
+ return result;
+ }
+
public Element createTable()
{
return document.createElement( "table" );
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/converter/WordToHtmlConverter.java b/src/scratchpad/src/org/apache/poi/hwpf/converter/WordToHtmlConverter.java
index 3092625e8c..d5314c9e7b 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/converter/WordToHtmlConverter.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/converter/WordToHtmlConverter.java
@@ -82,6 +82,7 @@ public class WordToHtmlConverter extends AbstractWordConverter
private static final POILogger logger = POILogFactory
.getLogger( WordToHtmlConverter.class );
+
private static String getSectionStyle( Section section )
{
float leftMargin = section.getMarginLeft() / TWIPS_PER_INCH;
@@ -281,6 +282,19 @@ public class WordToHtmlConverter extends AbstractWordConverter
}
@Override
+ protected void processDropDownList( Element block,
+ CharacterRun characterRun, String[] values, int defaultIndex )
+ {
+ Element select = htmlDocumentFacade.createSelect();
+ for ( int i = 0; i < values.length; i++ )
+ {
+ select.appendChild( htmlDocumentFacade.createOption( values[i],
+ defaultIndex == i ) );
+ }
+ block.appendChild( select );
+ }
+
+ @Override
protected void processDrawnObject( HWPFDocument doc,
CharacterRun characterRun, OfficeDrawing officeDrawing,
String path, Element block )
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/FFData.java b/src/scratchpad/src/org/apache/poi/hwpf/model/FFData.java
new file mode 100644
index 0000000000..7ea4b79384
--- /dev/null
+++ b/src/scratchpad/src/org/apache/poi/hwpf/model/FFData.java
@@ -0,0 +1,214 @@
+package org.apache.poi.hwpf.model;
+
+import org.apache.poi.util.Internal;
+import org.apache.poi.util.LittleEndian;
+
+/**
+ * The FFData structure specifies form field data for a text box, check box, or
+ * drop-down list box.
+ * <p>
+ * Class and fields descriptions are quoted from [MS-DOC] -- v20121003 Word
+ * (.doc) Binary File Format; Copyright (c) 2012 Microsoft Corporation; Release:
+ * October 8, 2012
+ * <p>
+ * This class is internal. It content or properties may change without notice
+ * due to changes in our knowledge of internal Microsoft Word binary structures.
+ *
+ * @author Sergey Vladimirov; according to [MS-DOC] -- v20121003 Word (.doc)
+ * Binary File Format; Copyright (c) 2012 Microsoft Corporation;
+ * Release: October 8, 2012
+ */
+@Internal
+public class FFData
+{
+ private FFDataBase _base;
+
+ /**
+ * An optional STTB that specifies the entries in the dropdown list box.
+ * This MUST exist if and only if bits.iType is iTypeDrop (2). The entries
+ * are Unicode strings and do not have extra data. This MUST NOT exceed 25
+ * elements.
+ */
+ private Sttb _hsttbDropList;
+
+ /**
+ * An optional unsigned integer that specifies the default state of the
+ * checkbox or dropdown list box. This value MUST exist if and only if
+ * bits.iType is iTypeChck (1) or iTypeDrop (2). If bits.iType is iTypeChck
+ * (1), wDef MUST be 0 or 1 and specify the default state of the checkbox as
+ * unchecked or checked, respectively. If bits.iType is iTypeDrop (2), wDef
+ * MUST be less than the number of items in the dropdown list box and
+ * specify the default item selected (zero-based index).
+ */
+ private Integer _wDef;
+
+ private Xstz _xstzEntryMcr;
+
+ private Xstz _xstzExitMcr;
+
+ private Xstz _xstzHelpText;
+
+ /**
+ * An Xstz that specifies the name of this form field. xstzName.cch MUST NOT
+ * exceed 20.
+ */
+ private Xstz _xstzName;
+
+ private Xstz _xstzStatText;
+
+ /**
+ * An optional Xstz that specifies the default text of this textbox. This
+ * structure MUST exist if and only if bits.iType is iTypeTxt (0).
+ * xstzTextDef.cch MUST NOT exceed 255. If bits.iTypeTxt is either
+ * iTypeTxtCurDate (3) or iTypeTxtCurTime (4), xstzTextDef MUST be an empty
+ * string. If bits.iTypeTxt is iTypeTxtCalc (5), xstzTextDef specifies an
+ * expression to calculate.
+ */
+ private Xstz _xstzTextDef;
+
+ private Xstz _xstzTextFormat;
+
+ public FFData( byte[] std, int offset )
+ {
+ fillFields( std, offset );
+ }
+
+ public void fillFields( final byte[] std, final int startOffset )
+ {
+ int offset = startOffset;
+
+ this._base = new FFDataBase( std, offset );
+ offset += FFDataBase.getSize();
+
+ this._xstzName = new Xstz( std, offset );
+ offset += this._xstzName.getSize();
+
+ if ( _base.getIType() == FFDataBase.ITYPE_TEXT )
+ {
+ _xstzTextDef = new Xstz( std, offset );
+ offset += this._xstzTextDef.getSize();
+ }
+ else
+ {
+ this._xstzTextDef = null;
+ }
+
+ if ( _base.getIType() == FFDataBase.ITYPE_CHCK
+ || _base.getIType() == FFDataBase.ITYPE_DROP )
+ {
+ this._wDef = Integer
+ .valueOf( LittleEndian.getUShort( std, offset ) );
+ offset += LittleEndian.SHORT_SIZE;
+ }
+ else
+ {
+ this._wDef = null;
+ }
+
+ _xstzTextFormat = new Xstz( std, offset );
+ offset += this._xstzTextFormat.getSize();
+
+ _xstzHelpText = new Xstz( std, offset );
+ offset += this._xstzHelpText.getSize();
+
+ _xstzStatText = new Xstz( std, offset );
+ offset += this._xstzStatText.getSize();
+
+ _xstzEntryMcr = new Xstz( std, offset );
+ offset += this._xstzEntryMcr.getSize();
+
+ _xstzExitMcr = new Xstz( std, offset );
+ offset += this._xstzExitMcr.getSize();
+
+ if ( _base.getIType() == FFDataBase.ITYPE_DROP )
+ {
+ _hsttbDropList = new Sttb( std, offset );
+ offset += _hsttbDropList.getSize();
+ }
+ }
+
+ /**
+ * specify the default item selected (zero-based index).
+ */
+ public int getDefaultDropDownItemIndex()
+ {
+ return _wDef.intValue();
+ }
+
+ public String[] getDropList()
+ {
+ return _hsttbDropList.getData();
+ }
+
+ public int getSize()
+ {
+ int size = FFDataBase.getSize();
+
+ size += _xstzName.getSize();
+
+ if ( _base.getIType() == FFDataBase.ITYPE_TEXT )
+ {
+ size += _xstzTextDef.getSize();
+ }
+
+ if ( _base.getIType() == FFDataBase.ITYPE_CHCK
+ || _base.getIType() == FFDataBase.ITYPE_DROP )
+ {
+ size += LittleEndian.SHORT_SIZE;
+ }
+
+ size += _xstzTextFormat.getSize();
+ size += _xstzHelpText.getSize();
+ size += _xstzStatText.getSize();
+ size += _xstzEntryMcr.getSize();
+ size += _xstzExitMcr.getSize();
+
+ if ( _base.getIType() == FFDataBase.ITYPE_DROP )
+ {
+ size += _hsttbDropList.getSize();
+ }
+
+ return size;
+ }
+
+ public String getTextDef()
+ {
+ return _xstzTextDef.getAsJavaString();
+ }
+
+ public byte[] serialize()
+ {
+ byte[] buffer = new byte[getSize()];
+ int offset = 0;
+
+ _base.serialize( buffer, offset );
+ offset += FFDataBase.getSize();
+
+ offset += _xstzName.serialize( buffer, offset );
+
+ if ( _base.getIType() == FFDataBase.ITYPE_TEXT )
+ {
+ offset += _xstzTextDef.serialize( buffer, offset );
+ }
+
+ if ( _base.getIType() == FFDataBase.ITYPE_CHCK
+ || _base.getIType() == FFDataBase.ITYPE_DROP )
+ {
+ LittleEndian.putUShort( buffer, offset, _wDef );
+ offset += LittleEndian.SHORT_SIZE;
+ }
+
+ offset += _xstzTextFormat.serialize( buffer, offset );
+ offset += _xstzHelpText.serialize( buffer, offset );
+ offset += _xstzStatText.serialize( buffer, offset );
+ offset += _xstzEntryMcr.serialize( buffer, offset );
+ offset += _xstzExitMcr.serialize( buffer, offset );
+
+ if ( _base.getIType() == FFDataBase.ITYPE_DROP )
+ {
+ offset += _hsttbDropList.serialize( buffer, offset );
+ }
+
+ return buffer;
+ }
+}
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/FFDataBase.java b/src/scratchpad/src/org/apache/poi/hwpf/model/FFDataBase.java
new file mode 100644
index 0000000000..999dca5519
--- /dev/null
+++ b/src/scratchpad/src/org/apache/poi/hwpf/model/FFDataBase.java
@@ -0,0 +1,33 @@
+package org.apache.poi.hwpf.model;
+
+import org.apache.poi.hwpf.model.types.FFDataBaseAbstractType;
+import org.apache.poi.util.Internal;
+
+/**
+ * The FFData structure specifies form field data for a text box, check box, or
+ * drop-down list box.
+ * <p>
+ * Class and fields descriptions are quoted from [MS-DOC] -- v20121003 Word
+ * (.doc) Binary File Format; Copyright (c) 2012 Microsoft Corporation; Release:
+ * October 8, 2012
+ * <p>
+ * This class is internal. It content or properties may change without notice
+ * due to changes in our knowledge of internal Microsoft Word binary structures.
+ *
+ * @author Sergey Vladimirov; according to [MS-DOC] -- v20121003 Word (.doc)
+ * Binary File Format; Copyright (c) 2012 Microsoft Corporation;
+ * Release: October 8, 2012
+ */
+@Internal
+public class FFDataBase extends FFDataBaseAbstractType
+{
+ public FFDataBase()
+ {
+ super();
+ }
+
+ public FFDataBase( byte[] std, int offset )
+ {
+ fillFields( std, offset );
+ }
+}
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/FIBFieldHandler.java b/src/scratchpad/src/org/apache/poi/hwpf/model/FIBFieldHandler.java
index 9d61d8abbc..ff55082afd 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/model/FIBFieldHandler.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/model/FIBFieldHandler.java
@@ -90,7 +90,8 @@ public final class FIBFieldHandler
public static final int PLCFATNBKL = 43;
// 506 == 0x01FA; 510 == 0x01FE
public static final int PMS = 44;
- public static final int FORMFLDSTTBS = 45;
+ // 514 == 0x0202; 518 == 0x0206
+ public static final int FORMFLDSTTBS = 45;
public static final int PLCFENDREF = 46;
public static final int PLCFENDTXT = 47;
public static final int PLCFFLDEDN = 48;
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/NilPICFAndBinData.java b/src/scratchpad/src/org/apache/poi/hwpf/model/NilPICFAndBinData.java
new file mode 100644
index 0000000000..ea98db50f8
--- /dev/null
+++ b/src/scratchpad/src/org/apache/poi/hwpf/model/NilPICFAndBinData.java
@@ -0,0 +1,59 @@
+package org.apache.poi.hwpf.model;
+
+import org.apache.poi.util.ArrayUtil;
+import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.POILogFactory;
+import org.apache.poi.util.POILogger;
+
+public class NilPICFAndBinData
+{
+
+ private static final POILogger log = POILogFactory
+ .getLogger( NilPICFAndBinData.class );
+
+ private byte[] _binData;
+
+ public NilPICFAndBinData( byte[] data, int offset )
+ {
+ fillFields( data, offset );
+ }
+
+ public void fillFields( byte[] data, int offset )
+ {
+ int lcb = LittleEndian.getInt( data, offset );
+ int cbHeader = LittleEndian.getUShort( data, offset
+ + LittleEndian.INT_SIZE );
+
+ if ( cbHeader != 0x44 )
+ {
+ log.log( POILogger.WARN, "NilPICFAndBinData at offset ", offset,
+ " cbHeader 0x" + Integer.toHexString( cbHeader )
+ + " != 0x44" );
+ }
+
+ // skip the 62 ignored bytes
+ int binaryLength = lcb - cbHeader;
+ this._binData = ArrayUtil.copyOfRange( data, offset + cbHeader,
+ offset + cbHeader + binaryLength );
+ }
+
+ public byte[] getBinData()
+ {
+ return _binData;
+ }
+
+ public byte[] serialize()
+ {
+ byte[] bs = new byte[_binData.length + 0x44];
+ LittleEndian.putInt( bs, 0, _binData.length + 0x44 );
+ System.arraycopy( _binData, 0, bs, 0x44, _binData.length );
+ return bs;
+ }
+
+ public int serialize( byte[] data, int offset )
+ {
+ LittleEndian.putInt( data, offset, _binData.length + 0x44 );
+ System.arraycopy( _binData, 0, data, offset + 0x44, _binData.length );
+ return 0x44 + _binData.length;
+ }
+}
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/Sttb.java b/src/scratchpad/src/org/apache/poi/hwpf/model/Sttb.java
new file mode 100644
index 0000000000..fabd1e2331
--- /dev/null
+++ b/src/scratchpad/src/org/apache/poi/hwpf/model/Sttb.java
@@ -0,0 +1,232 @@
+package org.apache.poi.hwpf.model;
+
+import org.apache.poi.util.ArrayUtil;
+import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.StringUtil;
+
+/**
+ * The STTB is a string table that is made up of a header that is followed by an
+ * array of elements. The cData value specifies the number of elements that are
+ * contained in the array.
+ * <p>
+ * Class and fields descriptions are quoted from [MS-DOC] -- v20121003 Word
+ * (.doc) Binary File Format; Copyright (c) 2012 Microsoft Corporation; Release:
+ * October 8, 2012
+ * <p>
+ * This class is internal. It content or properties may change without notice
+ * due to changes in our knowledge of internal Microsoft Word binary structures.
+ *
+ * @author Sergey Vladimirov; according to [MS-DOC] -- v20121003 Word (.doc)
+ * Binary File Format; Copyright (c) 2012 Microsoft Corporation;
+ * Release: October 8, 2012
+ */
+public class Sttb
+{
+
+ private int _cbExtra;
+
+ private final int _cDataLength;
+
+ private String[] _data;
+
+ private byte[][] _extraData;
+
+ private final boolean _fExtend = true;
+
+ public Sttb( byte[] buffer, int startOffset )
+ {
+ this( 2, buffer, startOffset );
+ }
+
+ public Sttb( int cDataLength, byte[] buffer, int startOffset )
+ {
+ this._cDataLength = cDataLength;
+ fillFields( buffer, startOffset );
+ }
+
+ public Sttb( int cDataLength, String[] data )
+ {
+ this._cDataLength = cDataLength;
+
+ this._data = ArrayUtil.copyOf( data, new String[data.length] );
+
+ this._cbExtra = 0;
+ this._extraData = null;
+ }
+
+ public void fillFields( byte[] buffer, int startOffset )
+ {
+ short ffff = LittleEndian.getShort( buffer, startOffset );
+ int offset = startOffset + LittleEndian.SHORT_SIZE;
+
+ if ( ffff != (short) 0xffff )
+ {
+ // Non-extended character Pascal strings
+ throw new UnsupportedOperationException(
+ "Non-extended character Pascal strings are not supported right now. "
+ + "Please, contact POI developers for update." );
+ }
+ // strings are extended character strings
+
+ int cData = _cDataLength == 2 ? LittleEndian.getUShort( buffer, offset )
+ : LittleEndian.getInt( buffer, offset );
+ offset += _cDataLength;
+
+ this._cbExtra = LittleEndian.getUShort( buffer, offset );
+ offset += 2;
+
+ _data = new String[cData];
+ _extraData = new byte[cData][];
+
+ for ( int i = 0; i < cData; i++ )
+ {
+ int cchData = LittleEndian.getShort( buffer, offset );
+ offset += 2;
+
+ if ( cchData < 0 )
+ continue;
+
+ _data[i] = StringUtil.getFromUnicodeLE( buffer, offset, cchData );
+ offset += cchData * 2;
+
+ _extraData[i] = LittleEndian
+ .getByteArray( buffer, offset, _cbExtra );
+ offset += _cbExtra;
+ }
+ }
+
+ /**
+ * The definition of each STTB specifies the meaning of this field. If this
+ * STTB uses extended characters, the size of this field is 2*cchData bytes
+ * and it is a Unicode string unless otherwise specified by the STTB
+ * definition. If this STTB does not use extended characters, then the size
+ * of this field is cchData bytes and it is an ANSI string, unless otherwise
+ * specified by the STTB definition.
+ */
+ public String[] getData()
+ {
+ return _data;
+ }
+
+ public int getSize()
+ {
+ // ffff
+ int size = LittleEndian.SHORT_SIZE;
+
+ // cData
+ size += _cDataLength;
+
+ // cbExtra
+ size += LittleEndian.SHORT_SIZE;
+
+ if ( this._fExtend )
+ {
+ for ( String data : _data )
+ {
+ // cchData
+ size += LittleEndian.SHORT_SIZE;
+ // data
+ size += 2 * data.length();
+ }
+ }
+ else
+ {
+ for ( String data : _data )
+ {
+ // cchData
+ size += LittleEndian.BYTE_SIZE;
+ // data
+ size += 1 * data.length();
+ }
+ }
+
+ // extraData
+ if ( _extraData != null )
+ {
+ size += _cbExtra * _data.length;
+ }
+
+ return size;
+ }
+
+ public byte[] serialize()
+ {
+ final byte[] buffer = new byte[getSize()];
+
+ LittleEndian.putShort( buffer, 0, (short) 0xffff );
+
+ if ( _data == null || _data.length == 0 )
+ {
+ if ( _cDataLength == 4 )
+ {
+ LittleEndian.putInt( buffer, 2, 0 );
+ LittleEndian.putUShort( buffer, 6, _cbExtra );
+ return buffer;
+ }
+
+ LittleEndian.putUShort( buffer, 2, 0 );
+ LittleEndian.putUShort( buffer, 4, _cbExtra );
+ return buffer;
+ }
+
+ int offset;
+ if ( _cDataLength == 4 )
+ {
+ LittleEndian.putInt( buffer, 2, _data.length );
+ LittleEndian.putUShort( buffer, 6, _cbExtra );
+ offset = 2 + LittleEndian.INT_SIZE + LittleEndian.SHORT_SIZE;
+ }
+ else
+ {
+ LittleEndian.putUShort( buffer, 2, _data.length );
+ LittleEndian.putUShort( buffer, 4, _cbExtra );
+ offset = 2 + LittleEndian.SHORT_SIZE + LittleEndian.SHORT_SIZE;
+ }
+
+ for ( int i = 0; i < _data.length; i++ )
+ {
+ String entry = _data[i];
+ if ( entry == null )
+ {
+ // is it correct?
+ buffer[offset] = -1;
+ buffer[offset + 1] = 0;
+ offset += 2;
+ continue;
+ }
+
+ if ( _fExtend )
+ {
+ LittleEndian.putUShort( buffer, offset, (int) entry.length() );
+ offset += LittleEndian.SHORT_SIZE;
+
+ StringUtil.putUnicodeLE( entry, buffer, offset );
+ offset += 2 * entry.length();
+ }
+ else
+ {
+ throw new UnsupportedOperationException(
+ "ANSI STTB is not supported yet" );
+ }
+
+ if ( _cbExtra != 0 )
+ {
+ if ( _extraData[i] != null && _extraData[i].length != 0 )
+ {
+ System.arraycopy( _extraData[i], 0, buffer, offset,
+ Math.min( _extraData[i].length, _cbExtra ) );
+ }
+ offset += _cbExtra;
+ }
+ }
+
+ return buffer;
+ }
+
+ public int serialize( byte[] buffer, int offset )
+ {
+ byte[] bs = serialize();
+ System.arraycopy( bs, 0, buffer, offset, bs.length );
+ return bs.length;
+ }
+}
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/SttbUtils.java b/src/scratchpad/src/org/apache/poi/hwpf/model/SttbUtils.java
index 1cc11e0cda..fba473f9cf 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/model/SttbUtils.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/model/SttbUtils.java
@@ -20,8 +20,6 @@ import java.io.IOException;
import org.apache.poi.hwpf.model.io.HWPFOutputStream;
import org.apache.poi.util.Internal;
-import org.apache.poi.util.LittleEndian;
-import org.apache.poi.util.StringUtil;
/**
* Utils class for storing and reading "STring TaBle stored in File"
@@ -32,180 +30,47 @@ import org.apache.poi.util.StringUtil;
class SttbUtils
{
- static class Sttb
- {
- public int cbExtra;
-
- public int cDataLength;
-
- public String[] data;
-
- public byte[][] extraData;
- }
-
- private static final int CBEXTRA_STTB_SAVED_BY = 0; // bytes
-
- private static final int CBEXTRA_STTBF_BKMK = 0; // bytes
-
- private static final int CBEXTRA_STTBF_R_MARK = 0; // bytes
-
private static final int CDATA_SIZE_STTB_SAVED_BY = 2; // bytes
private static final int CDATA_SIZE_STTBF_BKMK = 2; // bytes
private static final int CDATA_SIZE_STTBF_R_MARK = 2; // bytes
- static Sttb read( int cDataLength, byte[] buffer, int startOffset )
- {
- short ffff = LittleEndian.getShort( buffer, startOffset );
- int offset = startOffset + 2;
-
- if ( ffff != (short) 0xffff )
- {
- // Non-extended character Pascal strings
- throw new UnsupportedOperationException(
- "Non-extended character Pascal strings are not supported right now. "
- + "Please, contact POI developers for update." );
- }
- // strings are extended character strings
-
- int cData = cDataLength == 2 ? LittleEndian.getUShort( buffer, offset )
- : LittleEndian.getInt( buffer, offset );
- offset += cDataLength;
-
- Sttb sttb = new Sttb();
- sttb.cDataLength = cDataLength;
- sttb.cbExtra = LittleEndian.getUShort( buffer, offset );
- offset += 2;
-
- sttb.data = new String[cData];
- sttb.extraData = new byte[cData][];
-
- for ( int i = 0; i < cData; i++ )
- {
- int cchData = LittleEndian.getShort( buffer, offset );
- offset += 2;
-
- if ( cchData < 0 )
- continue;
-
- sttb.data[i] = StringUtil
- .getFromUnicodeLE( buffer, offset, cchData );
- offset += cchData * 2;
-
- sttb.extraData[i] = LittleEndian.getByteArray( buffer, offset,
- sttb.cbExtra );
- offset += sttb.cbExtra;
- }
-
- return sttb;
- }
-
static String[] readSttbfBkmk( byte[] buffer, int startOffset )
{
- return read( CDATA_SIZE_STTBF_BKMK, buffer, startOffset ).data;
+ return new Sttb( CDATA_SIZE_STTBF_BKMK, buffer, startOffset ).getData();
}
static String[] readSttbfRMark( byte[] buffer, int startOffset )
{
- return read( CDATA_SIZE_STTBF_R_MARK, buffer, startOffset ).data;
+ return new Sttb( CDATA_SIZE_STTBF_R_MARK, buffer, startOffset )
+ .getData();
}
static String[] readSttbSavedBy( byte[] buffer, int startOffset )
{
- return read( CDATA_SIZE_STTB_SAVED_BY, buffer, startOffset ).data;
- }
-
- static void write( Sttb sttb, HWPFOutputStream tableStream )
- throws IOException
- {
- final int headerSize = sttb.cDataLength == 2 ? 6 : 8;
-
- byte[] header = new byte[headerSize];
- LittleEndian.putShort( header, 0, (short) 0xffff );
-
- if ( sttb.data == null || sttb.data.length == 0 )
- {
- if ( sttb.cDataLength == 4 )
- {
- LittleEndian.putInt( header, 2, 0 );
- LittleEndian.putUShort( header, 6, sttb.cbExtra );
- tableStream.write( header );
- return;
- }
-
- LittleEndian.putUShort( header, 2, 0 );
- LittleEndian.putUShort( header, 4, sttb.cbExtra );
- tableStream.write( header );
- return;
- }
-
- if ( sttb.cDataLength == 4 )
- {
- LittleEndian.putInt( header, 2, sttb.data.length );
- LittleEndian.putUShort( header, 6, sttb.cbExtra );
- tableStream.write( header );
- }
- else
- {
- LittleEndian.putUShort( header, 2, sttb.data.length );
- LittleEndian.putUShort( header, 4, sttb.cbExtra );
- tableStream.write( header );
- }
-
- for ( int i = 0; i < sttb.data.length; i++ )
- {
- String entry = sttb.data[i];
- if ( entry == null )
- {
- // is it correct?
- tableStream.write( new byte[] { -1, 0 } );
- continue;
- }
-
- byte[] buf = new byte[entry.length() * 2 + sttb.cbExtra + 2];
-
- LittleEndian.putShort( buf, 0, (short) entry.length() );
- StringUtil.putUnicodeLE( entry, buf, 2 );
-
- if ( sttb.extraData != null && i < sttb.extraData.length
- && sttb.extraData[i] != null )
- System.arraycopy( sttb.extraData[i], 0, buf,
- entry.length() * 2,
- Math.min( sttb.extraData[i].length, sttb.cbExtra ) );
-
- tableStream.write( buf );
- }
+ return new Sttb( CDATA_SIZE_STTB_SAVED_BY, buffer, startOffset )
+ .getData();
}
static void writeSttbfBkmk( String[] data, HWPFOutputStream tableStream )
throws IOException
{
- Sttb sttb = new Sttb();
- sttb.cDataLength = CDATA_SIZE_STTBF_BKMK;
- sttb.data = data;
- sttb.cbExtra = CBEXTRA_STTBF_BKMK;
- write( sttb, tableStream );
+ tableStream.write( new Sttb( CDATA_SIZE_STTBF_BKMK, data ).serialize() );
}
static void writeSttbfRMark( String[] data, HWPFOutputStream tableStream )
throws IOException
{
- Sttb sttb = new Sttb();
- sttb.cDataLength = CDATA_SIZE_STTBF_R_MARK;
- sttb.data = data;
- sttb.cbExtra = CBEXTRA_STTBF_R_MARK;
- write( sttb, tableStream );
+ tableStream.write( new Sttb( CDATA_SIZE_STTBF_R_MARK, data )
+ .serialize() );
}
static void writeSttbSavedBy( String[] data, HWPFOutputStream tableStream )
throws IOException
{
- Sttb sttb = new Sttb();
- sttb.cDataLength = CDATA_SIZE_STTB_SAVED_BY;
- sttb.data = data;
- sttb.cbExtra = CBEXTRA_STTB_SAVED_BY;
- write( sttb, tableStream );
+ tableStream.write( new Sttb( CDATA_SIZE_STTB_SAVED_BY, data )
+ .serialize() );
}
}
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/Xstz.java b/src/scratchpad/src/org/apache/poi/hwpf/model/Xstz.java
new file mode 100644
index 0000000000..fb351e9cb9
--- /dev/null
+++ b/src/scratchpad/src/org/apache/poi/hwpf/model/Xstz.java
@@ -0,0 +1,69 @@
+package org.apache.poi.hwpf.model;
+
+import org.apache.poi.util.Internal;
+import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.POILogFactory;
+import org.apache.poi.util.POILogger;
+
+@Internal
+public class Xstz
+{
+ private static final POILogger log = POILogFactory.getLogger( Xstz.class );
+
+ private final short _chTerm = 0;
+ private Xst _xst;
+
+ public Xstz()
+ {
+ _xst = new Xst();
+ }
+
+ public Xstz( byte[] data, int startOffset )
+ {
+ fillFields( data, startOffset );
+ }
+
+ public void fillFields( byte[] data, int startOffset )
+ {
+ int offset = startOffset;
+
+ _xst = new Xst( data, offset );
+ offset += _xst.getSize();
+
+ short term = LittleEndian.getShort( data, offset );
+ if ( term != 0 )
+ {
+ log.log( POILogger.WARN, "chTerm at the end of Xstz at offset ",
+ offset, " is not 0" );
+ }
+ }
+
+ public String getAsJavaString()
+ {
+ return _xst.getAsJavaString();
+ }
+
+ public int getSize()
+ {
+ return _xst.getSize() + LittleEndian.SHORT_SIZE;
+ }
+
+ public int serialize( byte[] data, int startOffset )
+ {
+ int offset = startOffset;
+
+ _xst.serialize( data, offset );
+ offset += _xst.getSize();
+
+ LittleEndian.putUShort( data, offset, _chTerm );
+ offset += LittleEndian.SHORT_SIZE;
+
+ return offset - startOffset;
+ }
+
+ @Override
+ public String toString()
+ {
+ return "[Xstz]" + _xst.getAsJavaString() + "[/Xstz]";
+ }
+}
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/types/FFDataBaseAbstractType.java b/src/scratchpad/src/org/apache/poi/hwpf/model/types/FFDataBaseAbstractType.java
new file mode 100644
index 0000000000..f582018b28
--- /dev/null
+++ b/src/scratchpad/src/org/apache/poi/hwpf/model/types/FFDataBaseAbstractType.java
@@ -0,0 +1,428 @@
+/* ====================================================================
+ 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.types;
+
+
+import org.apache.poi.util.BitField;
+import org.apache.poi.util.Internal;
+import org.apache.poi.util.LittleEndian;
+
+/**
+ * The FFData structure specifies form field data for a text
+ box, check box, or drop-down list box. <p>Class and fields
+ descriptions are quoted from [MS-DOC] -- v20121003 Word (.doc) Binary
+ File Format; Copyright (c) 2012 Microsoft Corporation; Release:
+ October 8, 2012
+
+ * <p>
+ * NOTE: This source is automatically generated please do not modify this file. Either subclass or
+ * remove the record in src/types/definitions.
+ * <p>
+ * This class is internal. It content or properties may change without notice
+ * due to changes in our knowledge of internal Microsoft Word binary structures.
+
+ * @author Sergey Vladimirov; according to [MS-DOC] -- v20121003 Word
+ (.doc) Binary File Format; Copyright (c) 2012 Microsoft Corporation;
+ Release: October 8, 2012
+
+ */
+@Internal
+public abstract class FFDataBaseAbstractType
+{
+
+ protected long field_1_version;
+ protected short field_2_bits;
+ /**/private static final BitField iType = new BitField(0x0003);
+ /** Specifies that the form field is a textbox. */
+ /* */public final static byte ITYPE_TEXT = 0;
+ /** Specifies that the form field is a checkbox. */
+ /* */public final static byte ITYPE_CHCK = 1;
+ /** Specifies that the form field is a dropdown list box. */
+ /* */public final static byte ITYPE_DROP = 2;
+ /**/private static final BitField iRes = new BitField(0x007C);
+ /**/private static final BitField fOwnHelp = new BitField(0x0080);
+ /**/private static final BitField fOwnStat = new BitField(0x0100);
+ /**/private static final BitField fProt = new BitField(0x0200);
+ /**/private static final BitField iSize = new BitField(0x0400);
+ /**/private static final BitField iTypeTxt = new BitField(0x3800);
+ /** Specifies that the textbox value is regular text. */
+ /* */public final static byte ITYPETXT_REG = 0;
+ /** Specifies that the textbox value is a number. */
+ /* */public final static byte ITYPETXT_NUM = 0;
+ /** Specifies that the textbox value is a date or time. */
+ /* */public final static byte ITYPETXT_DATE = 0;
+ /** Specifies that the textbox value is the current date. */
+ /* */public final static byte ITYPETXT_CURDATE = 0;
+ /** Specifies that the textbox value is the current time. */
+ /* */public final static byte ITYPETXT_CURTIME = 0;
+ /** Specifies that the textbox value is calculated from an expression. The expression is given by FFData.xstzTextDef. */
+ /* */protected final static byte ITYPETXT_CALC = 0;
+ /**/private static final BitField fRecalc = new BitField(0x4000);
+ /**/private static final BitField fHasListBox = new BitField(0x8000);
+ protected int field_3_cch;
+ protected int field_4_hps;
+
+ protected FFDataBaseAbstractType()
+ {
+ }
+
+ protected void fillFields( byte[] data, int offset )
+ {
+ field_1_version = LittleEndian.getUInt( data, 0x0 + offset );
+ field_2_bits = LittleEndian.getShort( data, 0x4 + offset );
+ field_3_cch = LittleEndian.getShort( data, 0x6 + offset );
+ field_4_hps = LittleEndian.getShort( data, 0x8 + offset );
+ }
+
+ public void serialize( byte[] data, int offset )
+ {
+ LittleEndian.putUInt( data, 0x0 + offset, field_1_version );
+ LittleEndian.putShort( data, 0x4 + offset, field_2_bits );
+ LittleEndian.putUShort( data, 0x6 + offset, field_3_cch );
+ LittleEndian.putUShort( data, 0x8 + offset, field_4_hps );
+ }
+
+ public byte[] serialize()
+ {
+ final byte[] result = new byte[ getSize() ];
+ serialize( result, 0 );
+ return result;
+ }
+
+ /**
+ * Size of record
+ */
+ public static int getSize()
+ {
+ return 0 + 4 + 2 + 2 + 2;
+ }
+
+ @Override
+ public boolean equals( Object obj )
+ {
+ if ( this == obj )
+ return true;
+ if ( obj == null )
+ return false;
+ if ( getClass() != obj.getClass() )
+ return false;
+ FFDataBaseAbstractType other = (FFDataBaseAbstractType) obj;
+ if ( field_1_version != other.field_1_version )
+ return false;
+ if ( field_2_bits != other.field_2_bits )
+ return false;
+ if ( field_3_cch != other.field_3_cch )
+ return false;
+ if ( field_4_hps != other.field_4_hps )
+ return false;
+ return true;
+ }
+
+ @Override
+ public int hashCode()
+ {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result
+ + (int) ( field_1_version ^ ( field_1_version >>> 32 ) );
+ result = prime * result + field_2_bits;
+ result = prime * result + field_3_cch;
+ result = prime * result + field_4_hps;
+ return result;
+ }
+
+ public String toString()
+ {
+ StringBuilder builder = new StringBuilder();
+
+ builder.append("[FFDataBase]\n");
+ builder.append( " .version = " );
+ builder.append(" ( ").append( field_1_version ).append( " )\n" );
+ builder.append( " .bits = " );
+ builder.append(" ( ").append( field_2_bits ).append( " )\n" );
+ builder.append(" .iType = ").append(getIType()).append('\n');
+ builder.append(" .iRes = ").append(getIRes()).append('\n');
+ builder.append(" .fOwnHelp = ").append(isFOwnHelp()).append('\n');
+ builder.append(" .fOwnStat = ").append(isFOwnStat()).append('\n');
+ builder.append(" .fProt = ").append(isFProt()).append('\n');
+ builder.append(" .iSize = ").append(isISize()).append('\n');
+ builder.append(" .iTypeTxt = ").append(getITypeTxt()).append('\n');
+ builder.append(" .fRecalc = ").append(isFRecalc()).append('\n');
+ builder.append(" .fHasListBox = ").append(isFHasListBox()).append('\n');
+ builder.append( " .cch = " );
+ builder.append(" ( ").append( field_3_cch ).append( " )\n" );
+ builder.append( " .hps = " );
+ builder.append(" ( ").append( field_4_hps ).append( " )\n" );
+
+ builder.append("[/FFDataBase]");
+ return builder.toString();
+ }
+
+ /**
+ * An unsigned integer that MUST be 0xFFFFFFFF.
+ */
+ @Internal
+ public long getVersion()
+ {
+ return field_1_version;
+ }
+
+ /**
+ * An unsigned integer that MUST be 0xFFFFFFFF.
+ */
+ @Internal
+ public void setVersion( long field_1_version )
+ {
+ this.field_1_version = field_1_version;
+ }
+
+ /**
+ * An FFDataBits that specifies the type and state of this form field.
+ */
+ @Internal
+ public short getBits()
+ {
+ return field_2_bits;
+ }
+
+ /**
+ * An FFDataBits that specifies the type and state of this form field.
+ */
+ @Internal
+ public void setBits( short field_2_bits )
+ {
+ this.field_2_bits = field_2_bits;
+ }
+
+ /**
+ * An unsigned integer that specifies the maximum length, in characters, of the value of the textbox. This value MUST NOT exceed 32767. A value of 0 means there is no maximum length of the value of the textbox. If bits.iType is not iTypeText (0), this value MUST be 0..
+ */
+ @Internal
+ public int getCch()
+ {
+ return field_3_cch;
+ }
+
+ /**
+ * An unsigned integer that specifies the maximum length, in characters, of the value of the textbox. This value MUST NOT exceed 32767. A value of 0 means there is no maximum length of the value of the textbox. If bits.iType is not iTypeText (0), this value MUST be 0..
+ */
+ @Internal
+ public void setCch( int field_3_cch )
+ {
+ this.field_3_cch = field_3_cch;
+ }
+
+ /**
+ * An unsigned integer. If bits.iType is iTypeChck (1), hps specifies the size, in half-points, of the checkbox and MUST be between 2 and 3168, inclusive. If bits.iType is not iTypeChck (1), hps is undefined and MUST be ignored..
+ */
+ @Internal
+ public int getHps()
+ {
+ return field_4_hps;
+ }
+
+ /**
+ * An unsigned integer. If bits.iType is iTypeChck (1), hps specifies the size, in half-points, of the checkbox and MUST be between 2 and 3168, inclusive. If bits.iType is not iTypeChck (1), hps is undefined and MUST be ignored..
+ */
+ @Internal
+ public void setHps( int field_4_hps )
+ {
+ this.field_4_hps = field_4_hps;
+ }
+
+ /**
+ * Sets the iType field value.
+ * An unsigned integer that specifies the type of the form field.
+ */
+ @Internal
+ public void setIType( byte value )
+ {
+ field_2_bits = (short)iType.setValue(field_2_bits, value);
+ }
+
+ /**
+ * An unsigned integer that specifies the type of the form field.
+ * @return the iType field value.
+ */
+ @Internal
+ public byte getIType()
+ {
+ return ( byte )iType.getValue(field_2_bits);
+ }
+
+ /**
+ * Sets the iRes field value.
+ * An unsigned integer. If iType is iTypeText (0), then iRes MUST be 0. If iType is iTypeChck (1), iRes specifies the state of the checkbox and MUST be 0 (unchecked), 1 (checked), or 25 (undefined). Undefined checkboxes are treated as unchecked. If iType is iTypeDrop (2), iRes specifies the current selected list box item. A value of 25 specifies the selection is undefined. Otherwise, iRes is a zero-based index into FFData.hsttbDropList.
+ */
+ @Internal
+ public void setIRes( byte value )
+ {
+ field_2_bits = (short)iRes.setValue(field_2_bits, value);
+ }
+
+ /**
+ * An unsigned integer. If iType is iTypeText (0), then iRes MUST be 0. If iType is iTypeChck (1), iRes specifies the state of the checkbox and MUST be 0 (unchecked), 1 (checked), or 25 (undefined). Undefined checkboxes are treated as unchecked. If iType is iTypeDrop (2), iRes specifies the current selected list box item. A value of 25 specifies the selection is undefined. Otherwise, iRes is a zero-based index into FFData.hsttbDropList.
+ * @return the iRes field value.
+ */
+ @Internal
+ public byte getIRes()
+ {
+ return ( byte )iRes.getValue(field_2_bits);
+ }
+
+ /**
+ * Sets the fOwnHelp field value.
+ * A bit that specifies whether the form field has custom help text in FFData.xstzHelpText. If fOwnHelp is 0, FFData.xstzHelpText contains an empty or auto-generated string.
+ */
+ @Internal
+ public void setFOwnHelp( boolean value )
+ {
+ field_2_bits = (short)fOwnHelp.setBoolean(field_2_bits, value);
+ }
+
+ /**
+ * A bit that specifies whether the form field has custom help text in FFData.xstzHelpText. If fOwnHelp is 0, FFData.xstzHelpText contains an empty or auto-generated string.
+ * @return the fOwnHelp field value.
+ */
+ @Internal
+ public boolean isFOwnHelp()
+ {
+ return fOwnHelp.isSet(field_2_bits);
+ }
+
+ /**
+ * Sets the fOwnStat field value.
+ * A bit that specifies whether the form field has custom status bar text in FFData.xstzStatText. If fOwnStat is 0, FFData.xstzStatText contains an empty or auto-generated string.
+ */
+ @Internal
+ public void setFOwnStat( boolean value )
+ {
+ field_2_bits = (short)fOwnStat.setBoolean(field_2_bits, value);
+ }
+
+ /**
+ * A bit that specifies whether the form field has custom status bar text in FFData.xstzStatText. If fOwnStat is 0, FFData.xstzStatText contains an empty or auto-generated string.
+ * @return the fOwnStat field value.
+ */
+ @Internal
+ public boolean isFOwnStat()
+ {
+ return fOwnStat.isSet(field_2_bits);
+ }
+
+ /**
+ * Sets the fProt field value.
+ * A bit that specifies whether the form field is protected and its value cannot be changed.
+ */
+ @Internal
+ public void setFProt( boolean value )
+ {
+ field_2_bits = (short)fProt.setBoolean(field_2_bits, value);
+ }
+
+ /**
+ * A bit that specifies whether the form field is protected and its value cannot be changed.
+ * @return the fProt field value.
+ */
+ @Internal
+ public boolean isFProt()
+ {
+ return fProt.isSet(field_2_bits);
+ }
+
+ /**
+ * Sets the iSize field value.
+ * A bit that specifies whether the size of a checkbox is automatically determined by the text size where the checkbox is located. This value MUST be 0 if iType is not iTypeChck (1).
+ */
+ @Internal
+ public void setISize( boolean value )
+ {
+ field_2_bits = (short)iSize.setBoolean(field_2_bits, value);
+ }
+
+ /**
+ * A bit that specifies whether the size of a checkbox is automatically determined by the text size where the checkbox is located. This value MUST be 0 if iType is not iTypeChck (1).
+ * @return the iSize field value.
+ */
+ @Internal
+ public boolean isISize()
+ {
+ return iSize.isSet(field_2_bits);
+ }
+
+ /**
+ * Sets the iTypeTxt field value.
+ * An unsigned integer that specifies the type of the textbox. If iType is not iTypeText (0), iTypeTxt MUST be 0 and MUST be ignored.
+ */
+ @Internal
+ public void setITypeTxt( byte value )
+ {
+ field_2_bits = (short)iTypeTxt.setValue(field_2_bits, value);
+ }
+
+ /**
+ * An unsigned integer that specifies the type of the textbox. If iType is not iTypeText (0), iTypeTxt MUST be 0 and MUST be ignored.
+ * @return the iTypeTxt field value.
+ */
+ @Internal
+ public byte getITypeTxt()
+ {
+ return ( byte )iTypeTxt.getValue(field_2_bits);
+ }
+
+ /**
+ * Sets the fRecalc field value.
+ * A bit that specifies whether the value of the field is automatically calculated after the field is modified.
+ */
+ @Internal
+ public void setFRecalc( boolean value )
+ {
+ field_2_bits = (short)fRecalc.setBoolean(field_2_bits, value);
+ }
+
+ /**
+ * A bit that specifies whether the value of the field is automatically calculated after the field is modified.
+ * @return the fRecalc field value.
+ */
+ @Internal
+ public boolean isFRecalc()
+ {
+ return fRecalc.isSet(field_2_bits);
+ }
+
+ /**
+ * Sets the fHasListBox field value.
+ * A bit that specifies that the form field has a list box. This value MUST be 1 if iType is iTypeDrop (2). Otherwise, this value MUST be 0.
+ */
+ @Internal
+ public void setFHasListBox( boolean value )
+ {
+ field_2_bits = (short)fHasListBox.setBoolean(field_2_bits, value);
+ }
+
+ /**
+ * A bit that specifies that the form field has a list box. This value MUST be 1 if iType is iTypeDrop (2). Otherwise, this value MUST be 0.
+ * @return the fHasListBox field value.
+ */
+ @Internal
+ public boolean isFHasListBox()
+ {
+ return fHasListBox.isSet(field_2_bits);
+ }
+
+} // END OF CLASS
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/sprm/CharacterSprmUncompressor.java b/src/scratchpad/src/org/apache/poi/hwpf/sprm/CharacterSprmUncompressor.java
index 6bb3785f4c..d3fe6613a6 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/sprm/CharacterSprmUncompressor.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/sprm/CharacterSprmUncompressor.java
@@ -180,16 +180,13 @@ public final class CharacterSprmUncompressor extends SprmUncompressor
case 0x3:
// sprmCPicLocation -- 0x6A03
/*
- * Microsoft Office Word 97-2007 Binary File Format (.doc)
- * Specification
+ * [MS-DOC]
*
- * Page 75 of 210
+ * Page 104 of 622
*
- * sprmCPicLocation (opcode 0x6A03) is used ONLY IN CHPX FKPs. This
- * sprm moves the 4-byte operand of the sprm into the chp.fcPic
- * field. It simultaneously sets chp.fSpec to 1. This sprm is also
- * used when the chp.lTagObj field that is unioned with chp.fcPic is
- * to be set for OLE objects.
+ * A signed 32-bit integer that specifies either the position in the
+ * Data Stream of a picture or binary data or the name of an OLE
+ * object storage.
*/
newCHP.setFcPic( sprm.getOperand() );
newCHP.setFSpec( true );
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/usermodel/CharacterRun.java b/src/scratchpad/src/org/apache/poi/hwpf/usermodel/CharacterRun.java
index 77ec0ecd33..97875ee248 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/usermodel/CharacterRun.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/usermodel/CharacterRun.java
@@ -17,8 +17,11 @@
package org.apache.poi.hwpf.usermodel;
+import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.hwpf.model.CHPX;
+import org.apache.poi.hwpf.model.FFData;
import org.apache.poi.hwpf.model.Ffn;
+import org.apache.poi.hwpf.model.NilPICFAndBinData;
import org.apache.poi.hwpf.model.StyleSheet;
import org.apache.poi.hwpf.sprm.SprmBuffer;
@@ -631,4 +634,42 @@ public final class CharacterRun
String text = text();
return "CharacterRun of " + text.length() + " characters - " + text;
}
+
+ public String[] getDropDownListValues()
+ {
+ if ( getDocument() instanceof HWPFDocument )
+ {
+ char c = _text.charAt( _start );
+ if ( c == 0x01 )
+ {
+ NilPICFAndBinData data = new NilPICFAndBinData(
+ ( (HWPFDocument) getDocument() ).getDataStream(),
+ getPicOffset() );
+ FFData ffData = new FFData( data.getBinData(), 0 );
+
+ String[] values = ffData.getDropList();
+ return values;
+ }
+ }
+ return null;
+ }
+
+ public Integer getDropDownListDefaultItemIndex()
+ {
+ if ( getDocument() instanceof HWPFDocument )
+ {
+ char c = _text.charAt( _start );
+ if ( c == 0x01 )
+ {
+ NilPICFAndBinData data = new NilPICFAndBinData(
+ ( (HWPFDocument) getDocument() ).getDataStream(),
+ getPicOffset() );
+ FFData ffData = new FFData( data.getBinData(), 0 );
+
+ return Integer.valueOf( ffData.getDefaultDropDownItemIndex() );
+ }
+ }
+ return null;
+ }
+
}
diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/converter/TestWordToHtmlConverter.java b/src/scratchpad/testcases/org/apache/poi/hwpf/converter/TestWordToHtmlConverter.java
index 74be67b28d..6d748cd3cd 100644
--- a/src/scratchpad/testcases/org/apache/poi/hwpf/converter/TestWordToHtmlConverter.java
+++ b/src/scratchpad/testcases/org/apache/poi/hwpf/converter/TestWordToHtmlConverter.java
@@ -141,6 +141,14 @@ public class TestWordToHtmlConverter extends TestCase
getHtmlText( "Bug48075.doc" );
}
+ public void testBug52583() throws Exception
+ {
+ String result = getHtmlText( "Bug52583.doc" );
+ assertContains(
+ result,
+ "<select><option selected>riri</option><option>fifi</option><option>loulou</option></select>" );
+ }
+
public void testBug53182() throws Exception
{
String result = getHtmlText( "Bug53182.doc" );
diff --git a/src/types/definitions/FFData_type.xml b/src/types/definitions/FFData_type.xml
new file mode 100644
index 0000000000..2016adb6dd
--- /dev/null
+++ b/src/types/definitions/FFData_type.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0"?>
+<!--
+ ====================================================================
+ 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.
+ ====================================================================
+-->
+<record fromfile="true" name="FFDataBase" package="org.apache.poi.hwpf.model.types">
+ <suffix>AbstractType</suffix>
+ <description>The FFData structure specifies form field data for a text
+ box, check box, or drop-down list box. &lt;p&gt;Class and fields
+ descriptions are quoted from [MS-DOC] -- v20121003 Word (.doc) Binary
+ File Format; Copyright (c) 2012 Microsoft Corporation; Release:
+ October 8, 2012
+ </description>
+ <author>Sergey Vladimirov; according to [MS-DOC] -- v20121003 Word
+ (.doc) Binary File Format; Copyright (c) 2012 Microsoft Corporation;
+ Release: October 8, 2012
+ </author>
+ <fields>
+ <field type="long" size="4" name="version"
+ description="An unsigned integer that MUST be 0xFFFFFFFF" />
+ <field type="short" size="2" name="bits"
+ description="An FFDataBits that specifies the type and state of this form field">
+ <bit mask="0x0003" name="iType"
+ description="An unsigned integer that specifies the type of the form field. ">
+ <const type="byte" value="0" name="Text"
+ description="Specifies that the form field is a textbox." />
+ <const type="byte" value="1" name="Chck"
+ description="Specifies that the form field is a checkbox." />
+ <const type="byte" value="2" name="Drop"
+ description="Specifies that the form field is a dropdown list box." />
+ </bit>
+ <bit mask="0x007C" name="iRes"
+ description="An unsigned integer. If iType is iTypeText (0), then iRes MUST be 0. If iType is iTypeChck (1), iRes specifies the state of the checkbox and MUST be 0 (unchecked), 1 (checked), or 25 (undefined). Undefined checkboxes are treated as unchecked. If iType is iTypeDrop (2), iRes specifies the current selected list box item. A value of 25 specifies the selection is undefined. Otherwise, iRes is a zero-based index into FFData.hsttbDropList." />
+ <bit mask="0x0080" name="fOwnHelp"
+ description="A bit that specifies whether the form field has custom help text in FFData.xstzHelpText. If fOwnHelp is 0, FFData.xstzHelpText contains an empty or auto-generated string." />
+ <bit mask="0x0100" name="fOwnStat"
+ description="A bit that specifies whether the form field has custom status bar text in FFData.xstzStatText. If fOwnStat is 0, FFData.xstzStatText contains an empty or auto-generated string." />
+ <bit mask="0x0200" name="fProt"
+ description="A bit that specifies whether the form field is protected and its value cannot be changed." />
+ <bit mask="0x0400" name="iSize"
+ description="A bit that specifies whether the size of a checkbox is automatically determined by the text size where the checkbox is located. This value MUST be 0 if iType is not iTypeChck (1)." />
+ <bit mask="0x3800" name="iTypeTxt"
+ description="An unsigned integer that specifies the type of the textbox. If iType is not iTypeText (0), iTypeTxt MUST be 0 and MUST be ignored." >
+ <const type="byte" value="0" name="Reg"
+ description="Specifies that the textbox value is regular text." />
+ <const type="byte" value="0" name="Num"
+ description="Specifies that the textbox value is a number." />
+ <const type="byte" value="0" name="Date"
+ description="Specifies that the textbox value is a date or time." />
+ <const type="byte" value="0" name="CurDate"
+ description="Specifies that the textbox value is the current date." />
+ <const type="byte" value="0" name="CurTime"
+ description="Specifies that the textbox value is the current time." />
+ <const type="byte" value="0" name="Calc"
+ description="Specifies that the textbox value is calculated from an expression. The expression is given by FFData.xstzTextDef." />
+ </bit>
+ <bit mask="0x4000" name="fRecalc"
+ description="A bit that specifies whether the value of the field is automatically calculated after the field is modified." />
+ <bit mask="0x8000" name="fHasListBox"
+ description="A bit that specifies that the form field has a list box. This value MUST be 1 if iType is iTypeDrop (2). Otherwise, this value MUST be 0." />
+ </field>
+ <field type="int" size="2" name="cch"
+ description="An unsigned integer that specifies the maximum length, in characters, of the value of the textbox. This value MUST NOT exceed 32767. A value of 0 means there is no maximum length of the value of the textbox. If bits.iType is not iTypeText (0), this value MUST be 0." />
+ <field type="int" size="2" name="hps"
+ description="An unsigned integer. If bits.iType is iTypeChck (1), hps specifies the size, in half-points, of the checkbox and MUST be between 2 and 3168, inclusive. If bits.iType is not iTypeChck (1), hps is undefined and MUST be ignored." />
+ </fields>
+</record>
diff --git a/src/types/styles/hdftype.xsl b/src/types/styles/hdftype.xsl
index ab923d1921..d8c90e7523 100644
--- a/src/types/styles/hdftype.xsl
+++ b/src/types/styles/hdftype.xsl
@@ -352,10 +352,22 @@ public abstract class </xsl:text><xsl:call-template name="outputClassName"/><xsl
<xsl:value-of select="$fieldName"/>
<xsl:text>? 1231 : 1237 )</xsl:text>
</xsl:when>
- <xsl:when test="@type='byte' or @type='double' or @type='int' or @type='long' or @type='short'">
+ <xsl:when test="@type='byte' or @type='double' or @type='int' or @type='short'">
<xsl:text> + </xsl:text>
<xsl:value-of select="$fieldName"/>
</xsl:when>
+ <xsl:when test="@type='long'">
+ <xsl:call-template name="linebreak" />
+ <xsl:call-template name="indent" />
+ <xsl:call-template name="indent" />
+ <xsl:call-template name="indent" />
+ <xsl:call-template name="indent" />
+ <xsl:text> + (int) ( </xsl:text>
+ <xsl:value-of select="$fieldName"/>
+ <xsl:text> ^ ( </xsl:text>
+ <xsl:value-of select="$fieldName"/>
+ <xsl:text> >>> 32 ) )</xsl:text>
+ </xsl:when>
<xsl:otherwise>
<xsl:call-template name="linebreak" />
<xsl:call-template name="indent" />
@@ -440,27 +452,42 @@ public abstract class </xsl:text><xsl:call-template name="outputClassName"/><xsl
<xsl:value-of select="@mask"/>
<xsl:text>);</xsl:text>
<xsl:call-template name="linebreak"/>
+ <xsl:apply-templates select="const"/>
</xsl:template>
- <xsl:template match="const">
- <xsl:if test="@description">
- <xsl:call-template name="indent"/>
- <xsl:text>/** </xsl:text>
- <xsl:value-of select="@description"/>
- <xsl:text> */</xsl:text>
- <xsl:call-template name="linebreak"/>
- </xsl:if>
- <xsl:call-template name="indent"/>
- <xsl:text>/**/</xsl:text>
- <xsl:text>protected final static </xsl:text>
- <xsl:value-of select="@type"/>
- <xsl:text> </xsl:text>
- <xsl:value-of select="recutil:getConstName(../@name,@name,0)"/>
- <xsl:text> = </xsl:text>
- <xsl:value-of select="@value"/>
- <xsl:text>;</xsl:text>
- <xsl:call-template name="linebreak"/>
- </xsl:template>
+ <xsl:template match="const">
+ <xsl:if test="@description">
+ <xsl:call-template name="indent" />
+ <xsl:choose>
+ <xsl:when test="name(..) = 'bit'">
+ <xsl:text>/** </xsl:text>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:text>/** </xsl:text>
+ </xsl:otherwise>
+ </xsl:choose>
+ <xsl:value-of select="@description" />
+ <xsl:text> */</xsl:text>
+ <xsl:call-template name="linebreak" />
+ </xsl:if>
+ <xsl:call-template name="indent" />
+ <xsl:choose>
+ <xsl:when test="name(..) = 'bit'">
+ <xsl:text>/* */</xsl:text>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:text>/**/</xsl:text>
+ </xsl:otherwise>
+ </xsl:choose>
+ <xsl:text>protected final static </xsl:text>
+ <xsl:value-of select="@type" />
+ <xsl:text> </xsl:text>
+ <xsl:value-of select="recutil:getConstName(../@name,@name,0)" />
+ <xsl:text> = </xsl:text>
+ <xsl:value-of select="@value" />
+ <xsl:text>;</xsl:text>
+ <xsl:call-template name="linebreak" />
+ </xsl:template>
<xsl:template match="const" mode="listconsts">
<xsl:call-template name="linebreak"/>
diff --git a/test-data/document/Bug52583.doc b/test-data/document/Bug52583.doc
new file mode 100644
index 0000000000..b6e8646e6e
--- /dev/null
+++ b/test-data/document/Bug52583.doc
Binary files differ