]> source.dussan.org Git - poi.git/commitdiff
When sorting the contents of a directory, do so in a way that doesn't upset Excel...
authorNick Burch <nick@apache.org>
Tue, 12 Dec 2006 18:21:41 +0000 (18:21 +0000)
committerNick Burch <nick@apache.org>
Tue, 12 Dec 2006 18:21:41 +0000 (18:21 +0000)
git-svn-id: https://svn.apache.org/repos/asf/jakarta/poi/trunk@486265 13f79535-47bb-0310-9956-ffa450edef68

src/java/org/apache/poi/poifs/property/DirectoryProperty.java
src/testcases/org/apache/poi/hssf/data/39234.xls [new file with mode: 0644]
src/testcases/org/apache/poi/poifs/filesystem/TestPropertySorter.java [new file with mode: 0644]

index 5681ad5f034e374f7a1c7b5d12cb01b914439ea7..e0d817cf077d4f75e93eb6c647074eadfaebee1e 100644 (file)
@@ -127,7 +127,7 @@ public class DirectoryProperty
         return result;
     }
 
-    private class PropertyComparator
+    public static class PropertyComparator
         implements Comparator
     {
 
@@ -162,13 +162,40 @@ public class DirectoryProperty
 
         public int compare(Object o1, Object o2)
         {
+            String VBA_PROJECT = "_VBA_PROJECT";
             String name1  = (( Property ) o1).getName();
             String name2  = (( Property ) o2).getName();
-            int    result = name1.length() - name2.length();
+            int  result = name1.length() - name2.length();
 
             if (result == 0)
             {
-                result = name1.compareTo(name2);
+              // _VBA_PROJECT, it seems, will always come last
+              if (name1.compareTo(VBA_PROJECT) == 0)
+                result = 1;
+              else if (name2.compareTo(VBA_PROJECT) == 0)
+                result = -1;
+              else
+              {
+                if (name1.startsWith("__") && name2.startsWith("__"))
+                {
+                  // Betweeen __SRP_0 and __SRP_1 just sort as normal
+                  result = name1.compareToIgnoreCase(name2);
+                }
+                else if (name1.startsWith("__"))
+                {
+                  // If only name1 is __XXX then this will be placed after name2
+                  result = 1;
+                }
+                else if (name2.startsWith("__"))
+                {
+                  // If only name2 is __XXX then this will be placed after name1
+                  result = -1;
+                }
+                else
+                  // result = name1.compareTo(name2);
+                  // The default case is to sort names ignoring case
+                  result = name1.compareToIgnoreCase(name2);
+              }
             }
             return result;
         }
diff --git a/src/testcases/org/apache/poi/hssf/data/39234.xls b/src/testcases/org/apache/poi/hssf/data/39234.xls
new file mode 100644 (file)
index 0000000..20fc9a0
Binary files /dev/null and b/src/testcases/org/apache/poi/hssf/data/39234.xls differ
diff --git a/src/testcases/org/apache/poi/poifs/filesystem/TestPropertySorter.java b/src/testcases/org/apache/poi/poifs/filesystem/TestPropertySorter.java
new file mode 100644 (file)
index 0000000..7ddd2cc
--- /dev/null
@@ -0,0 +1,152 @@
+\r
+/* ====================================================================\r
+   Copyright 2002-2004   Apache Software Foundation\r
+\r
+   Licensed under the Apache License, Version 2.0 (the "License");\r
+   you may not use this file except in compliance with the License.\r
+   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.poifs.filesystem;\r
+\r
+import junit.framework.TestCase;\r
+import junit.framework.ComparisonFailure;\r
+\r
+import java.io.*;\r
+import java.util.*;\r
+\r
+import org.apache.poi.poifs.property.DirectoryProperty;\r
+import org.apache.poi.poifs.property.Property;\r
+\r
+/**\r
+ * Verify the order of entries <code>DirectoryProperty</code> .\r
+ * <p>\r
+ * In particular it is important to serialize ROOT._VBA_PROJECT_CUR.VBA node.\r
+ * See bug 39234 in bugzilla. Thanks to Bill Seddon for providing the solution.\r
+ * </p>\r
+ *\r
+ * @author Yegor Kozlov\r
+ */\r
+public class TestPropertySorter extends TestCase {\r
+\r
+    //the correct order of entries in the test file\r
+    protected static final String[] _entries = {\r
+        "dir", "JML", "UTIL", "Loader", "Sheet1", "Sheet2", "Sheet3",\r
+        "__SRP_0", "__SRP_1", "__SRP_2", "__SRP_3", "__SRP_4", "__SRP_5",\r
+        "ThisWorkbook", "_VBA_PROJECT",\r
+    };\r
+\r
+    protected File testFile;\r
+\r
+    public void setUp(){\r
+        String home = System.getProperty("HSSF.testdata.path");\r
+        testFile = new File(home + "/39234.xls");\r
+    }\r
+\r
+    /**\r
+     * Test sorting of properties in <code>DirectoryProperty</code>\r
+     */\r
+    public void testSortProperties() throws IOException {\r
+        InputStream is = new FileInputStream(testFile);\r
+        POIFSFileSystem fs = new POIFSFileSystem(is);\r
+        is.close();\r
+        Property[] props = getVBAProperties(fs);\r
+\r
+        assertEquals(_entries.length, props.length);\r
+\r
+        // (1). See that there is a problem with the old case-sensitive property comparartor\r
+        Arrays.sort(props, new CaseSensitivePropertyComparator());\r
+        try {\r
+            for (int i = 0; i < props.length; i++) {\r
+                assertEquals(_entries[i], props[i].getName());\r
+            }\r
+            fail("case-sensitive property comparator returns properties in wrong order");\r
+        } catch (ComparisonFailure e){\r
+            ; // as expected\r
+        }\r
+\r
+        // (2) Verify that the fixed proeprty comparator works right\r
+        Arrays.sort(props, new DirectoryProperty.PropertyComparator());\r
+        for (int i = 0; i < props.length; i++) {\r
+            assertEquals(_entries[i], props[i].getName());\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Serialize file system and verify that the order of properties is the same as in the original file.\r
+     */\r
+    public void testSerialization() throws IOException {\r
+        InputStream is = new FileInputStream(testFile);\r
+        POIFSFileSystem fs = new POIFSFileSystem(is);\r
+        is.close();\r
+\r
+        ByteArrayOutputStream out = new ByteArrayOutputStream();\r
+        fs.writeFilesystem(out);\r
+        out.close();\r
+        is = new ByteArrayInputStream(out.toByteArray());\r
+        fs = new POIFSFileSystem(is);\r
+        is.close();\r
+        Property[] props = getVBAProperties(fs);\r
+        Arrays.sort(props, new DirectoryProperty.PropertyComparator());\r
+\r
+        assertEquals(_entries.length, props.length);\r
+        for (int i = 0; i < props.length; i++) {\r
+            assertEquals(_entries[i], props[i].getName());\r
+        }\r
+    }\r
+\r
+    /**\r
+     * @return array of properties read from ROOT._VBA_PROJECT_CUR.VBA node\r
+     */\r
+    protected Property[] getVBAProperties(POIFSFileSystem fs) throws IOException {\r
+        String _VBA_PROJECT_CUR = "_VBA_PROJECT_CUR";\r
+        String VBA = "VBA";\r
+\r
+        DirectoryEntry root = fs.getRoot();\r
+        DirectoryEntry vba_project = (DirectoryEntry)root.getEntry(_VBA_PROJECT_CUR);\r
+\r
+        DirectoryNode vba = (DirectoryNode)vba_project.getEntry(VBA);\r
+        DirectoryProperty  p = (DirectoryProperty)vba.getProperty();\r
+\r
+        ArrayList lst = new ArrayList();\r
+        for (Iterator it = p.getChildren(); it.hasNext();){\r
+            Property ch = (Property)it.next();\r
+            lst.add(ch);\r
+        }\r
+        return (Property [])lst.toArray(new Property[ 0 ]);\r
+    }\r
+\r
+    /**\r
+     * Old version of case-sensitive PropertyComparator to demonstrate the problem\r
+     */\r
+    private class CaseSensitivePropertyComparator  implements Comparator\r
+    {\r
+\r
+        public boolean equals(Object o)\r
+        {\r
+            return this == o;\r
+        }\r
+\r
+        public int compare(Object o1, Object o2)\r
+        {\r
+            String name1  = (( Property ) o1).getName();\r
+            String name2  = (( Property ) o2).getName();\r
+            int    result = name1.length() - name2.length();\r
+\r
+            if (result == 0)\r
+            {\r
+                result = name1.compareTo(name2);\r
+            }\r
+            return result;\r
+        }\r
+    }\r
+\r
+}\r