git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1406208 13f79535-47bb-0310-9956-ffa450edef68tags/3.10-beta1
@@ -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> |
@@ -167,6 +167,7 @@ public abstract class AbstractWordConverter | |||
} | |||
structures.add( structure ); | |||
} | |||
private final Set<Bookmark> bookmarkStack = new LinkedHashSet<Bookmark>(); | |||
private FontReplacer fontReplacer = new DefaultFontReplacer(); | |||
@@ -778,6 +779,12 @@ public abstract class AbstractWordConverter | |||
CharacterRun characterRun, OfficeDrawing officeDrawing, | |||
String path, Element block ); | |||
protected void processDropDownList( Element block, | |||
CharacterRun characterRun, String[] values, int defaultIndex ) | |||
{ | |||
outputCharacters( block, characterRun, values[defaultIndex] ); | |||
} | |||
protected abstract void processEndnoteAutonumbered( | |||
HWPFDocument wordDocument, int noteIndex, Element block, | |||
Range endnoteTextRange ); | |||
@@ -835,6 +842,22 @@ public abstract class AbstractWordConverter | |||
break; | |||
} | |||
case 83: // drop down | |||
{ | |||
Range fieldContent = field.firstSubrange( parentRange ); | |||
CharacterRun cr = fieldContent.getCharacterRun( fieldContent | |||
.numCharacterRuns() - 1 ); | |||
String[] values = cr.getDropDownListValues(); | |||
Integer defIndex = cr.getDropDownListDefaultItemIndex(); | |||
if ( values != null ) | |||
{ | |||
processDropDownList( currentBlock, cr, values, | |||
defIndex == null ? -1 : defIndex.intValue() ); | |||
return; | |||
} | |||
break; | |||
} | |||
case 88: // hyperlink | |||
{ | |||
final Range firstSubrange = field.firstSubrange( parentRange ); | |||
@@ -1010,12 +1033,6 @@ public abstract class AbstractWordConverter | |||
return false; | |||
} | |||
} | |||
protected void processSymbol( HWPFDocument doc, CharacterRun characterRun, | |||
Element block ) | |||
{ | |||
} | |||
@SuppressWarnings( "unused" ) | |||
protected boolean processOle2( HWPFDocument wordDocument, Element block, | |||
@@ -1109,6 +1126,12 @@ public abstract class AbstractWordConverter | |||
processSection( wordDocument, section, 0 ); | |||
} | |||
protected void processSymbol( HWPFDocument doc, CharacterRun characterRun, | |||
Element block ) | |||
{ | |||
} | |||
protected abstract void processTable( HWPFDocumentCore wordDocument, | |||
Element flow, Table table ); | |||
@@ -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" ); |
@@ -82,6 +82,7 @@ public class WordToHtmlConverter extends AbstractWordConverter | |||
private static final POILogger logger = POILogFactory | |||
.getLogger( WordToHtmlConverter.class ); | |||
private static String getSectionStyle( Section section ) | |||
{ | |||
float leftMargin = section.getMarginLeft() / TWIPS_PER_INCH; | |||
@@ -280,6 +281,19 @@ public class WordToHtmlConverter extends AbstractWordConverter | |||
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 | |||
protected void processDrawnObject( HWPFDocument doc, | |||
CharacterRun characterRun, OfficeDrawing officeDrawing, |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
// 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; |
@@ -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; | |||
} | |||
} |
@@ -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.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() ); | |||
} | |||
} |
@@ -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: | |||
// 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 ); |
@@ -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; | |||
} | |||
} |
@@ -141,6 +141,14 @@ public class TestWordToHtmlConverter extends TestCase | |||
getHtmlText( "Bug48075.doc" ); | |||
} | |||
public void testBug52583() throws Exception | |||
{ | |||
String result = getHtmlText( "Bug52583.doc" ); | |||
assertContains( | |||
result, | |||
"<select><option selected>riri</option><option>fifi</option><option>loulou</option></select>" ); | |||
} | |||
public void testBug53182() throws Exception | |||
{ | |||
String result = getHtmlText( "Bug53182.doc" ); |
@@ -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:text>? 1231 : 1237 )</xsl:text> | |||
</xsl:when> | |||
<xsl:when test="@type='byte' or @type='double' or @type='int' or @type='long' or @type='short'"> | |||
<xsl:when test="@type='byte' or @type='double' or @type='int' or @type='short'"> | |||
<xsl:text> + </xsl:text> | |||
<xsl:value-of select="$fieldName"/> | |||
</xsl:when> | |||
<xsl:when test="@type='long'"> | |||
<xsl:call-template name="linebreak" /> | |||
<xsl:call-template name="indent" /> | |||
<xsl:call-template name="indent" /> | |||
<xsl:call-template name="indent" /> | |||
<xsl:call-template name="indent" /> | |||
<xsl:text> + (int) ( </xsl:text> | |||
<xsl:value-of select="$fieldName"/> | |||
<xsl:text> ^ ( </xsl:text> | |||
<xsl:value-of select="$fieldName"/> | |||
<xsl:text> >>> 32 ) )</xsl:text> | |||
</xsl:when> | |||
<xsl:otherwise> | |||
<xsl:call-template name="linebreak" /> | |||
<xsl:call-template name="indent" /> | |||
@@ -440,27 +452,42 @@ public abstract class </xsl:text><xsl:call-template name="outputClassName"/><xsl | |||
<xsl:value-of select="@mask"/> | |||
<xsl:text>);</xsl:text> | |||
<xsl:call-template name="linebreak"/> | |||
<xsl:apply-templates select="const"/> | |||
</xsl:template> | |||
<xsl:template match="const"> | |||
<xsl:if test="@description"> | |||
<xsl:call-template name="indent"/> | |||
<xsl:text>/** </xsl:text> | |||
<xsl:value-of select="@description"/> | |||
<xsl:text> */</xsl:text> | |||
<xsl:call-template name="linebreak"/> | |||
</xsl:if> | |||
<xsl:call-template name="indent"/> | |||
<xsl:text>/**/</xsl:text> | |||
<xsl:text>protected final static </xsl:text> | |||
<xsl:value-of select="@type"/> | |||
<xsl:text> </xsl:text> | |||
<xsl:value-of select="recutil:getConstName(../@name,@name,0)"/> | |||
<xsl:text> = </xsl:text> | |||
<xsl:value-of select="@value"/> | |||
<xsl:text>;</xsl:text> | |||
<xsl:call-template name="linebreak"/> | |||
</xsl:template> | |||
<xsl:template match="const"> | |||
<xsl:if test="@description"> | |||
<xsl:call-template name="indent" /> | |||
<xsl:choose> | |||
<xsl:when test="name(..) = 'bit'"> | |||
<xsl:text>/** </xsl:text> | |||
</xsl:when> | |||
<xsl:otherwise> | |||
<xsl:text>/** </xsl:text> | |||
</xsl:otherwise> | |||
</xsl:choose> | |||
<xsl:value-of select="@description" /> | |||
<xsl:text> */</xsl:text> | |||
<xsl:call-template name="linebreak" /> | |||
</xsl:if> | |||
<xsl:call-template name="indent" /> | |||
<xsl:choose> | |||
<xsl:when test="name(..) = 'bit'"> | |||
<xsl:text>/* */</xsl:text> | |||
</xsl:when> | |||
<xsl:otherwise> | |||
<xsl:text>/**/</xsl:text> | |||
</xsl:otherwise> | |||
</xsl:choose> | |||
<xsl:text>protected final static </xsl:text> | |||
<xsl:value-of select="@type" /> | |||
<xsl:text> </xsl:text> | |||
<xsl:value-of select="recutil:getConstName(../@name,@name,0)" /> | |||
<xsl:text> = </xsl:text> | |||
<xsl:value-of select="@value" /> | |||
<xsl:text>;</xsl:text> | |||
<xsl:call-template name="linebreak" /> | |||
</xsl:template> | |||
<xsl:template match="const" mode="listconsts"> | |||
<xsl:call-template name="linebreak"/> |