import org.apache.poi.util.Internal;
import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.POILogFactory;
+import org.apache.poi.util.POILogger;
/**
- * "List LeVeL (on File) (LVLF)"
- *
- * See page 170 for details.
+ * "The LVL structure contains formatting information about a specific level in
+ * a list. When a paragraph is formatted as part of this level, each placeholder
+ * in xst is replaced with the inherited level number of the most recent or
+ * current paragraph in the same list that is in the zero-based level specified
+ * by that placeholder. The level number that replaces a placeholder is
+ * formatted according to the lvlf.nfc of the LVL structure that corresponds to
+ * the level that the placeholder specifies, unless the lvlf.fLegal of this LVL
+ * structure is nonzero." -- Page 388 of 621 -- [MS-DOC] -- v20110315 Word
+ * (.doc) Binary File Format
*/
@Internal
public final class ListLevel
{
+ private static final POILogger logger = POILogFactory.getLogger( ListLevel.class );
+
private byte[] _grpprlChpx;
private byte[] _grpprlPapx;
private LVLF _lvlf;
- private char[] _numberText = null;
+ private char[] _xst = {};
public ListLevel( final byte[] buf, final int originalOffset )
{
System.arraycopy( buf, offset, _grpprlChpx, 0, _lvlf.getCbGrpprlChpx() );
offset += _lvlf.getCbGrpprlChpx();
- int numberTextLength = LittleEndian.getShort( buf, offset );
- /* sometimes numberTextLength<0 */
- /* by derjohng */
- if ( numberTextLength > 0 )
+ /*
+ * "If this level uses bullets (see lvlf.nfc), the cch field of this Xst
+ * MUST be equal to 0x0001, and this MUST NOT contain any placeholders."
+ * -- page 389 of 621 -- [MS-DOC] -- v20110315 Word (.doc) Binary File
+ * Format
+ */
+ if ( _lvlf.getNfc() == 0x17 )
{
- _numberText = new char[numberTextLength];
+ int numberTextLength = LittleEndian.getShort( buf, offset );
offset += LittleEndian.SHORT_SIZE;
- for ( int x = 0; x < numberTextLength; x++ )
+
+ if ( numberTextLength != 1 )
{
- _numberText[x] = (char) LittleEndian.getShort( buf, offset );
- offset += LittleEndian.SHORT_SIZE;
+ logger.log( POILogger.WARN, "LVL at offset ",
+ Integer.valueOf( originalOffset ),
+ " has nfc == 0x17 (bullets), but cch != 1 (",
+ Integer.valueOf( numberTextLength ), ")" );
}
+
+ _xst = new char[] { (char) LittleEndian.getShort( buf, offset ) };
+ offset += LittleEndian.SHORT_SIZE;
}
+ else
+ {
+ int numberTextLength = LittleEndian.getShort( buf, offset );
+ offset += LittleEndian.SHORT_SIZE;
+ if ( numberTextLength > 0 )
+ {
+ _xst = new char[numberTextLength];
+ for ( int x = 0; x < numberTextLength; x++ )
+ {
+ _xst[x] = (char) LittleEndian.getShort( buf, offset );
+ offset += LittleEndian.SHORT_SIZE;
+ }
+ }
+ else
+ {
+ /* sometimes numberTextLength<0 */
+ /* by derjohng */
+ _xst = new char[] {};
+ }
+ }
}
public ListLevel( int level, boolean numbered )
setStartAt( 1 );
_grpprlPapx = new byte[0];
_grpprlChpx = new byte[0];
- _numberText = new char[0];
if ( numbered )
{
_lvlf.getRgbxchNums()[0] = 1;
- _numberText = new char[] { (char) level, '.' };
+ _xst = new char[] { (char) level, '.' };
}
else
{
- _numberText = new char[] { '\u2022' };
+ _xst = new char[] { '\u2022' };
}
}
_lvlf.setJc( (byte) alignment );
_grpprlChpx = numberProperties;
_grpprlPapx = entryProperties;
- _numberText = numberText.toCharArray();
+ _xst = numberText.toCharArray();
}
public boolean equals( Object obj )
return lvl._lvlf.equals( this._lvlf )
&& Arrays.equals( lvl._grpprlChpx, _grpprlChpx )
&& Arrays.equals( lvl._grpprlPapx, _grpprlPapx )
- && Arrays.equals( lvl._numberText, _numberText );
+ && Arrays.equals( lvl._xst, _xst );
}
/**
public String getNumberText()
{
- if ( _numberText == null )
+ if ( _xst.length < 2 )
return null;
- return new String( _numberText );
+ return new String( _xst, 0, _xst.length - 1 );
}
public int getSizeInBytes()
{
- int result = LVLF.getSize() + _lvlf.getCbGrpprlChpx()
- + _lvlf.getCbGrpprlPapx() + 2; // numberText length
- if ( _numberText != null )
- {
- result += _numberText.length * LittleEndian.SHORT_SIZE;
- }
- return result;
+ return LVLF.getSize() + _lvlf.getCbGrpprlChpx()
+ + _lvlf.getCbGrpprlPapx() + LittleEndian.SHORT_SIZE
+ + _xst.length * LittleEndian.SHORT_SIZE;
}
public int getStartAt()
public void setNumberProperties( byte[] grpprl )
{
_grpprlChpx = grpprl;
-
}
public void setStartAt( int startAt )
System.arraycopy( _grpprlChpx, 0, buf, offset, _grpprlChpx.length );
offset += _grpprlChpx.length;
- if ( _numberText == null )
+ if ( _lvlf.getNfc() == 0x17 )
{
- // TODO - write junit to test this flow
- LittleEndian.putUShort( buf, offset, 0 );
+ LittleEndian.putUShort( buf, offset, 1 );
+ offset += LittleEndian.SHORT_SIZE;
+
+ LittleEndian.putUShort( buf, offset, _xst[0] );
+ offset += LittleEndian.SHORT_SIZE;
}
else
{
- LittleEndian.putUShort( buf, offset, _numberText.length );
+ LittleEndian.putUShort( buf, offset, _xst.length );
offset += LittleEndian.SHORT_SIZE;
- for ( int x = 0; x < _numberText.length; x++ )
+ for ( char c : _xst )
{
- LittleEndian.putUShort( buf, offset, _numberText[x] );
+ LittleEndian.putUShort( buf, offset, c );
offset += LittleEndian.SHORT_SIZE;
}
}
+
return buf;
}