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 35299804d7
commit 23ce993f61
1 changed files with 71 additions and 34 deletions

View File

@ -21,19 +21,29 @@ import java.util.Arrays;
import org.apache.poi.util.Internal; import org.apache.poi.util.Internal;
import org.apache.poi.util.LittleEndian; import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
/** /**
* "List LeVeL (on File) (LVLF)" * "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
* See page 170 for details. * 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 @Internal
public final class ListLevel public final class ListLevel
{ {
private static final POILogger logger = POILogFactory.getLogger( ListLevel.class );
private byte[] _grpprlChpx; private byte[] _grpprlChpx;
private byte[] _grpprlPapx; private byte[] _grpprlPapx;
private LVLF _lvlf; private LVLF _lvlf;
private char[] _numberText = null; private char[] _xst = {};
public ListLevel( final byte[] buf, final int originalOffset ) public ListLevel( final byte[] buf, final int originalOffset )
{ {
@ -50,20 +60,49 @@ public final class ListLevel
System.arraycopy( buf, offset, _grpprlChpx, 0, _lvlf.getCbGrpprlChpx() ); System.arraycopy( buf, offset, _grpprlChpx, 0, _lvlf.getCbGrpprlChpx() );
offset += _lvlf.getCbGrpprlChpx(); offset += _lvlf.getCbGrpprlChpx();
int numberTextLength = LittleEndian.getShort( buf, offset ); /*
/* sometimes numberTextLength<0 */ * "If this level uses bullets (see lvlf.nfc), the cch field of this Xst
/* by derjohng */ * MUST be equal to 0x0001, and this MUST NOT contain any placeholders."
if ( numberTextLength > 0 ) * -- 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; offset += LittleEndian.SHORT_SIZE;
for ( int x = 0; x < numberTextLength; x++ )
if ( numberTextLength != 1 )
{ {
_numberText[x] = (char) LittleEndian.getShort( buf, offset ); logger.log( POILogger.WARN, "LVL at offset ",
offset += LittleEndian.SHORT_SIZE; 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 ) public ListLevel( int level, boolean numbered )
@ -72,16 +111,15 @@ public final class ListLevel
setStartAt( 1 ); setStartAt( 1 );
_grpprlPapx = new byte[0]; _grpprlPapx = new byte[0];
_grpprlChpx = new byte[0]; _grpprlChpx = new byte[0];
_numberText = new char[0];
if ( numbered ) if ( numbered )
{ {
_lvlf.getRgbxchNums()[0] = 1; _lvlf.getRgbxchNums()[0] = 1;
_numberText = new char[] { (char) level, '.' }; _xst = new char[] { (char) level, '.' };
} }
else else
{ {
_numberText = new char[] { '\u2022' }; _xst = new char[] { '\u2022' };
} }
} }
@ -94,7 +132,7 @@ public final class ListLevel
_lvlf.setJc( (byte) alignment ); _lvlf.setJc( (byte) alignment );
_grpprlChpx = numberProperties; _grpprlChpx = numberProperties;
_grpprlPapx = entryProperties; _grpprlPapx = entryProperties;
_numberText = numberText.toCharArray(); _xst = numberText.toCharArray();
} }
public boolean equals( Object obj ) public boolean equals( Object obj )
@ -106,7 +144,7 @@ public final class ListLevel
return lvl._lvlf.equals( this._lvlf ) return lvl._lvlf.equals( this._lvlf )
&& Arrays.equals( lvl._grpprlChpx, _grpprlChpx ) && Arrays.equals( lvl._grpprlChpx, _grpprlChpx )
&& Arrays.equals( lvl._grpprlPapx, _grpprlPapx ) && 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() public String getNumberText()
{ {
if ( _numberText == null ) if ( _xst.length < 2 )
return null; return null;
return new String( _numberText ); return new String( _xst, 0, _xst.length - 1 );
} }
public int getSizeInBytes() public int getSizeInBytes()
{ {
int result = LVLF.getSize() + _lvlf.getCbGrpprlChpx() return LVLF.getSize() + _lvlf.getCbGrpprlChpx()
+ _lvlf.getCbGrpprlPapx() + 2; // numberText length + _lvlf.getCbGrpprlPapx() + LittleEndian.SHORT_SIZE
if ( _numberText != null ) + _xst.length * LittleEndian.SHORT_SIZE;
{
result += _numberText.length * LittleEndian.SHORT_SIZE;
}
return result;
} }
public int getStartAt() public int getStartAt()
@ -190,7 +224,6 @@ public final class ListLevel
public void setNumberProperties( byte[] grpprl ) public void setNumberProperties( byte[] grpprl )
{ {
_grpprlChpx = grpprl; _grpprlChpx = grpprl;
} }
public void setStartAt( int startAt ) public void setStartAt( int startAt )
@ -218,21 +251,25 @@ public final class ListLevel
System.arraycopy( _grpprlChpx, 0, buf, offset, _grpprlChpx.length ); System.arraycopy( _grpprlChpx, 0, buf, offset, _grpprlChpx.length );
offset += _grpprlChpx.length; offset += _grpprlChpx.length;
if ( _numberText == null ) if ( _lvlf.getNfc() == 0x17 )
{ {
// TODO - write junit to test this flow LittleEndian.putUShort( buf, offset, 1 );
LittleEndian.putUShort( buf, offset, 0 ); offset += LittleEndian.SHORT_SIZE;
LittleEndian.putUShort( buf, offset, _xst[0] );
offset += LittleEndian.SHORT_SIZE;
} }
else else
{ {
LittleEndian.putUShort( buf, offset, _numberText.length ); LittleEndian.putUShort( buf, offset, _xst.length );
offset += LittleEndian.SHORT_SIZE; 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; offset += LittleEndian.SHORT_SIZE;
} }
} }
return buf; return buf;
} }