]> source.dussan.org Git - poi.git/commitdiff
52311 - Conversion to html : Problem in titles number
authorSergey Vladimirov <sergey@apache.org>
Mon, 5 Nov 2012 14:38:12 +0000 (14:38 +0000)
committerSergey Vladimirov <sergey@apache.org>
Mon, 5 Nov 2012 14:38:12 +0000 (14:38 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1405808 13f79535-47bb-0310-9956-ffa450edef68

src/documentation/content/xdocs/status.xml
src/scratchpad/src/org/apache/poi/hwpf/converter/AbstractWordUtils.java
src/scratchpad/src/org/apache/poi/hwpf/model/types/GrfhicAbstractType.java
src/scratchpad/src/org/apache/poi/hwpf/model/types/LFOAbstractType.java
src/scratchpad/src/org/apache/poi/hwpf/usermodel/HWPFList.java
src/scratchpad/testcases/org/apache/poi/hwpf/converter/TestWordToTextConverter.java
src/types/styles/hdftype.xsl
test-data/document/Bug52311.doc [new file with mode: 0644]

index f1b386fb232f5e11514d79569930c49152212620..bfbabdf77b693df0775d31347794ae47715cd56e 100644 (file)
@@ -34,6 +34,7 @@
 
     <changes>
         <release version="3.9-beta1" date="2012-??-??">
+          <action dev="poi-developers" type="fix">52311 - Conversion to html : Problem in titles number </action>
           <action dev="poi-developers" type="fix">53914 - TableRow#getTopBorder() return bottom's border</action>
           <action dev="poi-developers" type="fix">53282 - Avoid exception when parsing OPC relationships with non-breaking spaces</action>
           <action dev="poi-developers" type="fix">54016 - Avoid exception when parsing workbooks with DConRefRecord in row aggregate</action>
index 83fe7987ae566ed814782592f026a6bd642c4f00..89ac7e5634d42b1580a9257bf8a1d8676ec15868 100644 (file)
@@ -226,13 +226,15 @@ public class AbstractWordUtils
         return stringBuilder.toString();
     }
 
-    public static class NumberingState {
-        
+    public static class NumberingState
+    {
+
         private final Map<String, Integer> levels = new HashMap<String, Integer>();
-        
+
     }
-    
-    public static String getBulletText(NumberingState numberingState, HWPFList list, char level )
+
+    public static String getBulletText( NumberingState numberingState,
+            HWPFList list, char level )
     {
         StringBuffer bulletBuffer = new StringBuffer();
         char[] xst = list.getNumberText( level ).toCharArray();
@@ -240,25 +242,38 @@ public class AbstractWordUtils
         {
             if ( element < 9 )
             {
-                final String key = list.getLsid() + "#" + ( (int) element );
+                int lsid = list.getLsid();
+                final String key = lsid + "#" + ( (int) element );
                 int num;
-                if ( numberingState.levels.containsKey( key ) )
+
+                if ( !list.isStartAtOverriden( element )
+                        && numberingState.levels.containsKey( key ) )
                 {
                     num = numberingState.levels.get( key ).intValue();
+                    if ( level == element )
+                    {
+                        num++;
+                        numberingState.levels.put( key, Integer.valueOf( num ) );
+                    }
                 }
                 else
                 {
-                    num = list.getStartAt( level );
+                    num = list.getStartAt( element );
                     numberingState.levels.put( key, Integer.valueOf( num ) );
                 }
 
-                bulletBuffer.append( NumberFormatter.getNumber( num,
-                        list.getNumberFormat( level ) ) );
-
                 if ( level == element )
                 {
-                    numberingState.levels.put( key, Integer.valueOf( num + 1 ) );
+                    // cleaning states of nested levels to reset numbering
+                    for ( int i = element + 1; i < 9; i++ )
+                    {
+                        final String childKey = lsid + "#" + i;
+                        numberingState.levels.remove( childKey );
+                    }
                 }
+                
+                bulletBuffer.append( NumberFormatter.getNumber( num,
+                        list.getNumberFormat( level ) ) );
             }
             else
             {
@@ -266,7 +281,7 @@ public class AbstractWordUtils
             }
         }
 
-        byte follow = list.getTypeOfCharFollowingTheNumber(level);
+        byte follow = list.getTypeOfCharFollowingTheNumber( level );
         switch ( follow )
         {
         case 0:
index a20283970cddb38dfe4d9f6f8115252535d4b43e..6f3c82378fc49258ccc274c016fb12bbbf9f1dc4 100644 (file)
    See the License for the specific language governing permissions and\r
    limitations under the License.\r
 ==================================================================== */\r
+\r
 package org.apache.poi.hwpf.model.types;\r
 \r
 \r
-import org.apache.poi.util.BitField;\r
-import org.apache.poi.util.Internal;\r
+import org.apache.poi.hwpf.usermodel.*;\r
+import org.apache.poi.util.*;\r
 \r
 /**\r
  * The grfhic structure is a set of HTML incompatibility flags that specify the HTML\r
@@ -108,9 +109,10 @@ public abstract class GrfhicAbstractType
     public String toString()\r
     {\r
         StringBuilder builder = new StringBuilder();\r
+\r
         builder.append("[Grfhic]\n");\r
-        builder.append("    .grfhic               = ");\r
-        builder.append(" (").append(getGrfhic()).append(" )\n");\r
+        builder.append( "    .grfhic               = " );\r
+        builder.append(" ( ").append( field_1_grfhic ).append( " )\n" );\r
         builder.append("         .fHtmlChecked             = ").append(isFHtmlChecked()).append('\n');\r
         builder.append("         .fHtmlUnsupported         = ").append(isFHtmlUnsupported()).append('\n');\r
         builder.append("         .fHtmlListTextNotSharpDot     = ").append(isFHtmlListTextNotSharpDot()).append('\n');\r
@@ -120,7 +122,7 @@ public abstract class GrfhicAbstractType
         builder.append("         .fHtmlHangingIndentBeneathNumber     = ").append(isFHtmlHangingIndentBeneathNumber()).append('\n');\r
         builder.append("         .fHtmlBuiltInBullet       = ").append(isFHtmlBuiltInBullet()).append('\n');\r
 \r
-        builder.append("[/Grfhic]\n");\r
+        builder.append("[/Grfhic]");\r
         return builder.toString();\r
     }\r
 \r
index e36017e65ed349f61e9b638de5ca677695865337..0289ef28ab761297cb0abc32b9f75bb1f49d7395 100644 (file)
@@ -21,20 +21,19 @@ import org.apache.poi.util.Internal;
 import org.apache.poi.util.LittleEndian;\r
 \r
 /**\r
- * List Format Override (LFO).\r
+ * List Format Override (LFO). <p>Class and fields descriptions are quoted from\r
+        [MS-DOC] --v20110315; Word (.doc) Binary File Format\r
+    \r
  * <p>\r
- * Class and fields descriptions are quoted from [MS-DOC] --v20110315; Word\r
- * (.doc) Binary File Format\r
- * \r
+ * NOTE: This source is automatically generated please do not modify this file.  Either subclass or\r
+ *       remove the record in src/types/definitions.\r
  * <p>\r
- * NOTE: This source is automatically generated please do not modify this file.\r
- * Either subclass or remove the record in src/types/definitions.\r
- * <p>\r
- * This class is internal. It content or properties may change without notice\r
+ * This class is internal. It content or properties may change without notice \r
  * due to changes in our knowledge of internal Microsoft Word binary structures.\r
- * \r
- * @author Sergey Vladimirov; according to [MS-DOC] --v20110315; Word (.doc)\r
- *         Binary File Format; Copyright (c) Microsoft Corporation\r
+\r
+ * @author Sergey Vladimirov; according to [MS-DOC] --v20110315; Word (.doc) Binary File Format;\r
+        Copyright (c) Microsoft Corporation\r
+    \r
  */\r
 @Internal\r
 public abstract class LFOAbstractType\r
@@ -55,13 +54,13 @@ public abstract class LFOAbstractType
 \r
     protected void fillFields( byte[] data, int offset )\r
     {\r
-        field_1_lsid = LittleEndian.getInt( data, 0x0 + offset );\r
-        field_2_unused1 = LittleEndian.getInt( data, 0x4 + offset );\r
-        field_3_unused2 = LittleEndian.getInt( data, 0x8 + offset );\r
-        field_4_clfolvl = data[0xc + offset];\r
-        field_5_ibstFltAutoNum = data[0xd + offset];\r
-        field_6_grfhic = new Grfhic( data, 0xe + offset );\r
-        field_7_unused3 = data[0xf + offset];\r
+        field_1_lsid                   = LittleEndian.getInt( data, 0x0 + offset );\r
+        field_2_unused1                = LittleEndian.getInt( data, 0x4 + offset );\r
+        field_3_unused2                = LittleEndian.getInt( data, 0x8 + offset );\r
+        field_4_clfolvl                = data[ 0xc + offset ];\r
+        field_5_ibstFltAutoNum         = data[ 0xd + offset ];\r
+        field_6_grfhic                 = new Grfhic( data, 0xe + offset );\r
+        field_7_unused3                = data[ 0xf + offset ];\r
     }\r
 \r
     public void serialize( byte[] data, int offset )\r
@@ -69,15 +68,15 @@ public abstract class LFOAbstractType
         LittleEndian.putInt( data, 0x0 + offset, field_1_lsid );\r
         LittleEndian.putInt( data, 0x4 + offset, field_2_unused1 );\r
         LittleEndian.putInt( data, 0x8 + offset, field_3_unused2 );\r
-        data[0xc + offset] = field_4_clfolvl;\r
-        data[0xd + offset] = field_5_ibstFltAutoNum;\r
+        data[ 0xc + offset ] = field_4_clfolvl;\r
+        data[ 0xd + offset ] = field_5_ibstFltAutoNum;\r
         field_6_grfhic.serialize( data, 0xe + offset );\r
-        data[0xf + offset] = field_7_unused3;\r
+        data[ 0xf + offset ] = field_7_unused3;\r
     }\r
 \r
     public byte[] serialize()\r
     {\r
-        final byte[] result = new byte[getSize()];\r
+        final byte[] result = new byte[ getSize() ];\r
         serialize( result, 0 );\r
         return result;\r
     }\r
@@ -132,7 +131,8 @@ public abstract class LFOAbstractType
         result = prime * result + field_3_unused2;\r
         result = prime * result + field_4_clfolvl;\r
         result = prime * result + field_5_ibstFltAutoNum;\r
-        result = prime * result + field_6_grfhic.hashCode();\r
+        result = prime * result\r
+                + ((field_6_grfhic == null) ? 0 : field_6_grfhic.hashCode());\r
         result = prime * result + field_7_unused3;\r
         return result;\r
     }\r
@@ -140,30 +140,29 @@ public abstract class LFOAbstractType
     public String toString()\r
     {\r
         StringBuilder builder = new StringBuilder();\r
-        builder.append( "[LFO]\n" );\r
+\r
+        builder.append("[LFO]\n");\r
         builder.append( "    .lsid                 = " );\r
-        builder.append( " (" ).append( getLsid() ).append( " )\n" );\r
+        builder.append(" ( ").append( field_1_lsid ).append( " )\n" );\r
         builder.append( "    .unused1              = " );\r
-        builder.append( " (" ).append( getUnused1() ).append( " )\n" );\r
+        builder.append(" ( ").append( field_2_unused1 ).append( " )\n" );\r
         builder.append( "    .unused2              = " );\r
-        builder.append( " (" ).append( getUnused2() ).append( " )\n" );\r
+        builder.append(" ( ").append( field_3_unused2 ).append( " )\n" );\r
         builder.append( "    .clfolvl              = " );\r
-        builder.append( " (" ).append( getClfolvl() ).append( " )\n" );\r
+        builder.append(" ( ").append( field_4_clfolvl ).append( " )\n" );\r
         builder.append( "    .ibstFltAutoNum       = " );\r
-        builder.append( " (" ).append( getIbstFltAutoNum() ).append( " )\n" );\r
+        builder.append(" ( ").append( field_5_ibstFltAutoNum ).append( " )\n" );\r
         builder.append( "    .grfhic               = " );\r
-        builder.append( " (" ).append( getGrfhic() ).append( " )\n" );\r
+        builder.append(" ( ").append( field_6_grfhic == null ? "null" : field_6_grfhic.toString().replaceAll( "\n", "\n    " ) ).append( " )\n" );\r
         builder.append( "    .unused3              = " );\r
-        builder.append( " (" ).append( getUnused3() ).append( " )\n" );\r
+        builder.append(" ( ").append( field_7_unused3 ).append( " )\n" );\r
 \r
-        builder.append( "[/LFO]\n" );\r
+        builder.append("[/LFO]");\r
         return builder.toString();\r
     }\r
 \r
     /**\r
-     * A signed integer that specifies the list identifier of an LSTF. This LFO\r
-     * corresponds to the LSTF in PlfLst.rgLstf that has an lsid whose value is\r
-     * equal to this value..\r
+     * A signed integer that specifies the list identifier of an LSTF. This LFO corresponds to the LSTF in PlfLst.rgLstf that has an lsid whose value is equal to this value..\r
      */\r
     @Internal\r
     public int getLsid()\r
@@ -172,9 +171,7 @@ public abstract class LFOAbstractType
     }\r
 \r
     /**\r
-     * A signed integer that specifies the list identifier of an LSTF. This LFO\r
-     * corresponds to the LSTF in PlfLst.rgLstf that has an lsid whose value is\r
-     * equal to this value..\r
+     * A signed integer that specifies the list identifier of an LSTF. This LFO corresponds to the LSTF in PlfLst.rgLstf that has an lsid whose value is equal to this value..\r
      */\r
     @Internal\r
     public void setLsid( int field_1_lsid )\r
@@ -290,4 +287,4 @@ public abstract class LFOAbstractType
         this.field_7_unused3 = field_7_unused3;\r
     }\r
 \r
-} // END OF CLASS\r
+}  // END OF CLASS\r
index 06e8ed2e703f0b03b46475bd472b6497a5989168..41bcb96526a44520249ae480df3d8bcaf258d0a3 100644 (file)
@@ -28,6 +28,7 @@ import org.apache.poi.util.Internal;
 import org.apache.poi.hwpf.model.LFO;
 import org.apache.poi.hwpf.model.LFOData;
 import org.apache.poi.hwpf.model.ListData;
+import org.apache.poi.hwpf.model.ListFormatOverrideLevel;
 import org.apache.poi.hwpf.model.ListLevel;
 import org.apache.poi.hwpf.model.StyleSheet;
 import org.apache.poi.hwpf.sprm.CharacterSprmCompressor;
@@ -167,6 +168,11 @@ public final class HWPFList
 
     public int getStartAt( char level )
     {
+        if ( isStartAtOverriden( level ) )
+        {
+            return _lfoData.getRgLfoLvl()[level].getIStartAt();
+        }
+
         return getLVL( level ).getStartAt();
     }
 
@@ -183,6 +189,15 @@ public final class HWPFList
         return _ignoreLogicalLeftIdentation;
     }
 
+    public boolean isStartAtOverriden( char level )
+    {
+        ListFormatOverrideLevel lfolvl = _lfoData.getRgLfoLvl().length > level ? _lfoData
+                .getRgLfoLvl()[level] : null;
+
+        return lfolvl != null && lfolvl.getIStartAt() != 0
+                && !lfolvl.isFormatting();
+    }
+
     public void setIgnoreLogicalLeftIdentation(
             boolean ignoreLogicalLeftIdentation )
     {
index 11d5976bbe3fca9b40ff50ee3a58dc33e502f32c..00a46f642c7a097b46bf2a24fa5b7feff08e7372 100644 (file)
@@ -36,6 +36,21 @@ public class TestWordToTextConverter extends TestCase
                 .contains( "Soak the rice in water for three to four hours" ) );
     }
 
+    public void testBug52311() throws Exception
+    {
+        HWPFDocument doc = HWPFTestDataSamples.openSampleFile( "Bug52311.doc" );
+        String result = WordToTextConverter.getText( doc );
+
+        assertTrue( result.contains( "2.1\tHeader 2.1" ) );
+        assertTrue( result.contains( "2.2\tHeader 2.2" ) );
+        assertTrue( result.contains( "2.3\tHeader 2.3" ) );
+        assertTrue( result.contains( "2.3.1\tHeader 2.3.1" ) );
+        assertTrue( result.contains( "2.99\tHeader 2.99" ) );
+        assertTrue( result.contains( "2.99.1\tHeader 2.99.1" ) );
+        assertTrue( result.contains( "2.100\tHeader 2.100" ) );
+        assertTrue( result.contains( "2.101\tHeader 2.101" ) );
+    }
+
     public void testBug53380_3() throws Exception
     {
         HWPFDocument doc = HWPFTestDataSamples
index 027323dfe07232e5977421c93adc024a6d2133b6..ab923d1921ca7d9e4249192b33ab68881554b0fc 100644 (file)
@@ -381,27 +381,8 @@ public abstract class </xsl:text><xsl:call-template name="outputClassName"/><xsl
     <xsl:call-template name="linebreak"/>
 
     <xsl:call-template name="linebreak"/>
-    <xsl:call-template name="indent"/>
-    <xsl:text>public String toString()
-    {
-        StringBuilder builder = new StringBuilder();
-</xsl:text>
-    <xsl:call-template name="indent"/>
-    <xsl:call-template name="indent"/>
-    <xsl:text>builder.append("[</xsl:text>
-    <xsl:value-of select="@name"/>
-    <xsl:text>]\n");</xsl:text>
-    <xsl:call-template name="linebreak"/>
-    <xsl:apply-templates select="//field" mode="tostring"/>
-    <xsl:call-template name="linebreak"/>
-    <xsl:call-template name="indent"/>
-    <xsl:call-template name="indent"/>
-    <xsl:text>builder.append("[/</xsl:text>
-    <xsl:value-of select="@name"/>
-    <xsl:text>]\n");
-        return builder.toString();
-    }
-</xsl:text>
+    
+    <xsl:call-template name="toString" />
 
 <xsl:apply-templates select="//field" mode="getset"/>
 <xsl:apply-templates select="//field" mode="bits"/>
@@ -549,21 +530,72 @@ public abstract class </xsl:text><xsl:call-template name="outputClassName"/><xsl
     }
 </xsl:template>
 
-    <xsl:template match="field" mode="tostring">
-        <xsl:call-template name="indent"/>
-        <xsl:call-template name="indent"/>
-        <xsl:text>builder.append("    .</xsl:text>
-        <xsl:value-of select="recutil:getFieldName(@name,20)"/>
-        <xsl:text> = ");</xsl:text>
-        <xsl:call-template name="linebreak"/>
-        <xsl:call-template name="indent"/>
-        <xsl:call-template name="indent"/>
-        <xsl:text>builder.append(" (").append(get</xsl:text>
-        <xsl:value-of select="recutil:getFieldName1stCap(@name,0)"/>
-        <xsl:text>()).append(" )\n");</xsl:text>
-        <xsl:call-template name="linebreak"/>
-        <xsl:apply-templates select="bit" mode="bittostring"/>
-    </xsl:template>
+       <xsl:template name="toString">
+               <xsl:call-template name="indent" />
+               <xsl:text>public String toString()</xsl:text>
+               <xsl:call-template name="linebreak" />
+
+               <xsl:call-template name="indent" />
+               <xsl:text>{</xsl:text>
+               <xsl:call-template name="linebreak" />
+
+               <xsl:call-template name="indent" />
+               <xsl:call-template name="indent" />
+               <xsl:text>StringBuilder builder = new StringBuilder();</xsl:text>
+               <xsl:call-template name="linebreak" />
+               <xsl:call-template name="linebreak" />
+
+               <xsl:call-template name="indent" />
+               <xsl:call-template name="indent" />
+               <xsl:text>builder.append("[</xsl:text>
+               <xsl:value-of select="@name" />
+               <xsl:text>]\n");</xsl:text>
+               <xsl:call-template name="linebreak" />
+
+               <xsl:apply-templates select="//field" mode="tostring" />
+
+               <xsl:call-template name="linebreak" />
+               <xsl:call-template name="indent" />
+               <xsl:call-template name="indent" />
+               <xsl:text>builder.append("[/</xsl:text>
+               <xsl:value-of select="@name" />
+               <xsl:text>]");
+        return builder.toString();
+    }
+</xsl:text>
+       </xsl:template>
+
+       <xsl:template match="field" mode="tostring">
+               <xsl:variable name="fieldName"
+                       select="recutil:getFieldName(position(),@name,0)" />
+
+               <xsl:call-template name="indent" />
+               <xsl:call-template name="indent" />
+               <xsl:text>builder.append( "    .</xsl:text>
+               <xsl:value-of select="recutil:getFieldName(@name,20)" />
+               <xsl:text> = " );</xsl:text>
+               <xsl:call-template name="linebreak" />
+
+               <xsl:call-template name="indent" />
+               <xsl:call-template name="indent" />
+               <xsl:text>builder.append(" ( ").append( </xsl:text>
+               <xsl:choose>
+                       <xsl:when
+                               test="@type='boolean' or @type='byte' or @type='double' or @type='int' or @type='long' or @type='short'">
+                               <xsl:value-of select="$fieldName" />
+                       </xsl:when>
+                       <xsl:otherwise>
+                               <xsl:value-of select="$fieldName" />
+                               <xsl:text> == null ? "null" : </xsl:text>
+                               <xsl:value-of select="$fieldName" />
+                               <xsl:text>.toString().replaceAll( "\n", "\n    " )</xsl:text>
+                       </xsl:otherwise>
+               </xsl:choose>
+               <xsl:text> ).append( " )\n" );</xsl:text>
+               <xsl:call-template name="linebreak" />
+
+               <xsl:apply-templates select="bit" mode="bittostring" />
+       </xsl:template>
 
     <xsl:template match="bit" mode="bittostring">
         <xsl:call-template name="indent"/>
diff --git a/test-data/document/Bug52311.doc b/test-data/document/Bug52311.doc
new file mode 100644 (file)
index 0000000..16f5568
Binary files /dev/null and b/test-data/document/Bug52311.doc differ