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:
Sergey Vladimirov 2012-11-06 16:26:43 +00:00
parent 110ef33b6e
commit d8ca4323de
18 changed files with 1290 additions and 180 deletions

View File

@ -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>

View File

@ -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 );
@ -1011,12 +1034,6 @@ public abstract class AbstractWordConverter
}
}
protected void processSymbol( HWPFDocument doc, CharacterRun characterRun,
Element block )
{
}
@SuppressWarnings( "unused" )
protected boolean processOle2( HWPFDocument wordDocument, Element block,
Entry entry ) throws Exception
@ -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 );

View File

@ -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" );

View File

@ -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,

View 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;
}
}

View 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 );
}
}

View File

@ -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;

View File

@ -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;
}
}

View 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;
}
}

View File

@ -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() );
}
}

View 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]";
}
}

View File

@ -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

View File

@ -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 );

View File

@ -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;
}
}

View File

@ -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" );

View 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. &lt;p&gt;Class and fields
descriptions are quoted from [MS-DOC] -- v20121003 Word (.doc) Binary
File Format; Copyright (c) 2012 Microsoft Corporation; Release:
October 8, 2012
</description>
<author>Sergey Vladimirov; according to [MS-DOC] -- v20121003 Word
(.doc) Binary File Format; Copyright (c) 2012 Microsoft Corporation;
Release: October 8, 2012
</author>
<fields>
<field type="long" size="4" name="version"
description="An unsigned integer that MUST be 0xFFFFFFFF" />
<field type="short" size="2" name="bits"
description="An FFDataBits that specifies the type and state of this form field">
<bit mask="0x0003" name="iType"
description="An unsigned integer that specifies the type of the form field. ">
<const type="byte" value="0" name="Text"
description="Specifies that the form field is a textbox." />
<const type="byte" value="1" name="Chck"
description="Specifies that the form field is a checkbox." />
<const type="byte" value="2" name="Drop"
description="Specifies that the form field is a dropdown list box." />
</bit>
<bit mask="0x007C" name="iRes"
description="An unsigned integer. If iType is iTypeText (0), then iRes MUST be 0. If iType is iTypeChck (1), iRes specifies the state of the checkbox and MUST be 0 (unchecked), 1 (checked), or 25 (undefined). Undefined checkboxes are treated as unchecked. If iType is iTypeDrop (2), iRes specifies the current selected list box item. A value of 25 specifies the selection is undefined. Otherwise, iRes is a zero-based index into FFData.hsttbDropList." />
<bit mask="0x0080" name="fOwnHelp"
description="A bit that specifies whether the form field has custom help text in FFData.xstzHelpText. If fOwnHelp is 0, FFData.xstzHelpText contains an empty or auto-generated string." />
<bit mask="0x0100" name="fOwnStat"
description="A bit that specifies whether the form field has custom status bar text in FFData.xstzStatText. If fOwnStat is 0, FFData.xstzStatText contains an empty or auto-generated string." />
<bit mask="0x0200" name="fProt"
description="A bit that specifies whether the form field is protected and its value cannot be changed." />
<bit mask="0x0400" name="iSize"
description="A bit that specifies whether the size of a checkbox is automatically determined by the text size where the checkbox is located. This value MUST be 0 if iType is not iTypeChck (1)." />
<bit mask="0x3800" name="iTypeTxt"
description="An unsigned integer that specifies the type of the textbox. If iType is not iTypeText (0), iTypeTxt MUST be 0 and MUST be ignored." >
<const type="byte" value="0" name="Reg"
description="Specifies that the textbox value is regular text." />
<const type="byte" value="0" name="Num"
description="Specifies that the textbox value is a number." />
<const type="byte" value="0" name="Date"
description="Specifies that the textbox value is a date or time." />
<const type="byte" value="0" name="CurDate"
description="Specifies that the textbox value is the current date." />
<const type="byte" value="0" name="CurTime"
description="Specifies that the textbox value is the current time." />
<const type="byte" value="0" name="Calc"
description="Specifies that the textbox value is calculated from an expression. The expression is given by FFData.xstzTextDef." />
</bit>
<bit mask="0x4000" name="fRecalc"
description="A bit that specifies whether the value of the field is automatically calculated after the field is modified." />
<bit mask="0x8000" name="fHasListBox"
description="A bit that specifies that the form field has a list box. This value MUST be 1 if iType is iTypeDrop (2). Otherwise, this value MUST be 0." />
</field>
<field type="int" size="2" name="cch"
description="An unsigned integer that specifies the maximum length, in characters, of the value of the textbox. This value MUST NOT exceed 32767. A value of 0 means there is no maximum length of the value of the textbox. If bits.iType is not iTypeText (0), this value MUST be 0." />
<field type="int" size="2" name="hps"
description="An unsigned integer. If bits.iType is iTypeChck (1), hps specifies the size, in half-points, of the checkbox and MUST be between 2 and 3168, inclusive. If bits.iType is not iTypeChck (1), hps is undefined and MUST be ignored." />
</fields>
</record>

View File

@ -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"/>

Binary file not shown.