]> source.dussan.org Git - poi.git/commitdiff
fixes for ExternalNameRecord serialisation bug #44691
authorJosh Micich <josh@apache.org>
Thu, 27 Mar 2008 20:03:29 +0000 (20:03 +0000)
committerJosh Micich <josh@apache.org>
Thu, 27 Mar 2008 20:03:29 +0000 (20:03 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@641964 13f79535-47bb-0310-9956-ffa450edef68

src/java/org/apache/poi/hssf/record/ExternalNameRecord.java
src/testcases/org/apache/poi/hssf/record/AllRecordTests.java
src/testcases/org/apache/poi/hssf/record/TestExternalNameRecord.java [new file with mode: 0644]

index 771603c859e856478112c96067f857e91869006d..fe2085948f13b8cf742cb7af5bba9ec03abc4447 100755 (executable)
@@ -17,7 +17,6 @@
 
 package org.apache.poi.hssf.record;
 
-import java.util.List;
 import java.util.Stack;
 
 import org.apache.poi.hssf.record.formula.Ptg;
@@ -27,153 +26,160 @@ import org.apache.poi.util.StringUtil;
 /**
  * EXTERNALNAME<p/>
  * 
- * @author josh micich
+ * @author Josh Micich
  */
 public final class ExternalNameRecord extends Record {
 
-    public final static short sid = 0x23; // as per BIFF8. (some old versions used 0x223)
+       public final static short sid = 0x23; // as per BIFF8. (some old versions used 0x223)
 
+       private static final int OPT_BUILTIN_NAME          = 0x0001;
+       private static final int OPT_AUTOMATIC_LINK        = 0x0002;
+       private static final int OPT_PICTURE_LINK          = 0x0004;
+       private static final int OPT_STD_DOCUMENT_NAME     = 0x0008;
+       private static final int OPT_OLE_LINK              = 0x0010;
+//     private static final int OPT_CLIP_FORMAT_MASK      = 0x7FE0;
+       private static final int OPT_ICONIFIED_PICTURE_LINK= 0x8000;
 
-    private static final int OPT_BUILTIN_NAME           =   0x0001;
-    private static final int OPT_AUTOMATIC_LINK         =   0x0002;
-    private static final int OPT_PICTURE_LINK           =   0x0004;
-    private static final int OPT_STD_DOCUMENT_NAME      =   0x0008;
-    private static final int OPT_OLE_LINK               =   0x0010;
-//    private static final int OPT_CLIP_FORMAT_MASK       =   0x7FE0;
-    private static final int OPT_ICONIFIED_PICTURE_LINK =   0x8000;
 
+       private short  field_1_option_flag;
+       private short  field_2_index;
+       private short  field_3_not_used;
+       private String field_4_name;
+       private Ptg[]  field_5_name_definition; // TODO - junits for name definition field 
 
-    private short             field_1_option_flag;
-    private short              field_2_index;
-    private short              field_3_not_used;
-    private String             field_4_name;
-    private Stack             field_5_name_definition;
-
-
-    public ExternalNameRecord(RecordInputStream in) {
-        super(in);
-    }
+       public ExternalNameRecord(RecordInputStream in) {
+               super(in);
+       }
 
        /**
         * Convenience Function to determine if the name is a built-in name
         */
        public boolean isBuiltInName() {
-           return (field_1_option_flag & OPT_BUILTIN_NAME) != 0;
-       }
-    /**
-     * For OLE and DDE, links can be either 'automatic' or 'manual'
-     */
-    public boolean isAutomaticLink() {
-        return (field_1_option_flag & OPT_AUTOMATIC_LINK) != 0;
-    }
-    /**
-     * only for OLE and DDE
-     */
-    public boolean isPicureLink() {
-        return (field_1_option_flag & OPT_PICTURE_LINK) != 0;
-    }
-    /**
-     * DDE links only. If <code>true</code>, this denotes the 'StdDocumentName'
-     */
-    public boolean isStdDocumentNameIdentifier() {
-        return (field_1_option_flag & OPT_STD_DOCUMENT_NAME) != 0;
-    }
-    public boolean isOLELink() {
-        return (field_1_option_flag & OPT_OLE_LINK) != 0;
-    }
-    public boolean isIconifiedPictureLink() {
-        return (field_1_option_flag & OPT_ICONIFIED_PICTURE_LINK) != 0;
-    }
-    /**
-     * @return the standard String representation of this name
-     */
-    public String getText() {
-       return field_4_name;
-    }
-
-
-    /**
-     * called by constructor, should throw runtime exception in the event of a
-     * record passed with a differing ID.
-     *
-     * @param id alleged id for this record
-     */
-    protected void validateSid(short id) {
-        if (id != sid) {
-            throw new RecordFormatException("NOT A valid ExternalName RECORD");
-        }
-    }
-
-    private int getDataSize(){
-        return 2 + 2 + field_4_name.length() + 2 + getNameDefinitionSize();
-    }
-
-    /**
-     * called by the class that is responsible for writing this sucker.
-     * Subclasses should implement this so that their data is passed back in a
-     * byte array.
-     *
-     * @param offset to begin writing at
-     * @param data byte array containing instance data
-     * @return number of bytes written
-     */
-    public int serialize( int offset, byte[] data ) {
-       // TODO - junit tests
-        int dataSize = getDataSize();
-
-        LittleEndian.putShort( data, 0 + offset, sid );
+               return (field_1_option_flag & OPT_BUILTIN_NAME) != 0;
+       }
+       /**
+        * For OLE and DDE, links can be either 'automatic' or 'manual'
+        */
+       public boolean isAutomaticLink() {
+               return (field_1_option_flag & OPT_AUTOMATIC_LINK) != 0;
+       }
+       /**
+        * only for OLE and DDE
+        */
+       public boolean isPicureLink() {
+               return (field_1_option_flag & OPT_PICTURE_LINK) != 0;
+       }
+       /**
+        * DDE links only. If <code>true</code>, this denotes the 'StdDocumentName'
+        */
+       public boolean isStdDocumentNameIdentifier() {
+               return (field_1_option_flag & OPT_STD_DOCUMENT_NAME) != 0;
+       }
+       public boolean isOLELink() {
+               return (field_1_option_flag & OPT_OLE_LINK) != 0;
+       }
+       public boolean isIconifiedPictureLink() {
+               return (field_1_option_flag & OPT_ICONIFIED_PICTURE_LINK) != 0;
+       }
+       /**
+        * @return the standard String representation of this name
+        */
+       public String getText() {
+               return field_4_name;
+       }
+
+
+       /**
+        * called by constructor, should throw runtime exception in the event of a
+        * record passed with a differing ID.
+        *
+        * @param id alleged id for this record
+        */
+       protected void validateSid(short id) {
+               if (id != sid) {
+                       throw new RecordFormatException("NOT A valid ExternalName RECORD");
+               }
+       }
+
+       private int getDataSize(){
+               return 3 * 2  // 3 short fields
+                       + 2 + field_4_name.length() // nameLen and name
+                       + 2 + getNameDefinitionSize(); // nameDefLen and nameDef
+       }
+
+       /**
+        * called by the class that is responsible for writing this sucker.
+        * Subclasses should implement this so that their data is passed back in a
+        * byte array.
+        *
+        * @param offset to begin writing at
+        * @param data byte array containing instance data
+        * @return number of bytes written
+        */
+       public int serialize( int offset, byte[] data ) {
+               int dataSize = getDataSize();
+
+               LittleEndian.putShort( data, 0 + offset, sid );
                LittleEndian.putShort( data, 2 + offset, (short) dataSize );
-        LittleEndian.putShort( data, 4 + offset, field_1_option_flag );
-        LittleEndian.putShort( data, 6 + offset, field_2_index );
-        LittleEndian.putShort( data, 8 + offset, field_3_not_used );
-        short nameLen = (short) field_4_name.length();
+               LittleEndian.putShort( data, 4 + offset, field_1_option_flag );
+               LittleEndian.putShort( data, 6 + offset, field_2_index );
+               LittleEndian.putShort( data, 8 + offset, field_3_not_used );
+               short nameLen = (short) field_4_name.length();
                LittleEndian.putShort( data, 10 + offset, nameLen );
-        StringUtil.putCompressedUnicode( field_4_name, data, 10 + offset );
-        short defLen = (short) getNameDefinitionSize();
-        LittleEndian.putShort( data, 12 + nameLen + offset, defLen );
-               Ptg.serializePtgStack(field_5_name_definition, data, 12 + nameLen + offset );
+               StringUtil.putCompressedUnicode( field_4_name, data, 12 + offset );
+               short defLen = (short) getNameDefinitionSize();
+               LittleEndian.putShort( data, 12 + nameLen + offset, defLen );
+               Ptg.serializePtgStack(toStack(field_5_name_definition), data, 14 + nameLen + offset );
                return dataSize + 4;
-    }
-
-    private int getNameDefinitionSize() {
-       int result = 0;
-        List list   = field_5_name_definition;
-
-        for (int k = 0; k < list.size(); k++)
-        {
-               Ptg ptg = ( Ptg ) list.get(k);
-        
-               result += ptg.getSize();
-        }
-        return result;
-    }
-
-
-    public int getRecordSize(){
-        return 6 + 2 + field_4_name.length() + 2 + getNameDefinitionSize();
-    }
-
-
-    protected void fillFields(RecordInputStream in) {
-        field_1_option_flag             = in.readShort();
-        field_2_index                   = in.readShort();
-        field_3_not_used                = in.readShort();
-        short nameLength = in.readShort();
-        field_4_name                    = in.readCompressedUnicode(nameLength);
-        short formulaLen = in.readShort();
-               field_5_name_definition         = Ptg.createParsedExpressionTokens(formulaLen, in);
-    }
-
-    public short getSid() {
-        return sid;
-    }
-
-    public String toString() {
-        StringBuffer sb = new StringBuffer();
-        sb.append(getClass().getName()).append(" [EXTERNALNAME ");
-        sb.append(" ").append(field_4_name);
-        sb.append(" ix=").append(field_2_index);
-        sb.append("]");
-        return sb.toString();
-    }
+       }
+
+       private int getNameDefinitionSize() {
+               int result = 0;
+               for (int i = 0; i < field_5_name_definition.length; i++) {
+                       result += field_5_name_definition[i].getSize();
+               }
+               return result;
+       }
+
+
+       public int getRecordSize(){
+               return 4 + getDataSize();
+       }
+
+
+       protected void fillFields(RecordInputStream in) {
+               field_1_option_flag = in.readShort();
+               field_2_index      = in.readShort();
+               field_3_not_used        = in.readShort();
+               short nameLength        = in.readShort();
+               field_4_name            = in.readCompressedUnicode(nameLength);
+               short formulaLen        = in.readShort();
+               field_5_name_definition = toPtgArray(Ptg.createParsedExpressionTokens(formulaLen, in));
+       }
+
+       private static Ptg[] toPtgArray(Stack s) {
+               Ptg[] result = new Ptg[s.size()];
+               s.toArray(result);
+               return result;
+       }
+       private static Stack toStack(Ptg[] ptgs) {
+               Stack result = new Stack();
+               for (int i = 0; i < ptgs.length; i++) {
+                       result.push(ptgs[i]);
+               }
+               return result;
+       }
+       public short getSid() {
+               return sid;
+       }
+
+       public String toString() {
+               StringBuffer sb = new StringBuffer();
+               sb.append(getClass().getName()).append(" [EXTERNALNAME ");
+               sb.append(" ").append(field_4_name);
+               sb.append(" ix=").append(field_2_index);
+               sb.append("]");
+               return sb.toString();
+       }
 }
index b1acfeafa17f70c13ae74ad5e7826da43123b5b1..9da8f45ebc26689543410303b518513ed5ab30d9 100755 (executable)
@@ -14,7 +14,6 @@
    See the License for the specific language governing permissions and
    limitations under the License.
 ==================================================================== */
-        
 
 package org.apache.poi.hssf.record;
 
@@ -28,10 +27,10 @@ import junit.framework.TestSuite;
  * 
  * @author Josh Micich
  */
-public class AllRecordTests {
+public final class AllRecordTests {
        
        public static Test suite() {
-               TestSuite result = new TestSuite("Tests for org.apache.poi.hssf.record");
+               TestSuite result = new TestSuite(AllRecordTests.class.getName());
 
                result.addTest(AllFormulaTests.suite());
                
@@ -56,6 +55,7 @@ public class AllRecordTests {
                result.addTestSuite(TestEmbeddedObjectRefSubRecord.class);
                result.addTestSuite(TestEndSubRecord.class);
                result.addTestSuite(TestEscherAggregate.class);
+               result.addTestSuite(TestExternalNameRecord.class);
                result.addTestSuite(TestFontBasisRecord.class);
                result.addTestSuite(TestFontIndexRecord.class);
                result.addTestSuite(TestFormulaRecord.class);
diff --git a/src/testcases/org/apache/poi/hssf/record/TestExternalNameRecord.java b/src/testcases/org/apache/poi/hssf/record/TestExternalNameRecord.java
new file mode 100644 (file)
index 0000000..a90221f
--- /dev/null
@@ -0,0 +1,55 @@
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+\r
+package org.apache.poi.hssf.record;\r
+\r
+import junit.framework.AssertionFailedError;\r
+import junit.framework.TestCase;\r
+/**\r
+ * \r
+ * @author Josh Micich\r
+ */\r
+public final class TestExternalNameRecord extends TestCase {\r
+\r
+       private static final byte[] dataFDS = {\r
+               0, 0, 0, 0, 0, 0, 3, 0, 70, 68, 83, 0, 0,\r
+       };\r
+       private static ExternalNameRecord createSimpleENR() {\r
+               return new ExternalNameRecord(new TestcaseRecordInputStream((short)0x0023, dataFDS));\r
+       }\r
+       public void testBasicDeserializeReserialize() {\r
+               \r
+               ExternalNameRecord enr = createSimpleENR();\r
+               assertEquals( "FDS", enr.getText());\r
+        \r
+               try {\r
+                       TestcaseRecordInputStream.confirmRecordEncoding(0x0023, dataFDS, enr.serialize());\r
+               } catch (ArrayIndexOutOfBoundsException e) {\r
+                       if(e.getMessage().equals("15")) {\r
+                               throw new AssertionFailedError("Identified bug 44691");\r
+                       }\r
+               }\r
+       }\r
+       \r
+       public void testBasicSize() {\r
+               ExternalNameRecord enr = createSimpleENR();\r
+               if(enr.getRecordSize() == 13) {\r
+                       throw new AssertionFailedError("Identified bug 44691");\r
+               }\r
+               assertEquals(17, enr.getRecordSize());\r
+       }\r
+}\r