]> source.dussan.org Git - poi.git/commitdiff
handle bullets lists correctly (i hope)
authorSergey Vladimirov <sergey@apache.org>
Sat, 1 Oct 2011 23:28:37 +0000 (23:28 +0000)
committerSergey Vladimirov <sergey@apache.org>
Sat, 1 Oct 2011 23:28:37 +0000 (23:28 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1178103 13f79535-47bb-0310-9956-ffa450edef68

src/scratchpad/src/org/apache/poi/hwpf/model/ListLevel.java

index a436433186711351f676ed541031ca3aeed6f41f..139aa4f75c6d2b16fbaab9e3fb29305335b88ed3 100644 (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;
     }