You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@poi.apache.org by se...@apache.org on 2012/11/06 17:26:44 UTC

svn commit: r1406208 - in /poi/trunk: src/documentation/content/xdocs/ src/scratchpad/src/org/apache/poi/hwpf/converter/ src/scratchpad/src/org/apache/poi/hwpf/model/ src/scratchpad/src/org/apache/poi/hwpf/model/types/ src/scratchpad/src/org/apache/poi...

Author: sergey
Date: Tue Nov  6 16:26:43 2012
New Revision: 1406208

URL: http://svn.apache.org/viewvc?rev=1406208&view=rev
Log:
Bug 52583 - Conversion to html : Problem with combobox

Added:
    poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/FFData.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/FFDataBase.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/NilPICFAndBinData.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/Sttb.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/Xstz.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/types/FFDataBaseAbstractType.java
    poi/trunk/src/types/definitions/FFData_type.xml
    poi/trunk/test-data/document/Bug52583.doc   (with props)
Modified:
    poi/trunk/src/documentation/content/xdocs/status.xml
    poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/converter/AbstractWordConverter.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/converter/HtmlDocumentFacade.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/converter/WordToHtmlConverter.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/FIBFieldHandler.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/SttbUtils.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/sprm/CharacterSprmUncompressor.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/usermodel/CharacterRun.java
    poi/trunk/src/scratchpad/testcases/org/apache/poi/hwpf/converter/TestWordToHtmlConverter.java
    poi/trunk/src/types/styles/hdftype.xsl

Modified: poi/trunk/src/documentation/content/xdocs/status.xml
URL: http://svn.apache.org/viewvc/poi/trunk/src/documentation/content/xdocs/status.xml?rev=1406208&r1=1406207&r2=1406208&view=diff
==============================================================================
--- poi/trunk/src/documentation/content/xdocs/status.xml (original)
+++ poi/trunk/src/documentation/content/xdocs/status.xml Tue Nov  6 16:26:43 2012
@@ -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>

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/converter/AbstractWordConverter.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/converter/AbstractWordConverter.java?rev=1406208&r1=1406207&r2=1406208&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/converter/AbstractWordConverter.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/converter/AbstractWordConverter.java Tue Nov  6 16:26:43 2012
@@ -167,6 +167,7 @@ public abstract class AbstractWordConver
         }
         structures.add( structure );
     }
+
     private final Set<Bookmark> bookmarkStack = new LinkedHashSet<Bookmark>();
 
     private FontReplacer fontReplacer = new DefaultFontReplacer();
@@ -778,6 +779,12 @@ public abstract class AbstractWordConver
             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 AbstractWordConver
 
             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 AbstractWordConver
             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 AbstractWordConver
         processSection( wordDocument, section, 0 );
     }
 
+    protected void processSymbol( HWPFDocument doc, CharacterRun characterRun,
+            Element block )
+    {
+
+    }
+
     protected abstract void processTable( HWPFDocumentCore wordDocument,
             Element flow, Table table );
 

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/converter/HtmlDocumentFacade.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/converter/HtmlDocumentFacade.java?rev=1406208&r1=1406207&r2=1406208&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/converter/HtmlDocumentFacade.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/converter/HtmlDocumentFacade.java Tue Nov  6 16:26:43 2012
@@ -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" );

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/converter/WordToHtmlConverter.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/converter/WordToHtmlConverter.java?rev=1406208&r1=1406207&r2=1406208&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/converter/WordToHtmlConverter.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/converter/WordToHtmlConverter.java Tue Nov  6 16:26:43 2012
@@ -82,6 +82,7 @@ public class WordToHtmlConverter extends
     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
     }
 
     @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 )

Added: poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/FFData.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/FFData.java?rev=1406208&view=auto
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/FFData.java (added)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/FFData.java Tue Nov  6 16:26:43 2012
@@ -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;
+    }
+}

Added: poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/FFDataBase.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/FFDataBase.java?rev=1406208&view=auto
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/FFDataBase.java (added)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/FFDataBase.java Tue Nov  6 16:26:43 2012
@@ -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 );
+    }
+}

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/FIBFieldHandler.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/FIBFieldHandler.java?rev=1406208&r1=1406207&r2=1406208&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/FIBFieldHandler.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/FIBFieldHandler.java Tue Nov  6 16:26:43 2012
@@ -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;

Added: poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/NilPICFAndBinData.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/NilPICFAndBinData.java?rev=1406208&view=auto
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/NilPICFAndBinData.java (added)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/NilPICFAndBinData.java Tue Nov  6 16:26:43 2012
@@ -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;
+    }
+}

Added: poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/Sttb.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/Sttb.java?rev=1406208&view=auto
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/Sttb.java (added)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/Sttb.java Tue Nov  6 16:26:43 2012
@@ -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;
+    }
+}

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/SttbUtils.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/SttbUtils.java?rev=1406208&r1=1406207&r2=1406208&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/SttbUtils.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/SttbUtils.java Tue Nov  6 16:26:43 2012
@@ -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() );
     }
 
 }

Added: poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/Xstz.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/Xstz.java?rev=1406208&view=auto
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/Xstz.java (added)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/Xstz.java Tue Nov  6 16:26:43 2012
@@ -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]";
+    }
+}

Added: poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/types/FFDataBaseAbstractType.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/types/FFDataBaseAbstractType.java?rev=1406208&view=auto
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/types/FFDataBaseAbstractType.java (added)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/types/FFDataBaseAbstractType.java Tue Nov  6 16:26:43 2012
@@ -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

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/sprm/CharacterSprmUncompressor.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/sprm/CharacterSprmUncompressor.java?rev=1406208&r1=1406207&r2=1406208&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/sprm/CharacterSprmUncompressor.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/sprm/CharacterSprmUncompressor.java Tue Nov  6 16:26:43 2012
@@ -180,16 +180,13 @@ public final class CharacterSprmUncompre
         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 );

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/usermodel/CharacterRun.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/usermodel/CharacterRun.java?rev=1406208&r1=1406207&r2=1406208&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/usermodel/CharacterRun.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/usermodel/CharacterRun.java Tue Nov  6 16:26:43 2012
@@ -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;
+    }
+
 }

Modified: poi/trunk/src/scratchpad/testcases/org/apache/poi/hwpf/converter/TestWordToHtmlConverter.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/testcases/org/apache/poi/hwpf/converter/TestWordToHtmlConverter.java?rev=1406208&r1=1406207&r2=1406208&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/testcases/org/apache/poi/hwpf/converter/TestWordToHtmlConverter.java (original)
+++ poi/trunk/src/scratchpad/testcases/org/apache/poi/hwpf/converter/TestWordToHtmlConverter.java Tue Nov  6 16:26:43 2012
@@ -141,6 +141,14 @@ public class TestWordToHtmlConverter ext
         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" );

Added: poi/trunk/src/types/definitions/FFData_type.xml
URL: http://svn.apache.org/viewvc/poi/trunk/src/types/definitions/FFData_type.xml?rev=1406208&view=auto
==============================================================================
--- poi/trunk/src/types/definitions/FFData_type.xml (added)
+++ poi/trunk/src/types/definitions/FFData_type.xml Tue Nov  6 16:26:43 2012
@@ -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>

Modified: poi/trunk/src/types/styles/hdftype.xsl
URL: http://svn.apache.org/viewvc/poi/trunk/src/types/styles/hdftype.xsl?rev=1406208&r1=1406207&r2=1406208&view=diff
==============================================================================
--- poi/trunk/src/types/styles/hdftype.xsl (original)
+++ poi/trunk/src/types/styles/hdftype.xsl Tue Nov  6 16:26:43 2012
@@ -352,10 +352,22 @@ public abstract class </xsl:text><xsl:ca
                 <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:ca
         <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"/>

Added: poi/trunk/test-data/document/Bug52583.doc
URL: http://svn.apache.org/viewvc/poi/trunk/test-data/document/Bug52583.doc?rev=1406208&view=auto
==============================================================================
Binary file - no diff available.

Propchange: poi/trunk/test-data/document/Bug52583.doc
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@poi.apache.org
For additional commands, e-mail: commits-help@poi.apache.org