handle bullets lists correctly (i hope)

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1178103 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Sergey Vladimirov 2011-10-01 23:28:37 +00:00
parent 69e7860bcc
commit 5041b7b215

View File

@ -21,19 +21,29 @@ import java.util.Arrays;
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 )
{
@ -50,20 +60,49 @@ public final class ListLevel
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 )
@ -72,16 +111,15 @@ public final class ListLevel
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' };
}
}
@ -94,7 +132,7 @@ public final class ListLevel
_lvlf.setJc( (byte) alignment );
_grpprlChpx = numberProperties;
_grpprlPapx = entryProperties;
_numberText = numberText.toCharArray();
_xst = numberText.toCharArray();
}
public boolean equals( Object obj )
@ -106,7 +144,7 @@ public final class ListLevel
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 );
}
/**
@ -142,21 +180,17 @@ public final class ListLevel
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()
@ -190,7 +224,6 @@ public final class ListLevel
public void setNumberProperties( byte[] grpprl )
{
_grpprlChpx = grpprl;
}
public void setStartAt( int startAt )
@ -218,21 +251,25 @@ public final class ListLevel
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;
}