]> source.dussan.org Git - poi.git/commitdiff
Fix for bug 45876 - allowed BoundSheetRecord to take sheet names longer than 31 chars
authorJosh Micich <josh@apache.org>
Mon, 29 Sep 2008 22:04:20 +0000 (22:04 +0000)
committerJosh Micich <josh@apache.org>
Mon, 29 Sep 2008 22:04:20 +0000 (22:04 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@700280 13f79535-47bb-0310-9956-ffa450edef68

src/documentation/content/xdocs/changes.xml
src/documentation/content/xdocs/status.xml
src/java/org/apache/poi/hssf/model/Workbook.java
src/java/org/apache/poi/hssf/record/BoundSheetRecord.java
src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java
src/testcases/org/apache/poi/hssf/record/TestBoundSheetRecord.java
src/testcases/org/apache/poi/hssf/usermodel/TestHSSFSheet.java

index 1a2604f85b1734b19efe0c4cac63f7c343aaf5f8..76d53e6287b4734cbc56cc4688951d8b2687c481 100644 (file)
@@ -37,6 +37,7 @@
 
                <!-- Don't forget to update status.xml too! -->
         <release version="3.2-alpha1" date="2008-??-??">
+           <action dev="POI-DEVELOPERS" type="fix">45876 - fixed BoundSheetRecord to allow sheet names longer than 31 chars</action>
            <action dev="POI-DEVELOPERS" type="add">45890 - fixed HSSFSheet.shiftRows to also update conditional formats</action>
            <action dev="POI-DEVELOPERS" type="add">45865 modified Formula Parser/Evaluator to handle cross-worksheet formulas</action>
            <action dev="POI-DEVELOPERS" type="add">Optimised the FormulaEvaluator to take cell dependencies into account</action>
index a56de462febedbf3439cf05d116920c1002fac51..34a3bc3271f0d96ee69286ee2fe8ec76b2914f63 100644 (file)
@@ -34,6 +34,7 @@
        <!-- Don't forget to update changes.xml too! -->
     <changes>
         <release version="3.2-alpha1" date="2008-??-??">
+           <action dev="POI-DEVELOPERS" type="fix">45876 - fixed BoundSheetRecord to allow sheet names longer than 31 chars</action>
            <action dev="POI-DEVELOPERS" type="add">45890 - fixed HSSFSheet.shiftRows to also update conditional formats</action>
            <action dev="POI-DEVELOPERS" type="add">45865 modified Formula Parser/Evaluator to handle cross-worksheet formulas</action>
            <action dev="POI-DEVELOPERS" type="add">Optimised the FormulaEvaluator to take cell dependencies into account</action>
index 0728d0e29ffdeb37d72cedcac65e7fa15ff494f3..54639adb182e114b8225cb0039e09cc8c2efb78c 100644 (file)
@@ -55,6 +55,12 @@ import org.apache.poi.util.POILogger;
  * @version 1.0-pre
  */
 public final class Workbook implements Model {
+    /**
+     * Excel silently truncates long sheet names to 31 chars.
+     * This constant is used to ensure uniqueness in the first 31 chars
+     */
+    private static final int MAX_SENSITIVE_SHEET_NAME_LEN = 31;
+
     private static final int   DEBUG       = POILogger.DEBUG;
 
     /**
@@ -488,32 +494,43 @@ public final class Workbook implements Model {
 
     /**
      * sets the name for a given sheet.  If the boundsheet record doesn't exist and
-     * its only one more than we have, go ahead and create it.  If its > 1 more than
+     * its only one more than we have, go ahead and create it.  If it's > 1 more than
      * we have, except
      *
      * @param sheetnum the sheet number (0 based)
      * @param sheetname the name for the sheet
      */
-    public void setSheetName(int sheetnum, String sheetname ) {
+    public void setSheetName(int sheetnum, String sheetname) {
         checkSheets(sheetnum);
         BoundSheetRecord sheet = (BoundSheetRecord)boundsheets.get( sheetnum );
         sheet.setSheetname(sheetname);
     }
 
     /**
-     * Determines whether a workbook contains the provided sheet name.
+     * Determines whether a workbook contains the provided sheet name.  For the purpose of 
+     * comparison, long names are truncated to 31 chars.
      *
      * @param name the name to test (case insensitive match)
      * @param excludeSheetIdx the sheet to exclude from the check or -1 to include all sheets in the check.
      * @return true if the sheet contains the name, false otherwise.
      */
-    public boolean doesContainsSheetName( String name, int excludeSheetIdx )
-    {
-        for ( int i = 0; i < boundsheets.size(); i++ )
-        {
+    public boolean doesContainsSheetName(String name, int excludeSheetIdx) {
+        String aName = name;
+        if (aName.length() > MAX_SENSITIVE_SHEET_NAME_LEN) {
+            aName = aName.substring(0, MAX_SENSITIVE_SHEET_NAME_LEN);
+        }
+        for (int i = 0; i < boundsheets.size(); i++) {
             BoundSheetRecord boundSheetRecord = getBoundSheetRec(i);
-            if (excludeSheetIdx != i && name.equalsIgnoreCase(boundSheetRecord.getSheetname()))
+            if (excludeSheetIdx == i) {
+                continue;
+            }
+            String bName = boundSheetRecord.getSheetname();
+            if (bName.length() > MAX_SENSITIVE_SHEET_NAME_LEN) {
+                bName = bName.substring(0, MAX_SENSITIVE_SHEET_NAME_LEN);
+            }
+            if (aName.equalsIgnoreCase(bName)) {
                 return true;
+            }
         }
         return false;
     }
@@ -1954,9 +1971,9 @@ public final class Workbook implements Model {
         return (short)getOrCreateLinkTable().checkExternSheet(sheetNumber);
     }
 
-       public int getExternalSheetIndex(String workbookName, String sheetName) {
-               return getOrCreateLinkTable().getExternalSheetIndex(workbookName, sheetName);
-       }
+    public int getExternalSheetIndex(String workbookName, String sheetName) {
+        return getOrCreateLinkTable().getExternalSheetIndex(workbookName, sheetName);
+    }
     
 
     /** gets the total number of names
index 2c1d0220f504f46bcf13356d4819d9acfb18e17d..4ecddce7e8d7dd35b744c5f6e4f2f9910f5be163 100644 (file)
@@ -116,9 +116,8 @@ public final class BoundSheetRecord extends Record {
                        throw new IllegalArgumentException("sheetName must not be null");
                }
                int len = sheetName.length();
-               if (len < 1 || len > 31) {
-                       throw new IllegalArgumentException("sheetName '" + sheetName 
-                                       + "' is invalid - must be 1-30 characters long");
+               if (len < 1) {
+                       throw new IllegalArgumentException("sheetName must not be empty string");
                }
                for (int i=0; i<len; i++) {
                        char ch = sheetName.charAt(i);
index cd860a10a9014794b597ac0bfdfdd9011b510acd..1744ff39d18a4c6d02b02e6b22276350b29437ba 100644 (file)
@@ -515,15 +515,17 @@ public class HSSFWorkbook extends POIDocument
     }
 
     /**
-     * set the sheet name.
-     * Will throw IllegalArgumentException if the name is greater than 31 chars
-     * or contains /\?*[]
+     * Sets the sheet name.
+     * Will throw IllegalArgumentException if the name is duplicated or contains /\?*[]
+     * Note - Excel allows sheet names up to 31 chars in length but other applications allow more.
+     * Excel does not crash with names longer than 31 chars, but silently truncates such names to 
+     * 31 chars.  POI enforces uniqueness on the first 31 chars.
+     * 
      * @param sheetIx number (0 based)
      */
-    public void setSheetName(int sheetIx, String name)
-    {
-        if (workbook.doesContainsSheetName( name, sheetIx )) {
-            throw new IllegalArgumentException( "The workbook already contains a sheet with this name" );
+    public void setSheetName(int sheetIx, String name) {
+        if (workbook.doesContainsSheetName(name, sheetIx)) {
+            throw new IllegalArgumentException("The workbook already contains a sheet with this name");
         }
         validateSheetIndex(sheetIx);
         workbook.setSheetName(sheetIx, name);
@@ -726,14 +728,14 @@ public class HSSFWorkbook extends POIDocument
      * create an HSSFSheet for this HSSFWorkbook, adds it to the sheets and
      * returns the high level representation. Use this to create new sheets.
      *
-     * @param sheetname
-     *            sheetname to set for the sheet.
+     * @param sheetname the name for the new sheet. Note - certain length limits
+     * apply. See {@link #setSheetName(int, String)}.
+     *
      * @return HSSFSheet representing the new sheet.
      * @throws IllegalArgumentException
      *             if there is already a sheet present with a case-insensitive
      *             match for the specified name.
      */
-
     public HSSFSheet createSheet(String sheetname)
     {
         if (workbook.doesContainsSheetName( sheetname, _sheets.size() ))
index e80afe973b07a82ebf5165369dbe876cc95b19a3..f973da37dbc682e3266365ed060cd6a6f000dedf 100644 (file)
@@ -45,13 +45,6 @@ public final class TestBoundSheetRecord extends TestCase {
     public void testName() {
         BoundSheetRecord record = new BoundSheetRecord("1234567890223456789032345678904");
 
-        try {
-            record.setSheetname("12345678902234567890323456789042");
-            throw new AssertionFailedError("Should have thrown IllegalArgumentException, but didnt");
-        } catch (IllegalArgumentException e) {
-            // expected
-        }
-
         try {
             record.setSheetname("s//*s");
             throw new AssertionFailedError("Should have thrown IllegalArgumentException, but didnt");
index 5e9541d540e509a1e7c51f179e61ddf10e776f90..e5aae7c0423a3efb49a0cc19d3927ea545ea3ef1 100644 (file)
@@ -891,4 +891,23 @@ public final class TestHSSFSheet extends TestCase {
 
         //TODO: check shapeId in the cloned sheet
     }
+    
+    /**
+     * POI now (Sep 2008) allows sheet names longer than 31 chars (for other apps besides Excel).
+     * Since Excel silently truncates to 31, make sure that POI enforces uniqueness on the first
+     * 31 chars. 
+     */
+    public void testLongSheetNames() {
+        HSSFWorkbook wb = new HSSFWorkbook();
+        final String SAME_PREFIX = "A123456789B123456789C123456789"; // 30 chars
+        
+        wb.createSheet(SAME_PREFIX + "Dxxxx");
+        try {
+            wb.createSheet(SAME_PREFIX + "Dyyyy"); // identical up to the 32nd char
+            throw new AssertionFailedError("Expected exception not thrown");
+        } catch (IllegalArgumentException e) {
+            assertEquals("The workbook already contains a sheet of this name", e.getMessage());
+        }
+        wb.createSheet(SAME_PREFIX + "Exxxx"); // OK - differs in the 31st char
+    }
 }