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
This commit is contained in:
parent
110ef33b6e
commit
d8ca4323de
@ -34,6 +34,7 @@
|
|||||||
|
|
||||||
<changes>
|
<changes>
|
||||||
<release version="3.9-beta1" date="2012-??-??">
|
<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="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">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>
|
<action dev="poi-developers" type="fix">52311 - Conversion to html : Problem in titles number </action>
|
||||||
|
@ -167,6 +167,7 @@ public abstract class AbstractWordConverter
|
|||||||
}
|
}
|
||||||
structures.add( structure );
|
structures.add( structure );
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Set<Bookmark> bookmarkStack = new LinkedHashSet<Bookmark>();
|
private final Set<Bookmark> bookmarkStack = new LinkedHashSet<Bookmark>();
|
||||||
|
|
||||||
private FontReplacer fontReplacer = new DefaultFontReplacer();
|
private FontReplacer fontReplacer = new DefaultFontReplacer();
|
||||||
@ -778,6 +779,12 @@ public abstract class AbstractWordConverter
|
|||||||
CharacterRun characterRun, OfficeDrawing officeDrawing,
|
CharacterRun characterRun, OfficeDrawing officeDrawing,
|
||||||
String path, Element block );
|
String path, Element block );
|
||||||
|
|
||||||
|
protected void processDropDownList( Element block,
|
||||||
|
CharacterRun characterRun, String[] values, int defaultIndex )
|
||||||
|
{
|
||||||
|
outputCharacters( block, characterRun, values[defaultIndex] );
|
||||||
|
}
|
||||||
|
|
||||||
protected abstract void processEndnoteAutonumbered(
|
protected abstract void processEndnoteAutonumbered(
|
||||||
HWPFDocument wordDocument, int noteIndex, Element block,
|
HWPFDocument wordDocument, int noteIndex, Element block,
|
||||||
Range endnoteTextRange );
|
Range endnoteTextRange );
|
||||||
@ -835,6 +842,22 @@ public abstract class AbstractWordConverter
|
|||||||
|
|
||||||
break;
|
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
|
case 88: // hyperlink
|
||||||
{
|
{
|
||||||
final Range firstSubrange = field.firstSubrange( parentRange );
|
final Range firstSubrange = field.firstSubrange( parentRange );
|
||||||
@ -1011,12 +1034,6 @@ public abstract class AbstractWordConverter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void processSymbol( HWPFDocument doc, CharacterRun characterRun,
|
|
||||||
Element block )
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings( "unused" )
|
@SuppressWarnings( "unused" )
|
||||||
protected boolean processOle2( HWPFDocument wordDocument, Element block,
|
protected boolean processOle2( HWPFDocument wordDocument, Element block,
|
||||||
Entry entry ) throws Exception
|
Entry entry ) throws Exception
|
||||||
@ -1109,6 +1126,12 @@ public abstract class AbstractWordConverter
|
|||||||
processSection( wordDocument, section, 0 );
|
processSection( wordDocument, section, 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void processSymbol( HWPFDocument doc, CharacterRun characterRun,
|
||||||
|
Element block )
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
protected abstract void processTable( HWPFDocumentCore wordDocument,
|
protected abstract void processTable( HWPFDocumentCore wordDocument,
|
||||||
Element flow, Table table );
|
Element flow, Table table );
|
||||||
|
|
||||||
|
@ -161,11 +161,28 @@ public class HtmlDocumentFacade
|
|||||||
return document.createElement( "li" );
|
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()
|
public Element createParagraph()
|
||||||
{
|
{
|
||||||
return document.createElement( "p" );
|
return document.createElement( "p" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Element createSelect()
|
||||||
|
{
|
||||||
|
Element result = document.createElement( "select" );
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
public Element createTable()
|
public Element createTable()
|
||||||
{
|
{
|
||||||
return document.createElement( "table" );
|
return document.createElement( "table" );
|
||||||
|
@ -82,6 +82,7 @@ public class WordToHtmlConverter extends AbstractWordConverter
|
|||||||
private static final POILogger logger = POILogFactory
|
private static final POILogger logger = POILogFactory
|
||||||
.getLogger( WordToHtmlConverter.class );
|
.getLogger( WordToHtmlConverter.class );
|
||||||
|
|
||||||
|
|
||||||
private static String getSectionStyle( Section section )
|
private static String getSectionStyle( Section section )
|
||||||
{
|
{
|
||||||
float leftMargin = section.getMarginLeft() / TWIPS_PER_INCH;
|
float leftMargin = section.getMarginLeft() / TWIPS_PER_INCH;
|
||||||
@ -280,6 +281,19 @@ public class WordToHtmlConverter extends AbstractWordConverter
|
|||||||
afterProcess();
|
afterProcess();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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
|
@Override
|
||||||
protected void processDrawnObject( HWPFDocument doc,
|
protected void processDrawnObject( HWPFDocument doc,
|
||||||
CharacterRun characterRun, OfficeDrawing officeDrawing,
|
CharacterRun characterRun, OfficeDrawing officeDrawing,
|
||||||
|
214
src/scratchpad/src/org/apache/poi/hwpf/model/FFData.java
Normal file
214
src/scratchpad/src/org/apache/poi/hwpf/model/FFData.java
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
33
src/scratchpad/src/org/apache/poi/hwpf/model/FFDataBase.java
Normal file
33
src/scratchpad/src/org/apache/poi/hwpf/model/FFDataBase.java
Normal file
@ -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 );
|
||||||
|
}
|
||||||
|
}
|
@ -90,7 +90,8 @@ public final class FIBFieldHandler
|
|||||||
public static final int PLCFATNBKL = 43;
|
public static final int PLCFATNBKL = 43;
|
||||||
// 506 == 0x01FA; 510 == 0x01FE
|
// 506 == 0x01FA; 510 == 0x01FE
|
||||||
public static final int PMS = 44;
|
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 PLCFENDREF = 46;
|
||||||
public static final int PLCFENDTXT = 47;
|
public static final int PLCFENDTXT = 47;
|
||||||
public static final int PLCFFLDEDN = 48;
|
public static final int PLCFFLDEDN = 48;
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
232
src/scratchpad/src/org/apache/poi/hwpf/model/Sttb.java
Normal file
232
src/scratchpad/src/org/apache/poi/hwpf/model/Sttb.java
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -20,8 +20,6 @@ import java.io.IOException;
|
|||||||
|
|
||||||
import org.apache.poi.hwpf.model.io.HWPFOutputStream;
|
import org.apache.poi.hwpf.model.io.HWPFOutputStream;
|
||||||
import org.apache.poi.util.Internal;
|
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"
|
* Utils class for storing and reading "STring TaBle stored in File"
|
||||||
@ -32,180 +30,47 @@ import org.apache.poi.util.StringUtil;
|
|||||||
class SttbUtils
|
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_STTB_SAVED_BY = 2; // bytes
|
||||||
|
|
||||||
private static final int CDATA_SIZE_STTBF_BKMK = 2; // bytes
|
private static final int CDATA_SIZE_STTBF_BKMK = 2; // bytes
|
||||||
|
|
||||||
private static final int CDATA_SIZE_STTBF_R_MARK = 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 )
|
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 )
|
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 )
|
static String[] readSttbSavedBy( byte[] buffer, int startOffset )
|
||||||
{
|
{
|
||||||
return read( CDATA_SIZE_STTB_SAVED_BY, buffer, startOffset ).data;
|
return new Sttb( CDATA_SIZE_STTB_SAVED_BY, buffer, startOffset )
|
||||||
}
|
.getData();
|
||||||
|
|
||||||
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 );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void writeSttbfBkmk( String[] data, HWPFOutputStream tableStream )
|
static void writeSttbfBkmk( String[] data, HWPFOutputStream tableStream )
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
Sttb sttb = new Sttb();
|
tableStream.write( new Sttb( CDATA_SIZE_STTBF_BKMK, data ).serialize() );
|
||||||
sttb.cDataLength = CDATA_SIZE_STTBF_BKMK;
|
|
||||||
sttb.data = data;
|
|
||||||
sttb.cbExtra = CBEXTRA_STTBF_BKMK;
|
|
||||||
write( sttb, tableStream );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void writeSttbfRMark( String[] data, HWPFOutputStream tableStream )
|
static void writeSttbfRMark( String[] data, HWPFOutputStream tableStream )
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
Sttb sttb = new Sttb();
|
tableStream.write( new Sttb( CDATA_SIZE_STTBF_R_MARK, data )
|
||||||
sttb.cDataLength = CDATA_SIZE_STTBF_R_MARK;
|
.serialize() );
|
||||||
sttb.data = data;
|
|
||||||
sttb.cbExtra = CBEXTRA_STTBF_R_MARK;
|
|
||||||
write( sttb, tableStream );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void writeSttbSavedBy( String[] data, HWPFOutputStream tableStream )
|
static void writeSttbSavedBy( String[] data, HWPFOutputStream tableStream )
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
Sttb sttb = new Sttb();
|
tableStream.write( new Sttb( CDATA_SIZE_STTB_SAVED_BY, data )
|
||||||
sttb.cDataLength = CDATA_SIZE_STTB_SAVED_BY;
|
.serialize() );
|
||||||
sttb.data = data;
|
|
||||||
sttb.cbExtra = CBEXTRA_STTB_SAVED_BY;
|
|
||||||
write( sttb, tableStream );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
69
src/scratchpad/src/org/apache/poi/hwpf/model/Xstz.java
Normal file
69
src/scratchpad/src/org/apache/poi/hwpf/model/Xstz.java
Normal file
@ -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]";
|
||||||
|
}
|
||||||
|
}
|
@ -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
|
@ -180,16 +180,13 @@ public final class CharacterSprmUncompressor extends SprmUncompressor
|
|||||||
case 0x3:
|
case 0x3:
|
||||||
// sprmCPicLocation -- 0x6A03
|
// sprmCPicLocation -- 0x6A03
|
||||||
/*
|
/*
|
||||||
* Microsoft Office Word 97-2007 Binary File Format (.doc)
|
* [MS-DOC]
|
||||||
* Specification
|
|
||||||
*
|
*
|
||||||
* Page 75 of 210
|
* Page 104 of 622
|
||||||
*
|
*
|
||||||
* sprmCPicLocation (opcode 0x6A03) is used ONLY IN CHPX FKPs. This
|
* A signed 32-bit integer that specifies either the position in the
|
||||||
* sprm moves the 4-byte operand of the sprm into the chp.fcPic
|
* Data Stream of a picture or binary data or the name of an OLE
|
||||||
* field. It simultaneously sets chp.fSpec to 1. This sprm is also
|
* object storage.
|
||||||
* used when the chp.lTagObj field that is unioned with chp.fcPic is
|
|
||||||
* to be set for OLE objects.
|
|
||||||
*/
|
*/
|
||||||
newCHP.setFcPic( sprm.getOperand() );
|
newCHP.setFcPic( sprm.getOperand() );
|
||||||
newCHP.setFSpec( true );
|
newCHP.setFSpec( true );
|
||||||
|
@ -17,8 +17,11 @@
|
|||||||
|
|
||||||
package org.apache.poi.hwpf.usermodel;
|
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.CHPX;
|
||||||
|
import org.apache.poi.hwpf.model.FFData;
|
||||||
import org.apache.poi.hwpf.model.Ffn;
|
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.model.StyleSheet;
|
||||||
import org.apache.poi.hwpf.sprm.SprmBuffer;
|
import org.apache.poi.hwpf.sprm.SprmBuffer;
|
||||||
|
|
||||||
@ -631,4 +634,42 @@ public final class CharacterRun
|
|||||||
String text = text();
|
String text = text();
|
||||||
return "CharacterRun of " + text.length() + " characters - " + 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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -141,6 +141,14 @@ public class TestWordToHtmlConverter extends TestCase
|
|||||||
getHtmlText( "Bug48075.doc" );
|
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
|
public void testBug53182() throws Exception
|
||||||
{
|
{
|
||||||
String result = getHtmlText( "Bug53182.doc" );
|
String result = getHtmlText( "Bug53182.doc" );
|
||||||
|
81
src/types/definitions/FFData_type.xml
Normal file
81
src/types/definitions/FFData_type.xml
Normal file
@ -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. <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
|
||||||
|
</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>
|
@ -352,10 +352,22 @@ public abstract class </xsl:text><xsl:call-template name="outputClassName"/><xsl
|
|||||||
<xsl:value-of select="$fieldName"/>
|
<xsl:value-of select="$fieldName"/>
|
||||||
<xsl:text>? 1231 : 1237 )</xsl:text>
|
<xsl:text>? 1231 : 1237 )</xsl:text>
|
||||||
</xsl:when>
|
</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:text> + </xsl:text>
|
||||||
<xsl:value-of select="$fieldName"/>
|
<xsl:value-of select="$fieldName"/>
|
||||||
</xsl:when>
|
</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:otherwise>
|
||||||
<xsl:call-template name="linebreak" />
|
<xsl:call-template name="linebreak" />
|
||||||
<xsl:call-template name="indent" />
|
<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:value-of select="@mask"/>
|
||||||
<xsl:text>);</xsl:text>
|
<xsl:text>);</xsl:text>
|
||||||
<xsl:call-template name="linebreak"/>
|
<xsl:call-template name="linebreak"/>
|
||||||
|
<xsl:apply-templates select="const"/>
|
||||||
</xsl:template>
|
</xsl:template>
|
||||||
|
|
||||||
<xsl:template match="const">
|
<xsl:template match="const">
|
||||||
<xsl:if test="@description">
|
<xsl:if test="@description">
|
||||||
<xsl:call-template name="indent"/>
|
<xsl:call-template name="indent" />
|
||||||
<xsl:text>/** </xsl:text>
|
<xsl:choose>
|
||||||
<xsl:value-of select="@description"/>
|
<xsl:when test="name(..) = 'bit'">
|
||||||
<xsl:text> */</xsl:text>
|
<xsl:text>/** </xsl:text>
|
||||||
<xsl:call-template name="linebreak"/>
|
</xsl:when>
|
||||||
</xsl:if>
|
<xsl:otherwise>
|
||||||
<xsl:call-template name="indent"/>
|
<xsl:text>/** </xsl:text>
|
||||||
<xsl:text>/**/</xsl:text>
|
</xsl:otherwise>
|
||||||
<xsl:text>protected final static </xsl:text>
|
</xsl:choose>
|
||||||
<xsl:value-of select="@type"/>
|
<xsl:value-of select="@description" />
|
||||||
<xsl:text> </xsl:text>
|
<xsl:text> */</xsl:text>
|
||||||
<xsl:value-of select="recutil:getConstName(../@name,@name,0)"/>
|
<xsl:call-template name="linebreak" />
|
||||||
<xsl:text> = </xsl:text>
|
</xsl:if>
|
||||||
<xsl:value-of select="@value"/>
|
<xsl:call-template name="indent" />
|
||||||
<xsl:text>;</xsl:text>
|
<xsl:choose>
|
||||||
<xsl:call-template name="linebreak"/>
|
<xsl:when test="name(..) = 'bit'">
|
||||||
</xsl:template>
|
<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:template match="const" mode="listconsts">
|
||||||
<xsl:call-template name="linebreak"/>
|
<xsl:call-template name="linebreak"/>
|
||||||
|
BIN
test-data/document/Bug52583.doc
Normal file
BIN
test-data/document/Bug52583.doc
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user