From 23ce993f61f3ba98036f8718f038a2c15dba6753 Mon Sep 17 00:00:00 2001 From: Sergey Vladimirov Date: Sat, 1 Oct 2011 23:28:37 +0000 Subject: [PATCH] handle bullets lists correctly (i hope) git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1178103 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/poi/hwpf/model/ListLevel.java | 103 ++++++++++++------ 1 file changed, 70 insertions(+), 33 deletions(-) diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/ListLevel.java b/src/scratchpad/src/org/apache/poi/hwpf/model/ListLevel.java index a436433186..139aa4f75c 100644 --- a/src/scratchpad/src/org/apache/poi/hwpf/model/ListLevel.java +++ b/src/scratchpad/src/org/apache/poi/hwpf/model/ListLevel.java @@ -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; } -- 2.39.5