]> source.dussan.org Git - poi.git/commitdiff
Bug 59200: Check for actual Excel limits on data validation title/text
authorDominik Stadler <centic@apache.org>
Fri, 25 Nov 2016 08:55:52 +0000 (08:55 +0000)
committerDominik Stadler <centic@apache.org>
Fri, 25 Nov 2016 08:55:52 +0000 (08:55 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1771254 13f79535-47bb-0310-9956-ffa450edef68

src/java/org/apache/poi/hssf/record/DVRecord.java
src/java/org/apache/poi/hssf/usermodel/HSSFDataValidation.java
src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFDataValidation.java
src/testcases/org/apache/poi/ss/usermodel/BaseTestBugzillaIssues.java

index 68d560afd32b64822eddbaf347d84a2a38ae8827..04b3f84411d66f346f3c4710e466526e97d84127 100644 (file)
@@ -42,13 +42,13 @@ public final class DVRecord extends StandardRecord implements Cloneable {
 
        /** Option flags */
        private int _option_flags;
-       /** Title of the prompt box */
+       /** Title of the prompt box, cannot be longer than 32 chars */
        private UnicodeString _promptTitle;
-       /** Title of the error box */
+       /** Title of the error box, cannot be longer than 32 chars */
        private UnicodeString _errorTitle;
-       /** Text of the prompt box */
+       /** Text of the prompt box, cannot be longer than 255 chars */
        private UnicodeString _promptText;
-       /** Text of the error box */
+       /** Text of the error box, cannot be longer than 255 chars */
        private UnicodeString _errorText;
        /** Not used - Excel seems to always write 0x3FE0 */
        private short _not_used_1 = 0x3FE0;
@@ -82,6 +82,21 @@ public final class DVRecord extends StandardRecord implements Cloneable {
                        Ptg[] formula1, Ptg[] formula2,
                        CellRangeAddressList regions) {
                
+               // check length-limits
+               if(promptTitle != null && promptTitle.length() > 32) {
+                       throw new IllegalStateException("Prompt-title cannot be longer than 32 characters, but had: " + promptTitle);
+               }
+               if(promptText != null && promptText.length() > 255) {
+                       throw new IllegalStateException("Prompt-text cannot be longer than 255 characters, but had: " + promptText);
+               }
+
+               if(errorTitle != null && errorTitle.length() > 32) {
+                       throw new IllegalStateException("Error-title cannot be longer than 32 characters, but had: " + errorTitle);
+               }
+               if(errorText != null && errorText.length() > 255) {
+                       throw new IllegalStateException("Error-text cannot be longer than 255 characters, but had: " + errorText);
+               }
+
                int flags = 0;
                flags = opt_data_type.setValue(flags, validationType);
                flags = opt_condition_operator.setValue(flags, operator);
@@ -267,8 +282,8 @@ public final class DVRecord extends StandardRecord implements Cloneable {
                }
                Ptg[] ptgs = f.getTokens();
                sb.append('\n');
-               for (int i = 0; i < ptgs.length; i++) {
-                       sb.append('\t').append(ptgs[i].toString()).append('\n');
+               for (Ptg ptg : ptgs) {
+                       sb.append('\t').append(ptg.toString()).append('\n');
                }
        }
 
index 6654749863b94a73cb1d47038348f63e6505b6e4..206ee11b99bdfcc312a5c8ab8267d0b9badce384 100644 (file)
@@ -44,7 +44,9 @@ public final class HSSFDataValidation implements DataValidation {
        /**
         * Constructor which initializes the cell range on which this object will be
         * applied
-        * @param constraint 
+        *
+        * @param regions A list of regions where the constraint is validated.
+        * @param constraint The constraints to apply for this validation.
         */
        public HSSFDataValidation(CellRangeAddressList regions, DataValidationConstraint constraint) {
                _regions = regions;
@@ -109,6 +111,7 @@ public final class HSSFDataValidation implements DataValidation {
         * @see org.apache.poi.hssf.usermodel.DataValidation#getSuppressDropDownArrow()
         */
        public boolean getSuppressDropDownArrow() {
+               //noinspection SimplifiableIfStatement
                if (_constraint.getValidationType()==ValidationType.LIST) {
                        return _suppress_dropdown_arrow;
                }
@@ -148,6 +151,13 @@ public final class HSSFDataValidation implements DataValidation {
         * @see org.apache.poi.hssf.usermodel.DataValidation#createPromptBox(java.lang.String, java.lang.String)
         */
        public void createPromptBox(String title, String text) {
+               // check length-limits
+               if(title != null && title.length() > 32) {
+                       throw new IllegalStateException("Prompt-title cannot be longer than 32 characters, but had: " + title);
+               }
+               if(text != null && text.length() > 255) {
+                       throw new IllegalStateException("Prompt-text cannot be longer than 255 characters, but had: " + text);
+               }
                _prompt_title = title;
                _prompt_text = text;
                this.setShowPromptBox(true);
@@ -171,6 +181,12 @@ public final class HSSFDataValidation implements DataValidation {
         * @see org.apache.poi.hssf.usermodel.DataValidation#createErrorBox(java.lang.String, java.lang.String)
         */
        public void createErrorBox(String title, String text) {
+               if(title != null && title.length() > 32) {
+                       throw new IllegalStateException("Error-title cannot be longer than 32 characters, but had: " + title);
+               }
+               if(text != null && text.length() > 255) {
+                       throw new IllegalStateException("Error-text cannot be longer than 255 characters, but had: " + text);
+               }
                _error_title = title;
                _error_text = text;
                this.setShowErrorBox(true);
index c204e86a8df68b696c1deebdd00a3bb9ef096cd7..4c42a3c17b47151b6c41e7e15e76d25abb7d9d49 100644 (file)
@@ -103,6 +103,13 @@ public class XSSFDataValidation implements DataValidation {
         * @see org.apache.poi.ss.usermodel.DataValidation#createErrorBox(java.lang.String, java.lang.String)
         */
        public void createErrorBox(String title, String text) {
+               // the spec does not specify a length-limit, however Excel reports files as "corrupt" if they exceed 255 bytes for these texts...
+               if(title != null && title.length() > 255) {
+                       throw new IllegalStateException("Error-title cannot be longer than 32 characters, but had: " + title);
+               }
+               if(text != null && text.length() > 255) {
+                       throw new IllegalStateException("Error-text cannot be longer than 255 characters, but had: " + text);
+               }
                ctDdataValidation.setErrorTitle(title);
                ctDdataValidation.setError(text);
        }
@@ -111,6 +118,13 @@ public class XSSFDataValidation implements DataValidation {
         * @see org.apache.poi.ss.usermodel.DataValidation#createPromptBox(java.lang.String, java.lang.String)
         */
        public void createPromptBox(String title, String text) {
+               // the spec does not specify a length-limit, however Excel reports files as "corrupt" if they exceed 255 bytes for these texts...
+               if(title != null && title.length() > 255) {
+                       throw new IllegalStateException("Error-title cannot be longer than 32 characters, but had: " + title);
+               }
+               if(text != null && text.length() > 255) {
+                       throw new IllegalStateException("Error-text cannot be longer than 255 characters, but had: " + text);
+               }
                ctDdataValidation.setPromptTitle(title);
                ctDdataValidation.setPrompt(text);
        }
@@ -237,14 +251,12 @@ public class XSSFDataValidation implements DataValidation {
        }
        
     private static XSSFDataValidationConstraint getConstraint(CTDataValidation ctDataValidation) {
-       XSSFDataValidationConstraint constraint = null;
        String formula1 = ctDataValidation.getFormula1();
        String formula2 = ctDataValidation.getFormula2();
        Enum operator = ctDataValidation.getOperator();
        org.openxmlformats.schemas.spreadsheetml.x2006.main.STDataValidationType.Enum type = ctDataValidation.getType();
                Integer validationType = XSSFDataValidation.validationTypeReverseMappings.get(type);
                Integer operatorType = XSSFDataValidation.operatorTypeReverseMappings.get(operator);
-               constraint = new XSSFDataValidationConstraint(validationType,operatorType, formula1,formula2);
-       return constraint;
+               return new XSSFDataValidationConstraint(validationType,operatorType, formula1,formula2);
     }
 }
index b5649ef995a720a6849a9b71fa3dde3f41473a86..309155ca2d7cb06765bdebfeb9417ed4234d2fa0 100644 (file)
@@ -21,6 +21,7 @@ import org.apache.poi.hssf.usermodel.HSSFWorkbook;
 import org.apache.poi.ss.ITestDataProvider;
 import org.apache.poi.ss.SpreadsheetVersion;
 import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.ss.util.CellRangeAddressList;
 import org.apache.poi.ss.util.PaneInformation;
 import org.apache.poi.ss.util.SheetUtil;
 import org.apache.poi.util.POILogFactory;
@@ -36,6 +37,7 @@ import java.awt.geom.Rectangle2D;
 import java.io.IOException;
 import java.text.AttributedString;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 import static org.junit.Assert.*;
@@ -46,9 +48,12 @@ import static org.junit.Assert.*;
  * @author Yegor Kozlov
  */
 public abstract class BaseTestBugzillaIssues {
-    
     private static final POILogger logger = POILogFactory.getLogger(BaseTestBugzillaIssues.class);
 
+    private static final String TEST_32 = "Some text with 32 characters to ";
+    private static final String TEST_255 = "Some very long text that is exactly 255 characters, which are allowed here, bla bla, bla bla, bla bla, bla bla, bla bla, bla bla, bla bla, bla bla, bla bla, bla bla, bla bla, bla bla, bla bla, bla bla, bla bla, bla bla, bla bla, bla bla, bla bla, bla.....";
+    private static final String TEST_256 = "Some very long text that is longer than the 255 characters allowed in HSSF here, bla bla, bla bla, bla bla, bla bla, bla bla, bla bla, bla bla, bla bla, bla bla, bla bla, bla bla, bla bla, bla bla, bla bla, bla bla, bla bla, bla bla, bla bla, bla bla, bla1";
+
     private final ITestDataProvider _testDataProvider;
 
     protected BaseTestBugzillaIssues(ITestDataProvider testDataProvider) {
@@ -477,7 +482,7 @@ public abstract class BaseTestBugzillaIssues {
         String txt = lines[0] + "0";
 
         AttributedString str = new AttributedString(txt);
-        copyAttributes(font, str, 0, txt.length());
+        copyAttributes(font, str, txt.length());
 
         // TODO: support rich text fragments
         /*if (rt.numFormattingRuns() > 0) {
@@ -496,18 +501,18 @@ public abstract class BaseTestBugzillaIssues {
     private double computeCellWidthFixed(Font font, String txt) {
         final FontRenderContext fontRenderContext = new FontRenderContext(null, true, true);
         AttributedString str = new AttributedString(txt);
-        copyAttributes(font, str, 0, txt.length());
+        copyAttributes(font, str, txt.length());
 
         TextLayout layout = new TextLayout(str.getIterator(), fontRenderContext);
         return getFrameWidth(layout);
     }
 
-    private static void copyAttributes(Font font, AttributedString str, int startIdx, int endIdx) {
-        str.addAttribute(TextAttribute.FAMILY, font.getFontName(), startIdx, endIdx);
+    private static void copyAttributes(Font font, AttributedString str, int endIdx) {
+        str.addAttribute(TextAttribute.FAMILY, font.getFontName(), 0, endIdx);
         str.addAttribute(TextAttribute.SIZE, (float)font.getFontHeightInPoints());
-        if (font.getBoldweight() == Font.BOLDWEIGHT_BOLD) str.addAttribute(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD, startIdx, endIdx);
-        if (font.getItalic() ) str.addAttribute(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE, startIdx, endIdx);
-        if (font.getUnderline() == Font.U_SINGLE ) str.addAttribute(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON, startIdx, endIdx);
+        if (font.getBold()) str.addAttribute(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD, 0, endIdx);
+        if (font.getItalic() ) str.addAttribute(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE, 0, endIdx);
+        if (font.getUnderline() == Font.U_SINGLE ) str.addAttribute(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON, 0, endIdx);
     }
 
     /**
@@ -1020,6 +1025,7 @@ public abstract class BaseTestBugzillaIssues {
         wb.close();
     }
 
+    @SuppressWarnings("deprecation")
     @Test
     public void bug56981() throws IOException {
         Workbook wb = _testDataProvider.createWorkbook();
@@ -1095,7 +1101,7 @@ public abstract class BaseTestBugzillaIssues {
         Font font = wb.createFont();
         font.setFontName("Arial");
         font.setFontHeightInPoints((short)14);
-        font.setBoldweight(Font.BOLDWEIGHT_BOLD);
+        font.setBold(true);
         font.setColor(IndexedColors.RED.getIndex());
         str2.applyFont(font);
 
@@ -1276,6 +1282,7 @@ public abstract class BaseTestBugzillaIssues {
         wb2.close();
     }
 
+    @SuppressWarnings("deprecation")
     @Test
     public void bug58260() throws IOException {
         //Create workbook and worksheet
@@ -1779,4 +1786,61 @@ public abstract class BaseTestBugzillaIssues {
         
         wb.close();
     }
+
+    @Test
+    public void test59200() throws IOException {
+        Workbook wb = _testDataProvider.createWorkbook();
+        final Sheet sheet = wb.createSheet();
+
+        DataValidation dataValidation;
+        CellRangeAddressList headerCell = new CellRangeAddressList(0, 1, 0, 1);
+        DataValidationConstraint constraint = sheet.getDataValidationHelper().createCustomConstraint("A1<>\"\"");
+
+        dataValidation = sheet.getDataValidationHelper().createValidation(constraint, headerCell);
+
+        // HSSF has 32/255 limits as part of the Spec, XSSF has no limit in the spec, but Excel applies a 255 length limit!
+        // more than 255 fail for all
+        checkFailures(dataValidation, TEST_256, TEST_32, true);
+        checkFailures(dataValidation, TEST_32, TEST_256, true);
+        // more than 32 title fail for HSSFWorkbook
+        checkFailures(dataValidation, TEST_255, TEST_32, wb instanceof HSSFWorkbook);
+        // 32 length title and 255 length text wrok for both
+        checkFailures(dataValidation, TEST_32, TEST_255, false);
+
+        dataValidation.setShowErrorBox(false);
+        sheet.addValidationData(dataValidation);
+
+        // write out and read back in to trigger some more validation
+        final Workbook wbBack = _testDataProvider.writeOutAndReadBack(wb);
+
+        final Sheet sheetBack = wbBack.getSheetAt(0);
+        final List<? extends DataValidation> dataValidations = sheetBack.getDataValidations();
+        assertEquals(1, dataValidations.size());
+
+        /*String ext = (wb instanceof HSSFWorkbook) ? ".xls" : ".xlsx";
+        OutputStream str = new FileOutputStream("C:\\temp\\59200" + ext);
+        try {
+            wb.write(str);
+        } finally {
+            str.close();
+        }*/
+
+        wb.close();
+    }
+
+    private void checkFailures(DataValidation dataValidation, String title, String text, boolean shouldFail) {
+        try {
+            dataValidation.createPromptBox(title, text);
+            assertFalse("Should fail in a length-check, had " + title.length() + " and " + text.length(), shouldFail);
+        } catch (IllegalStateException e) {
+            assertTrue("Should not fail in a length-check, had " + title.length() + " and " + text.length(), shouldFail);
+            // expected here
+        }
+        try {
+            dataValidation.createErrorBox(title, text);
+            assertFalse("Should fail in a length-check, had " + title.length() + " and " + text.length(), shouldFail);
+        } catch (IllegalStateException e) {
+            assertTrue("Should not fail in a length-check, had " + title.length() + " and " + text.length(), shouldFail);
+        }
+    }
 }
\ No newline at end of file