]> source.dussan.org Git - poi.git/commitdiff
Merged revisions 638786-638802,638805-638811,638813-638814,638816-639230,639233-63924...
authorNick Burch <nick@apache.org>
Mon, 28 Jul 2008 21:27:16 +0000 (21:27 +0000)
committerNick Burch <nick@apache.org>
Mon, 28 Jul 2008 21:27:16 +0000 (21:27 +0000)
https://svn.apache.org:443/repos/asf/poi/trunk

........
  r678539 | nick | 2008-07-21 20:35:47 +0100 (Mon, 21 Jul 2008) | 1 line

  Fix bug #45437 - Detect encrypted word documents, and throw an EncryptedDocumentException instead of a OOM
........
  r680394 | nick | 2008-07-28 17:41:47 +0100 (Mon, 28 Jul 2008) | 1 line

  Fix for DataFormatter on some JVMs
........
  r680470 | josh | 2008-07-28 21:08:15 +0100 (Mon, 28 Jul 2008) | 1 line

  More tweaks for bug 45404.  Fixes for JDK 1.4, improved member scoping and formatting.
........

git-svn-id: https://svn.apache.org/repos/asf/poi/branches/ooxml@680509 13f79535-47bb-0310-9956-ffa450edef68

src/documentation/content/xdocs/changes.xml
src/documentation/content/xdocs/status.xml
src/java/org/apache/poi/EncryptedDocumentException.java [new file with mode: 0644]
src/java/org/apache/poi/hssf/usermodel/HSSFDataFormatter.java
src/scratchpad/src/org/apache/poi/hslf/exceptions/EncryptedPowerPointFileException.java
src/scratchpad/src/org/apache/poi/hwpf/HWPFDocument.java
src/scratchpad/testcases/org/apache/poi/hwpf/data/PasswordProtected.doc [new file with mode: 0644]
src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestProblems.java
src/testcases/org/apache/poi/hssf/usermodel/AllUserModelTests.java
src/testcases/org/apache/poi/hssf/usermodel/TestHSSFDataFormatter.java

index 43d6bb7b167a5ec8cf9d39069f0dd3d5c60839f0..12bce0ccf5321546e48399c3ad134df5676ee1ae 100644 (file)
@@ -51,6 +51,7 @@
            <action dev="POI-DEVELOPERS" type="add">Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx</action>
         </release>
         <release version="3.1.1-alpha1" date="2008-??-??">
+           <action dev="POI-DEVELOPERS" type="fix">45437 - Detect encrypted word documents, and throw an EncryptedDocumentException instead of a OOM</action>
            <action dev="POI-DEVELOPERS" type="add">45404 - New class, hssf.usermodel.HSSFDataFormatter, for formatting numbers and dates in the same way that Excel does</action>
            <action dev="POI-DEVELOPERS" type="fix">45414 - Don't add too many UncalcedRecords to sheets with charts in them</action>
            <action dev="POI-DEVELOPERS" type="fix">45398 - Support detecting date formats containing "am/pm" as date times</action>
index f1f81d06993f4a00aef69cd4d26bae5b041267ce..3b6644db96572c851a66cf2d003d68cc22a1d8f7 100644 (file)
@@ -48,6 +48,7 @@
            <action dev="POI-DEVELOPERS" type="add">Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx</action>
         </release>
         <release version="3.1.1-alpha1" date="2008-??-??">
+           <action dev="POI-DEVELOPERS" type="fix">45437 - Detect encrypted word documents, and throw an EncryptedDocumentException instead of a OOM</action>
            <action dev="POI-DEVELOPERS" type="add">45404 - New class, hssf.usermodel.HSSFDataFormatter, for formatting numbers and dates in the same way that Excel does</action>
            <action dev="POI-DEVELOPERS" type="fix">45414 - Don't add too many UncalcedRecords to sheets with charts in them</action>
            <action dev="POI-DEVELOPERS" type="fix">45398 - Support detecting date formats containing "am/pm" as date times</action>
diff --git a/src/java/org/apache/poi/EncryptedDocumentException.java b/src/java/org/apache/poi/EncryptedDocumentException.java
new file mode 100644 (file)
index 0000000..4922d1c
--- /dev/null
@@ -0,0 +1,24 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+package org.apache.poi;
+
+public class EncryptedDocumentException extends IllegalStateException
+{
+       public EncryptedDocumentException(String s) {
+               super(s);
+       }
+}
index c1701e22b39aef91b6a9fe018909d1e77051de69..67291a22f1f255bd6343893cc432f95d63c1f022 100644 (file)
@@ -68,78 +68,64 @@ import java.util.regex.Pattern;
  * can override the default format pattern with <code>
  * HSSFDataFormatter.setDefaultNumberFormat(Format)</code>. <b>Note:</b> the
  * default format will only be used when a Format cannot be created from the
- * cell's data format string.  
- * 
+ * cell's data format string.
+ *
  * @author James May (james dot may at fmr dot com)
  *
  */
-public class HSSFDataFormatter {
+public final class HSSFDataFormatter {
 
        /** Pattern to find a number format: "0" or  "#" */
-       protected Pattern numPattern;
-       
+       private static final Pattern numPattern = Pattern.compile("[0#]+");
+
        /** Pattern to find days of week as text "ddd...." */
-       protected Pattern daysAsText;
-       
+       private static final Pattern daysAsText = Pattern.compile("([d]{3,})", Pattern.CASE_INSENSITIVE);
+
        /** Pattern to find "AM/PM" marker */
-       protected Pattern amPmPattern;
+       private static final Pattern amPmPattern = Pattern.compile("((A|P)[M/P]*)", Pattern.CASE_INSENSITIVE);
 
        /** A regex to find patterns like [$$-1009] and [$�-452]. */
-       protected Pattern specialPatternGroup;
-       
+       private static final Pattern specialPatternGroup = Pattern.compile("(\\[\\$[^-\\]]*-[0-9A-Z]+\\])");
+
        /** <em>General</em> format for whole numbers. */
-       protected Format generalWholeNumFormat;
-       
+       private static final Format generalWholeNumFormat = new DecimalFormat("#");
+
        /** <em>General</em> format for decimal numbers. */
-       protected Format generalDecimalNumFormat;       
-       
+       private static final Format generalDecimalNumFormat = new DecimalFormat("#.##########");
+
        /** A default format to use when a number pattern cannot be parsed. */
-       protected Format defaultNumFormat;
-       
-       /** 
+       private Format defaultNumFormat;
+
+       /**
         * A map to cache formats.
         *  Map<String,Format> formats
         */
-       protected Map formats;
-       
+       private final Map formats;
 
        /**
         * Constructor
         */
        public HSSFDataFormatter() {
-               numPattern = Pattern.compile("[0#]+");
-               daysAsText = Pattern.compile("([d]{3,})", Pattern.CASE_INSENSITIVE);
-               amPmPattern = Pattern.compile("((A|P)[M/P]*)", Pattern.CASE_INSENSITIVE);
-               specialPatternGroup = Pattern.compile("(\\[\\$[^-\\]]*-[0-9A-Z]+\\])");
-               generalWholeNumFormat =  new DecimalFormat("#");
-               generalDecimalNumFormat =  new DecimalFormat("#.##########");   
                formats = new HashMap();
-               
+
                // init built-in formats
-               init();
-       }
 
-       /**
-        * Initialize the formatter. Called after construction.
-        */
-       protected void init() {         
-               
-               ZipPlusFourFormat zipFormat = new ZipPlusFourFormat();
+               Format zipFormat = ZipPlusFourFormat.instance;
                addFormat("00000\\-0000", zipFormat);
                addFormat("00000-0000", zipFormat);
-               
-               PhoneFormat phoneFormat = new PhoneFormat();
+
+               Format phoneFormat = PhoneFormat.instance;
                // allow for format string variations
                addFormat("[<=9999999]###\\-####;\\(###\\)\\ ###\\-####", phoneFormat);
                addFormat("[<=9999999]###-####;(###) ###-####", phoneFormat);
                addFormat("###\\-####;\\(###\\)\\ ###\\-####", phoneFormat);
-               addFormat("###-####;(###) ###-####", phoneFormat);              
-               
-               SSNFormat ssnFormat = new SSNFormat();
-               addFormat("000\\-00\\-0000", ssnFormat);                
-               addFormat("000-00-0000", ssnFormat);                    
+               addFormat("###-####;(###) ###-####", phoneFormat);
+
+               Format ssnFormat = SSNFormat.instance;
+               addFormat("000\\-00\\-0000", ssnFormat);
+               addFormat("000-00-0000", ssnFormat);
        }
-       
+
        /**
         * Return a Format for the given cell if one exists, otherwise try to
         * create one. This method will return <code>null</code> if the any of the
@@ -149,15 +135,15 @@ public class HSSFDataFormatter {
         * <li>the style's data format string is null or empty</li>
         * <li>the format string cannot be recognized as either a number or date</li>
         * </ul>
-        * 
+        *
         * @param cell The cell to retrieve a Format for
         * @return A Format for the format String
         */
-       protected Format getFormat(HSSFCell cell) {
+       private Format getFormat(HSSFCell cell) {
                if ( cell.getCellStyle() == null) {
                        return null;
                }
-               
+
                int formatIndex = cell.getCellStyle().getDataFormat();
                String formatStr = cell.getCellStyle().getDataFormatString();
                if(formatStr == null || formatStr.trim().length() == 0) {
@@ -165,380 +151,375 @@ public class HSSFDataFormatter {
                }
                return getFormat(cell.getNumericCellValue(), formatIndex, formatStr);
        }
-       
+
        private Format getFormat(double cellValue, int formatIndex, String formatStr) {
                Format format = (Format)formats.get(formatStr);
                if (format != null) {
                        return format;
-               } else if (formatStr.equals("General")) {
+               }
+               if (formatStr.equals("General")) {
                        if (HSSFDataFormatter.isWholeNumber(cellValue)) {
                                return generalWholeNumFormat;
-                       } else {
-                               return generalDecimalNumFormat;
                        }
-               } else {
-                       format = createFormat(cellValue, formatIndex, formatStr);
-                       formats.put(formatStr, format);
-                       return format;
+                       return generalDecimalNumFormat;
                }
+               format = createFormat(cellValue, formatIndex, formatStr);
+               formats.put(formatStr, format);
+               return format;
        }
-       
+
        /**
         * Create and return a Format based on the format string from a  cell's
         * style. If the pattern cannot be parsed, return a default pattern.
-        * 
+        *
         * @param cell The Excel cell
         * @return A Format representing the excel format. May return null.
         */
-       protected Format createFormat(HSSFCell cell) {  
-               String sFormat = cell.getCellStyle().getDataFormatString();
-               
+       public Format createFormat(HSSFCell cell) {
+
                int formatIndex = cell.getCellStyle().getDataFormat();
                String formatStr = cell.getCellStyle().getDataFormatString();
-               return createFormat(cell.getNumericCellValue(), formatIndex, formatStr); 
+               return createFormat(cell.getNumericCellValue(), formatIndex, formatStr);
        }
-       
+
        private Format createFormat(double cellValue, int formatIndex, String sFormat) {
                // remove color formatting if present
                String formatStr = sFormat.replaceAll("\\[[a-zA-Z]*\\]", "");
-               
+
                // try to extract special characters like currency
-               Matcher m = specialPatternGroup.matcher(formatStr);             
-               try {
-                       while(m.find()) {
-                               String match = m.group();
-                               String symbol = match.substring(match.indexOf('$') + 1, match.indexOf('-'));
-                               if (symbol.indexOf('$') > -1) {
-                                       StringBuffer sb = new StringBuffer();
-                                       sb.append(symbol.substring(0, symbol.indexOf('$')));
-                                       sb.append('\\');
-                                       sb.append(symbol.substring(symbol.indexOf('$'), symbol.length()));
-                                       symbol = sb.toString();
-                               }
-                               formatStr = m.replaceAll(symbol);
+               Matcher m = specialPatternGroup.matcher(formatStr);
+               while(m.find()) {
+                       String match = m.group();
+                       String symbol = match.substring(match.indexOf('$') + 1, match.indexOf('-'));
+                       if (symbol.indexOf('$') > -1) {
+                               StringBuffer sb = new StringBuffer();
+                               sb.append(symbol.substring(0, symbol.indexOf('$')));
+                               sb.append('\\');
+                               sb.append(symbol.substring(symbol.indexOf('$'), symbol.length()));
+                               symbol = sb.toString();
                        }
-               } catch (Exception e) {
-                       return getDefaultFormat(cellValue);
+                       formatStr = m.replaceAll(symbol);
+                       m = specialPatternGroup.matcher(formatStr);
                }
-               
+
                if(formatStr == null || formatStr.trim().length() == 0) {
                        return getDefaultFormat(cellValue);
                }
 
-               Format returnVal = null;
-               StringBuffer sb = null;
-
-       if(HSSFDateUtil.isADateFormat(formatIndex,formatStr) &&
-                       HSSFDateUtil.isValidExcelDate(cellValue)) {
-               formatStr = formatStr.replaceAll("\\\\-","-");
-               formatStr = formatStr.replaceAll("\\\\,",",");
-               formatStr = formatStr.replaceAll("\\\\ "," ");
-               formatStr = formatStr.replaceAll(";@", "");
-               boolean hasAmPm = false;
-               Matcher amPmMatcher = amPmPattern.matcher(formatStr);
-               while (amPmMatcher.find()) {
-                       formatStr = amPmMatcher.replaceAll("a");
-                       hasAmPm = true;
-               }
-               
-               Matcher dateMatcher = daysAsText.matcher(formatStr);
-               if (dateMatcher.find()) {
-                               String match = dateMatcher.group(0);
-                               formatStr = dateMatcher.replaceAll(match.toUpperCase().replaceAll("D", "E"));
-               }
-               
-               // Convert excel date format to SimpleDateFormat.
-               // Excel uses lower case 'm' for both minutes and months.
-               // From Excel help:
-               /* 
-                         The "m" or "mm" code must appear immediately after the "h" or"hh"
-                         code or immediately before the "ss" code; otherwise, Microsoft
-                         Excel displays the month instead of minutes."
-                       */
-               
-               sb = new StringBuffer();
-               char[] chars = formatStr.toCharArray();
-               boolean mIsMonth = true;
-               List ms = new ArrayList();
-               for(int j=0; j<chars.length; j++) {
-                       char c = chars[j];
-                       if (c == 'h' || c == 'H') {
-                               mIsMonth = false;
-                               if (hasAmPm) {
-                                       sb.append('h');
-                               } else {
-                                       sb.append('H');
-                               }                               
-                       }
-                       else if (c == 'm') {
-                               if(mIsMonth) {
-                                       sb.append('M');
-                                       ms.add(
-                                                       new Integer(sb.length() -1)
-                                       );
-                               } else {
-                                       sb.append('m');
-                               }
-                       }
-                       else if (c == 's' || c == 'S') {
-                               sb.append('s');
-                               // if 'M' precedes 's' it should be minutes ('m') 
-                               for (int i = 0; i < ms.size(); i++) {
-                                       int index = ((Integer)ms.get(i)).intValue();
-                                       if (sb.charAt(index) == 'M') {
-                                               sb.replace(index, index+1, "m");
-                                       }
-                               }
-                               mIsMonth = true;
-                               ms.clear();
-                       }
-                       else if (Character.isLetter(c)) {
-                               mIsMonth = true;
-                               ms.clear();
-                               if (c == 'y' || c == 'Y') {
-                                       sb.append('y');
-                               }
-                               else if (c == 'd' || c == 'D') {
-                                       sb.append('d');                         
-                               }
-                               else {
-                                       sb.append(c);
-                               }                               
-                       }
-                       else {
-                               sb.append(c);
-                       }
-               }
-                       formatStr = sb.toString();
-                       
-                       try {
-                               returnVal = new SimpleDateFormat(formatStr);                            
-                       } catch(IllegalArgumentException iae) {
-                               
-                               // the pattern could not be parsed correctly,
-                               // so fall back to the default number format
-                               return getDefaultFormat(cellValue);
-                       }               
-                       
-               } else if (numPattern.matcher(formatStr).find()) {
-                       sb = new StringBuffer(formatStr);
-                       for (int i = 0; i < sb.length(); i++) {
-                               char c = sb.charAt(i);
-                               //handle (#,##0_);
-                               if (c == '(') {
-                                       int idx = sb.indexOf(")", i);
-                                       if (idx > -1 && sb.charAt(idx -1) == '_') {
-                                               sb.deleteCharAt(idx);
-                                               sb.deleteCharAt(idx - 1);
-                                               sb.deleteCharAt(i);
-                                               i--;
+
+               if(HSSFDateUtil.isADateFormat(formatIndex,formatStr) &&
+                               HSSFDateUtil.isValidExcelDate(cellValue)) {
+                       return createDateFormat(formatStr, cellValue);
+               }
+               if (numPattern.matcher(formatStr).find()) {
+                       return createNumberFormat(formatStr, cellValue);
+               }
+               // TODO - when does this occur?
+               return null;
+       }
+
+       private Format createDateFormat(String pFormatStr, double cellValue) {
+               String formatStr = pFormatStr;
+               formatStr = formatStr.replaceAll("\\\\-","-");
+               formatStr = formatStr.replaceAll("\\\\,",",");
+               formatStr = formatStr.replaceAll("\\\\ "," ");
+               formatStr = formatStr.replaceAll(";@", "");
+               boolean hasAmPm = false;
+               Matcher amPmMatcher = amPmPattern.matcher(formatStr);
+               while (amPmMatcher.find()) {
+                       formatStr = amPmMatcher.replaceAll("@");
+                       hasAmPm = true;
+                       amPmMatcher = amPmPattern.matcher(formatStr);
+               }
+               formatStr = formatStr.replaceAll("@", "a");
+
+
+               Matcher dateMatcher = daysAsText.matcher(formatStr);
+               if (dateMatcher.find()) {
+                       String match = dateMatcher.group(0);
+                       formatStr = dateMatcher.replaceAll(match.toUpperCase().replaceAll("D", "E"));
+               }
+
+               // Convert excel date format to SimpleDateFormat.
+               // Excel uses lower case 'm' for both minutes and months.
+               // From Excel help:
+               /*
+                 The "m" or "mm" code must appear immediately after the "h" or"hh"
+                 code or immediately before the "ss" code; otherwise, Microsoft
+                 Excel displays the month instead of minutes."
+               */
+
+               StringBuffer sb = new StringBuffer();
+               char[] chars = formatStr.toCharArray();
+               boolean mIsMonth = true;
+               List ms = new ArrayList();
+               for(int j=0; j<chars.length; j++) {
+                       char c = chars[j];
+                       if (c == 'h' || c == 'H') {
+                               mIsMonth = false;
+                               if (hasAmPm) {
+                                       sb.append('h');
+                               } else {
+                                       sb.append('H');
+                               }
+                       }
+                       else if (c == 'm') {
+                               if(mIsMonth) {
+                                       sb.append('M');
+                                       ms.add(
+                                                       new Integer(sb.length() -1)
+                                       );
+                               } else {
+                                       sb.append('m');
+                               }
+                       }
+                       else if (c == 's' || c == 'S') {
+                               sb.append('s');
+                               // if 'M' precedes 's' it should be minutes ('m')
+                               for (int i = 0; i < ms.size(); i++) {
+                                       int index = ((Integer)ms.get(i)).intValue();
+                                       if (sb.charAt(index) == 'M') {
+                                               sb.replace(index, index+1, "m");
                                        }
-                               } else if (c == ')' && i > 0 && sb.charAt(i - 1) == '_') {
-                                       sb.deleteCharAt(i);
-                                       sb.deleteCharAt(i - 1);
-                                       i--;
-                               // remove quotes and back slashes
-                               } else if (c == '\\' || c == '"') {
-                                       sb.deleteCharAt(i);
-                                       i--;
-                                       
-                               // for scientific/engineering notation
-                               } else if (c == '+' && i > 0 && sb.charAt(i - 1) == 'E') {
+                               }
+                               mIsMonth = true;
+                               ms.clear();
+                       }
+                       else if (Character.isLetter(c)) {
+                               mIsMonth = true;
+                               ms.clear();
+                               if (c == 'y' || c == 'Y') {
+                                       sb.append('y');
+                               }
+                               else if (c == 'd' || c == 'D') {
+                                       sb.append('d');
+                               }
+                               else {
+                                       sb.append(c);
+                               }
+                       }
+                       else {
+                               sb.append(c);
+                       }
+               }
+               formatStr = sb.toString();
+
+               try {
+                       return new SimpleDateFormat(formatStr);
+               } catch(IllegalArgumentException iae) {
+
+                       // the pattern could not be parsed correctly,
+                       // so fall back to the default number format
+                       return getDefaultFormat(cellValue);
+               }
+
+       }
+
+       private Format createNumberFormat(String formatStr, double cellValue) {
+               StringBuffer sb = new StringBuffer(formatStr);
+               for (int i = 0; i < sb.length(); i++) {
+                       char c = sb.charAt(i);
+                       //handle (#,##0_);
+                       if (c == '(') {
+                               int idx = sb.indexOf(")", i);
+                               if (idx > -1 && sb.charAt(idx -1) == '_') {
+                                       sb.deleteCharAt(idx);
+                                       sb.deleteCharAt(idx - 1);
                                        sb.deleteCharAt(i);
                                        i--;
-                               }                                                       
-                       }
-                       formatStr = sb.toString();
-                       try {
-                               returnVal = new DecimalFormat(formatStr);                               
-                       } catch(IllegalArgumentException iae) {
+                               }
+                       } else if (c == ')' && i > 0 && sb.charAt(i - 1) == '_') {
+                               sb.deleteCharAt(i);
+                               sb.deleteCharAt(i - 1);
+                               i--;
+                       // remove quotes and back slashes
+                       } else if (c == '\\' || c == '"') {
+                               sb.deleteCharAt(i);
+                               i--;
 
-                               // the pattern could not be parsed correctly,
-                               // so fall back to the default number format
-                               return getDefaultFormat(cellValue);
+                       // for scientific/engineering notation
+                       } else if (c == '+' && i > 0 && sb.charAt(i - 1) == 'E') {
+                               sb.deleteCharAt(i);
+                               i--;
                        }
                }
-               return returnVal;
+
+               try {
+                       return new DecimalFormat(sb.toString());
+               } catch(IllegalArgumentException iae) {
+
+                       // the pattern could not be parsed correctly,
+                       // so fall back to the default number format
+                       return getDefaultFormat(cellValue);
+               }
        }
-       
+
        /**
         * Return true if the double value represents a whole number
         * @param d the double value to check
-        * @return true if d is a whole number
+        * @return <code>true</code> if d is a whole number
         */
        private static boolean isWholeNumber(double d) {
                return d == Math.floor(d);
        }
-       
+
        /**
         * Returns a default format for a cell.
         * @param cell The cell
         * @return a default format
         */
-       protected Format getDefaultFormat(HSSFCell cell) {
+       public Format getDefaultFormat(HSSFCell cell) {
                return getDefaultFormat(cell.getNumericCellValue());
        }
        private Format getDefaultFormat(double cellValue) {
                // for numeric cells try user supplied default
                if (defaultNumFormat != null) {
                        return defaultNumFormat;
-                       
-                 // otherwise use general format       
-               } else if (isWholeNumber(cellValue)){
+
+                 // otherwise use general format
+               }
+               if (isWholeNumber(cellValue)){
                        return generalWholeNumFormat;
-               } else {
-                       return generalDecimalNumFormat;
                }
+               return generalDecimalNumFormat;
        }
-       
+
        /**
         * Returns the formatted value of an Excel date as a <tt>String</tt> based
         * on the cell's <code>DataFormat</code>. i.e. "Thursday, January 02, 2003"
         * , "01/02/2003" , "02-Jan" , etc.
-        * 
+        *
         * @param cell The cell
         * @return a formatted date string
-        */      
-    protected String getFormattedDateString(HSSFCell cell) {
-       Format dateFormat = getFormat(cell);
-       Date d = cell.getDateCellValue();
-       if (dateFormat != null) {
-               return dateFormat.format(d);
-       } else {
-               return d.toString();
-       }
-    }
-    
+        */
+       private String getFormattedDateString(HSSFCell cell) {
+               Format dateFormat = getFormat(cell);
+               Date d = cell.getDateCellValue();
+               if (dateFormat != null) {
+                       return dateFormat.format(d);
+               }
+               return d.toString();
+       }
+
        /**
         * Returns the formatted value of an Excel number as a <tt>String</tt>
         * based on the cell's <code>DataFormat</code>. Supported formats include
         * currency, percents, decimals, phone number, SSN, etc.:
         * "61.54%", "$100.00", "(800) 555-1234".
-        * 
+        *
         * @param cell The cell
         * @return a formatted number string
-        */ 
-    protected String getFormattedNumberString(HSSFCell cell) {
-       
-       Format numberFormat = getFormat(cell);
-       double d = cell.getNumericCellValue();
-       if (numberFormat != null) {
-               return numberFormat.format(new Double(d));
-       } else {
-               return String.valueOf(d);
-       }       
-    }
-
-    /**
-     * Formats the given raw cell value, based on the supplied
-     *  format index and string, according to excel style rules.
-     * @see #formatCellValue(HSSFCell)
-     */
-    public String formatRawCellContents(double value, int formatIndex, String formatString) {
-       // Is it a date?
-       if(HSSFDateUtil.isADateFormat(formatIndex,formatString) &&
-                       HSSFDateUtil.isValidExcelDate(value)) {
-               
-               Format dateFormat = getFormat(value, formatIndex, formatString);
-               Date d = HSSFDateUtil.getJavaDate(value);
-               if (dateFormat != null) {
-                       return dateFormat.format(d);
-               } else {
-                       return d.toString();
-               }
-       } else {
-               // Number
-               Format numberFormat = getFormat(value, formatIndex, formatString);
-               if (numberFormat != null) {
-                       return numberFormat.format(new Double(value));
-               } else {
-                       return String.valueOf(value);
-               }       
-       }
-    }
-    
+        */
+       private String getFormattedNumberString(HSSFCell cell) {
+
+               Format numberFormat = getFormat(cell);
+               double d = cell.getNumericCellValue();
+               if (numberFormat == null) {
+                       return String.valueOf(d);
+               }
+               return numberFormat.format(new Double(d));
+       }
+
+       /**
+        * Formats the given raw cell value, based on the supplied
+        *  format index and string, according to excel style rules.
+        * @see #formatCellValue(HSSFCell)
+        */
+       public String formatRawCellContents(double value, int formatIndex, String formatString) {
+               // Is it a date?
+               if(HSSFDateUtil.isADateFormat(formatIndex,formatString) &&
+                               HSSFDateUtil.isValidExcelDate(value)) {
+
+                       Format dateFormat = getFormat(value, formatIndex, formatString);
+                       Date d = HSSFDateUtil.getJavaDate(value);
+                       if (dateFormat == null) {
+                               return d.toString();
+                       }
+                       return dateFormat.format(d);
+               }
+               // else Number
+               Format numberFormat = getFormat(value, formatIndex, formatString);
+               if (numberFormat == null) {
+                       return String.valueOf(value);
+               }
+               return numberFormat.format(new Double(value));
+       }
+
        /**
         * <p>
         * Returns the formatted value of a cell as a <tt>String</tt> regardless
         * of the cell type. If the Excel format pattern cannot be parsed then the
-        * cell value will be formatted using a default format. 
+        * cell value will be formatted using a default format.
         * </p>
         * <p>When passed a null or blank cell, this method will return an empty
         * String (""). Formulas in formula type cells will not be evaluated.
         * </p>
-        * 
+        *
         * @param cell The cell
         * @return the formatted cell value as a String
         */
        public String formatCellValue(HSSFCell cell) {
                return formatCellValue(cell, null);
        }
-    
+
        /**
         * <p>
         * Returns the formatted value of a cell as a <tt>String</tt> regardless
         * of the cell type. If the Excel format pattern cannot be parsed then the
-        * cell value will be formatted using a default format. 
+        * cell value will be formatted using a default format.
         * </p>
         * <p>When passed a null or blank cell, this method will return an empty
         * String (""). Formula cells will be evaluated using the given
         * {@link HSSFFormulaEvaluator} if the evaluator is non-null. If the
         * evaluator is null, then the formula String will be returned. The caller
-        * is responsible for setting the currentRow on the evaluator, otherwise an
-        * IllegalArgumentException may be thrown.
+        * is responsible for setting the currentRow on the evaluator
         *</p>
-        * 
-        * @param cell The cell
+        *
+        * @param cell The cell (can be null)
         * @param evaluator The HSSFFormulaEvaluator (can be null)
         * @return a string value of the cell
-        * @throws IllegalArgumentException if cell type is <code>
-        * HSSFCell.CELL_TYPE_FORMULA</code> <b>and</b> evaluator is not null
-        * <b>and</b> the evlaluator's currentRow has not been set.
         */
-       public String formatCellValue(HSSFCell cell, 
+       public String formatCellValue(HSSFCell cell,
                        HSSFFormulaEvaluator evaluator) throws IllegalArgumentException {
 
-               String value = "";
                if (cell == null) {
-                       return value;
+                       return "";
                }
-               
+
                int cellType = cell.getCellType();
                if (evaluator != null && cellType == HSSFCell.CELL_TYPE_FORMULA) {
                        try {
                                cellType = evaluator.evaluateFormulaCell(cell);
-                       } catch (Throwable t) {
-                               throw new IllegalArgumentException("Did you forget to set the current" +
-                                               " row on the HSSFFormulaEvaluator?", t);
+                       } catch (RuntimeException e) {
+                               throw new RuntimeException("Did you forget to set the current" +
+                                               " row on the HSSFFormulaEvaluator?", e);
                        }
-               }               
+               }
                switch (cellType)
-        {
-            case HSSFCell.CELL_TYPE_FORMULA :
-               // should only occur if evaluator is null
-               value = cell.getCellFormula();
-                break;
-
-            case HSSFCell.CELL_TYPE_NUMERIC :
-               
-               if (HSSFDateUtil.isCellDateFormatted(cell)) {
-                       value = getFormattedDateString(cell);
-               } else {
-                       value = getFormattedNumberString(cell);
-               }
-                break;
-
-            case HSSFCell.CELL_TYPE_STRING :
-                value = cell.getRichStringCellValue().getString();
-                break;
-                
-            case HSSFCell.CELL_TYPE_BOOLEAN :
-               value = String.valueOf(cell.getBooleanCellValue());
-        }
-               return value;
+               {
+                       case HSSFCell.CELL_TYPE_FORMULA :
+                               // should only occur if evaluator is null
+                               return cell.getCellFormula();
+
+                       case HSSFCell.CELL_TYPE_NUMERIC :
+
+                               if (HSSFDateUtil.isCellDateFormatted(cell)) {
+                                       return getFormattedDateString(cell);
+                               }
+                               return getFormattedNumberString(cell);
+
+                       case HSSFCell.CELL_TYPE_STRING :
+                               return cell.getRichStringCellValue().getString();
+
+                       case HSSFCell.CELL_TYPE_BOOLEAN :
+                               return String.valueOf(cell.getBooleanCellValue());
+                       case HSSFCell.CELL_TYPE_BLANK :
+                               return "";
+               }
+               throw new RuntimeException("Unexpected celltype (" + cellType + ")");
        }
-               
-       
+
+
        /**
         * <p>
         * Sets a default number format to be used when the Excel format cannot be
@@ -552,7 +533,7 @@ public class HSSFDataFormatter {
         * numeric cell. Therefore the code in the format method should expect a
         * <code>Number</code> value.
         * </p>
-        * 
+        *
         * @param format A Format instance to be used as a default
         * @see java.text.Format#format
         */
@@ -566,8 +547,8 @@ public class HSSFDataFormatter {
                        }
                }
                defaultNumFormat = format;
-       }       
-       
+       }
+
        /**
         * Adds a new format to the available formats.
         * <p>
@@ -575,7 +556,7 @@ public class HSSFDataFormatter {
         * by <code>java.text.Format#format</code>) will be a double value from a
         * numeric cell. Therefore the code in the format method should expect a
         * <code>Number</code> value.
-        * </p>  
+        * </p>
         * @param excelFormatStr The data format string
         * @param format A Format instance
         */
@@ -584,24 +565,30 @@ public class HSSFDataFormatter {
        }
 
        // Some custom formats
-       
+
+       /**
+        * @return a <tt>DecimalFormat</tt> with parseIntegerOnly set <code>true</code>
+        */
+       /* package */ static DecimalFormat createIntegerOnlyFormat(String fmt) {
+               DecimalFormat result = new DecimalFormat(fmt);
+               result.setParseIntegerOnly(true);
+               return result;
+       }
        /**
         * Format class for Excel's SSN format. This class mimics Excel's built-in
         * SSN formatting.
-        * 
+        *
         * @author James May
         */
-       static class SSNFormat extends Format {
-               private DecimalFormat df;
-               
-               /** Constructor */
-               public SSNFormat() {
-                       df = new DecimalFormat("000000000");
-                       df.setParseIntegerOnly(true);
-               }
-               
+       private static final class SSNFormat extends Format {
+               public static final Format instance = new SSNFormat();
+               private static final DecimalFormat df = createIntegerOnlyFormat("000000000");
+               private SSNFormat() {
+                       // enforce singleton
+               }
+
                /** Format a number as an SSN */
-               public String format(Number num) {
+               public static String format(Number num) {
                        String result = df.format(num);
                        StringBuffer sb = new StringBuffer();
                        sb.append(result.substring(0, 3)).append('-');
@@ -609,66 +596,60 @@ public class HSSFDataFormatter {
                        sb.append(result.substring(5, 9));
                        return sb.toString();
                }
-               
-               public StringBuffer format(Object obj, StringBuffer toAppendTo,
-                               FieldPosition pos) {
+
+               public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) {
                        return toAppendTo.append(format((Number)obj));
                }
-               
+
                public Object parseObject(String source, ParsePosition pos) {
                        return df.parseObject(source, pos);
                }
        }
-       
+
        /**
         * Format class for Excel Zip + 4 format. This class mimics Excel's
         * built-in formatting for Zip + 4.
         * @author James May
-        */     
-       static class ZipPlusFourFormat extends Format {
-               private DecimalFormat df;
-               
-               /** Constructor */
-               public ZipPlusFourFormat() {
-                       df = new DecimalFormat("000000000");
-                       df.setParseIntegerOnly(true);
-               }
-               
+        */
+       private static final class ZipPlusFourFormat extends Format {
+               public static final Format instance = new ZipPlusFourFormat();
+               private static final DecimalFormat df = createIntegerOnlyFormat("000000000");
+               private ZipPlusFourFormat() {
+                       // enforce singleton
+               }
+
                /** Format a number as Zip + 4 */
-               public String format(Number num) {
+               public static String format(Number num) {
                        String result = df.format(num);
                        StringBuffer sb = new StringBuffer();
                        sb.append(result.substring(0, 5)).append('-');
                        sb.append(result.substring(5, 9));
                        return sb.toString();
                }
-               
-               public StringBuffer format(Object obj, StringBuffer toAppendTo,
-                               FieldPosition pos) {
+
+               public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) {
                        return toAppendTo.append(format((Number)obj));
                }
-               
+
                public Object parseObject(String source, ParsePosition pos) {
                        return df.parseObject(source, pos);
                }
-       }       
-       
+       }
+
        /**
         * Format class for Excel phone number format. This class mimics Excel's
         * built-in phone number formatting.
         * @author James May
-        */     
-       static class PhoneFormat extends Format {
-               private DecimalFormat df;
-
-               /** Constructor */
-               public PhoneFormat() {
-                       df = new DecimalFormat("##########");
-                       df.setParseIntegerOnly(true);
+        */
+       private static final class PhoneFormat extends Format {
+               public static final Format instance = new PhoneFormat();
+               private static final DecimalFormat df = createIntegerOnlyFormat("##########");
+               private PhoneFormat() {
+                       // enforce singleton
                }
-               
+
                /** Format a number as a phone number */
-               public String format(Number num) {
+               public static String format(Number num) {
                        String result = df.format(num);
                        StringBuffer sb = new StringBuffer();
                        String seg1, seg2, seg3;
@@ -676,28 +657,27 @@ public class HSSFDataFormatter {
                        if (len <= 4) {
                                return result;
                        }
-                       
+
                        seg3 = result.substring(len - 4, len);
-                       seg2 = result.substring(Math.max(0, len - 7), len - 4); 
+                       seg2 = result.substring(Math.max(0, len - 7), len - 4);
                        seg1 = result.substring(Math.max(0, len - 10), Math.max(0, len - 7));
-                       
+
                        if(seg1 != null && seg1.trim().length() > 0) {
                                sb.append('(').append(seg1).append(") ");
                        }
                        if(seg2 != null && seg2.trim().length() > 0) {
-                               sb.append(seg2).append('-'); 
+                               sb.append(seg2).append('-');
                        }
                        sb.append(seg3);
                        return sb.toString();
                }
-               
-               public StringBuffer format(Object obj, StringBuffer toAppendTo,
-                               FieldPosition pos) {
+
+               public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) {
                        return toAppendTo.append(format((Number)obj));
                }
-               
+
                public Object parseObject(String source, ParsePosition pos) {
                        return df.parseObject(source, pos);
                }
-       }       
+       }
 }
index 77f93a10f6eba215c613b519ab8e9541b7d38b37..08eabd223b6056bfeb2a30d4174c96ab31b5ef8b 100644 (file)
@@ -1,4 +1,3 @@
-
 /* ====================================================================
    Licensed to the Apache Software Foundation (ASF) under one or more
    contributor license agreements.  See the NOTICE file distributed with
    See the License for the specific language governing permissions and
    limitations under the License.
 ==================================================================== */
-        
-
-
 package org.apache.poi.hslf.exceptions;
 
+import org.apache.poi.EncryptedDocumentException;
+
 /**
  * This exception is thrown when we try to open a PowerPoint file, and
  *  discover that it is encrypted
- *
- * @author Nick Burch
  */
-
-public class EncryptedPowerPointFileException extends IllegalStateException
+public class EncryptedPowerPointFileException extends EncryptedDocumentException
 {
        public EncryptedPowerPointFileException(String s) {
                super(s);
index a43357f02146ea1950eb4b9914e04f2b6bcaf3d4..c97d6a8bf07a52ac45b839e99d6d6130013d34b3 100644 (file)
@@ -28,6 +28,7 @@ import java.io.ByteArrayInputStream;
 
 import java.util.Iterator;
 
+import org.apache.poi.EncryptedDocumentException;
 import org.apache.poi.POIDocument;
 import org.apache.poi.poifs.filesystem.DirectoryNode;
 import org.apache.poi.poifs.filesystem.POIFSFileSystem;
@@ -174,9 +175,13 @@ public class HWPFDocument extends POIDocument
     
     directory.createDocumentInputStream("WordDocument").read(_mainStream);
 
-    // use the fib to determine the name of the table stream.
+    // Create our FIB, and check for the doc being encrypted
     _fib = new FileInformationBlock(_mainStream);
+    if(_fib.isFEncrypted()) {
+       throw new EncryptedDocumentException("Cannot process encrypted word files!");
+    }
 
+    // use the fib to determine the name of the table stream.
     String name = "0Table";
     if (_fib.isFWhichTblStm())
     {
diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/data/PasswordProtected.doc b/src/scratchpad/testcases/org/apache/poi/hwpf/data/PasswordProtected.doc
new file mode 100644 (file)
index 0000000..0d6c169
Binary files /dev/null and b/src/scratchpad/testcases/org/apache/poi/hwpf/data/PasswordProtected.doc differ
index 23681486f32b9945fa184a74237662faa02dfc99..764b3239dcd46c0759cf418c18f462c550402188 100644 (file)
@@ -22,6 +22,7 @@ import java.io.FileOutputStream;
 
 import junit.framework.TestCase;
 
+import org.apache.poi.EncryptedDocumentException;
 import org.apache.poi.hwpf.HWPFDocument;
 import org.apache.poi.hwpf.model.StyleSheet;
 
@@ -138,4 +139,18 @@ public class TestProblems extends TestCase {
                
                assertEquals(newLength, totalLength - deletedLength);
        }
+       
+       /**
+        * With an encrypted file, we should give a suitable
+        *  exception, and not OOM
+        */
+       public void testEncryptedFile() throws Exception {
+               try {
+                       new HWPFDocument(new FileInputStream(
+                       new File(dirname, "PasswordProtected.doc")));
+                       fail();
+               } catch(EncryptedDocumentException e) {
+                       // Good
+               }
+       }
 }
index 15a19c09121c9ae679415c61170aa68ae8c66acd..772a4fdfc781cfc9c88fa71c5d34686928651de3 100755 (executable)
@@ -44,6 +44,7 @@ public class AllUserModelTests {
                result.addTestSuite(TestHSSFClientAnchor.class);
                result.addTestSuite(TestHSSFComment.class);
                result.addTestSuite(TestHSSFConditionalFormatting.class);
+               result.addTestSuite(TestHSSFDataFormatter.class);
                result.addTestSuite(TestHSSFDateUtil.class);
                result.addTestSuite(TestHSSFHeaderFooter.class);
                result.addTestSuite(TestHSSFHyperlink.class);
index 39baedd8856d04c40cfd55db1cee4b760fdd457f..f865d6e494ed9f5c2833de32d55b18f0e84c819e 100644 (file)
@@ -25,141 +25,141 @@ import junit.framework.TestCase;
 
 /**
  * Unit tests for HSSFDataFormatter.java
- * 
+ *
  * @author James May (james dot may at fmr dot com)
  *
  */
-public class TestHSSFDataFormatter extends TestCase {
+public final class TestHSSFDataFormatter extends TestCase {
+
+       private final HSSFDataFormatter formatter;
+       private final HSSFWorkbook wb;
 
-       HSSFDataFormatter formatter;
-       HSSFWorkbook wb;
-       
        public TestHSSFDataFormatter() {
                // create the formatter to test
                formatter = new HSSFDataFormatter();
-               
+
                // create a workbook to test with
-           wb = new HSSFWorkbook();
-           HSSFSheet sheet = wb.createSheet();
-           HSSFDataFormat format = wb.createDataFormat();
-  
-           // create a row and put some cells in it
-           HSSFRow row = sheet.createRow((short)0);
-
-           // date value for July 8 1901 1:19 PM
-           double dateNum = 555.555;
-           
-           //valid date formats -- all should have "Jul" in output
-           String[] goodDatePatterns = new String[] {
-               "[$-F800]dddd\\,\\ mmmm\\ dd\\,\\ yyyy",
-               "mmm/d/yy\\ h:mm PM;@",
-               "mmmm/d/yy\\ h:mm;@",
-               "mmmm/d;@",
-               "mmmm/d/yy;@",
-               "mmm/dd/yy;@",
-               "[$-409]d\\-mmm;@",
-               "[$-409]d\\-mmm\\-yy;@",
-               "[$-409]dd\\-mmm\\-yy;@",
-               "[$-409]mmm\\-yy;@",
-               "[$-409]mmmm\\-yy;@",
-               "[$-409]mmmm\\ d\\,\\ yyyy;@",
-               "[$-409]mmm/d/yy\\ h:mm:ss;@",
-               "[$-409]mmmm/d/yy\\ h:mm:ss am;@",
-               "[$-409]mmmmm;@",
-               "[$-409]mmmmm\\-yy;@",
-               "mmmm/d/yyyy;@",
-               "[$-409]d\\-mmm\\-yyyy;@"
-           };
-           
-           // valid number formats
-           String[] goodNumPatterns = new String[] {
-                       "#,##0.0000",
-                       "#,##0;[Red]#,##0",
-                       "(#,##0.00_);(#,##0.00)",
-                       "($#,##0.00_);[Red]($#,##0.00)",
-                       "$#,##0.00",
-                       "[$�-809]#,##0.00",
-                       "[$�-2] #,##0.00",
-                       "0000.00000%",
-                       "0.000E+00",
-                       "0.00E+00",
-           };
-           
-           // invalid date formats -- will throw exception in DecimalFormat ctor
-           String[] badNumPatterns = new String[] {
-                       "#,#$'#0.0000",
-                       "'#','#ABC#0;##,##0",
-                       "000 '123 4'5'6 000",
-                       "#''0#0'1#10L16EE"
-           };      
-           
-           // create cells with good date patterns
-           for (int i = 0; i < goodDatePatterns.length; i++) {
-               HSSFCell cell = row.createCell((short) i);
-               cell.setCellValue(dateNum);
-               HSSFCellStyle cellStyle = wb.createCellStyle();
-               cellStyle.setDataFormat(format.getFormat(goodDatePatterns[i]));
-               cell.setCellStyle(cellStyle);
-           }
-           row = sheet.createRow(1);
-           
-           // create cells with num patterns
-           for (int i = 0; i < goodNumPatterns.length; i++) {
-               HSSFCell cell = row.createCell((short) i);
-               cell.setCellValue(-1234567890.12345);
-               HSSFCellStyle cellStyle = wb.createCellStyle();
-               cellStyle.setDataFormat(format.getFormat(goodNumPatterns[i]));
-               cell.setCellStyle(cellStyle);
-           }
-           row = sheet.createRow(2);
-           
-           // create cells with bad num patterns
-           for (int i = 0; i < badNumPatterns.length; i++) {
-               HSSFCell cell = row.createCell((short) i);
-               cell.setCellValue(1234567890.12345);
-               HSSFCellStyle cellStyle = wb.createCellStyle();
-               cellStyle.setDataFormat(format.getFormat(badNumPatterns[i]));
-               cell.setCellStyle(cellStyle);
-           }
-           
-           // Built in formats
-
-           { // Zip + 4 format
-               row = sheet.createRow(3);
-               HSSFCell cell = row.createCell((short) 0);
-               cell.setCellValue(123456789);
-               HSSFCellStyle cellStyle = wb.createCellStyle();
-               cellStyle.setDataFormat(format.getFormat("00000-0000"));
-               cell.setCellStyle(cellStyle);
-           }
-           
-           { // Phone number format
-               row = sheet.createRow(4);
-               HSSFCell cell = row.createCell((short) 0);
-               cell.setCellValue(5551234567D);
-               HSSFCellStyle cellStyle = wb.createCellStyle();
-               cellStyle.setDataFormat(format.getFormat("[<=9999999]###-####;(###) ###-####"));
-               cell.setCellStyle(cellStyle);
-           }
-           
-           { // SSN format
-               row = sheet.createRow(5);
-               HSSFCell cell = row.createCell((short) 0);
-               cell.setCellValue(444551234);
-               HSSFCellStyle cellStyle = wb.createCellStyle();
-               cellStyle.setDataFormat(format.getFormat("000-00-0000"));
-               cell.setCellStyle(cellStyle);
-           }
-           
-           { // formula cell
-               row = sheet.createRow(6);
-               HSSFCell cell = row.createCell((short) 0);
-               cell.setCellType(HSSFCell.CELL_TYPE_FORMULA);
-               cell.setCellFormula("SUM(12.25,12.25)/100");
-               HSSFCellStyle cellStyle = wb.createCellStyle();
-               cellStyle.setDataFormat(format.getFormat("##.00%;"));
-               cell.setCellStyle(cellStyle);
-           }       
+               wb = new HSSFWorkbook();
+               HSSFSheet sheet = wb.createSheet();
+               HSSFDataFormat format = wb.createDataFormat();
+
+               // create a row and put some cells in it
+               HSSFRow row = sheet.createRow(0);
+
+               // date value for July 8 1901 1:19 PM
+               double dateNum = 555.555;
+
+               //valid date formats -- all should have "Jul" in output
+               String[] goodDatePatterns ={
+                       "[$-F800]dddd\\,\\ mmmm\\ dd\\,\\ yyyy",
+                       "mmm/d/yy\\ h:mm PM;@",
+                       "mmmm/d/yy\\ h:mm;@",
+                       "mmmm/d;@",
+                       "mmmm/d/yy;@",
+                       "mmm/dd/yy;@",
+                       "[$-409]d\\-mmm;@",
+                       "[$-409]d\\-mmm\\-yy;@",
+                       "[$-409]dd\\-mmm\\-yy;@",
+                       "[$-409]mmm\\-yy;@",
+                       "[$-409]mmmm\\-yy;@",
+                       "[$-409]mmmm\\ d\\,\\ yyyy;@",
+                       "[$-409]mmm/d/yy\\ h:mm:ss;@",
+                       "[$-409]mmmm/d/yy\\ h:mm:ss am;@",
+                       "[$-409]mmmmm;@",
+                       "[$-409]mmmmm\\-yy;@",
+                       "mmmm/d/yyyy;@",
+                       "[$-409]d\\-mmm\\-yyyy;@"
+               };
+
+               // valid number formats
+               String[] goodNumPatterns = {
+                               "#,##0.0000",
+                               "#,##0;[Red]#,##0",
+                               "(#,##0.00_);(#,##0.00)",
+                               "($#,##0.00_);[Red]($#,##0.00)",
+                               "$#,##0.00",
+                               "[$�-809]#,##0.00",
+                               "[$�-2] #,##0.00",
+                               "0000.00000%",
+                               "0.000E+00",
+                               "0.00E+00",
+               };
+
+               // invalid date formats -- will throw exception in DecimalFormat ctor
+               String[] badNumPatterns = {
+                               "#,#$'#0.0000",
+                               "'#','#ABC#0;##,##0",
+                               "000 '123 4'5'6 000",
+                               "#''0#0'1#10L16EE"
+               };
+
+               // create cells with good date patterns
+               for (int i = 0; i < goodDatePatterns.length; i++) {
+                       HSSFCell cell = row.createCell((short) i);
+                       cell.setCellValue(dateNum);
+                       HSSFCellStyle cellStyle = wb.createCellStyle();
+                       cellStyle.setDataFormat(format.getFormat(goodDatePatterns[i]));
+                       cell.setCellStyle(cellStyle);
+               }
+               row = sheet.createRow(1);
+
+               // create cells with num patterns
+               for (int i = 0; i < goodNumPatterns.length; i++) {
+                       HSSFCell cell = row.createCell((short) i);
+                       cell.setCellValue(-1234567890.12345);
+                       HSSFCellStyle cellStyle = wb.createCellStyle();
+                       cellStyle.setDataFormat(format.getFormat(goodNumPatterns[i]));
+                       cell.setCellStyle(cellStyle);
+               }
+               row = sheet.createRow(2);
+
+               // create cells with bad num patterns
+               for (int i = 0; i < badNumPatterns.length; i++) {
+                       HSSFCell cell = row.createCell((short) i);
+                       cell.setCellValue(1234567890.12345);
+                       HSSFCellStyle cellStyle = wb.createCellStyle();
+                       cellStyle.setDataFormat(format.getFormat(badNumPatterns[i]));
+                       cell.setCellStyle(cellStyle);
+               }
+
+               // Built in formats
+
+               { // Zip + 4 format
+                       row = sheet.createRow(3);
+                       HSSFCell cell = row.createCell((short) 0);
+                       cell.setCellValue(123456789);
+                       HSSFCellStyle cellStyle = wb.createCellStyle();
+                       cellStyle.setDataFormat(format.getFormat("00000-0000"));
+                       cell.setCellStyle(cellStyle);
+               }
+
+               { // Phone number format
+                       row = sheet.createRow(4);
+                       HSSFCell cell = row.createCell((short) 0);
+                       cell.setCellValue(5551234567D);
+                       HSSFCellStyle cellStyle = wb.createCellStyle();
+                       cellStyle.setDataFormat(format.getFormat("[<=9999999]###-####;(###) ###-####"));
+                       cell.setCellStyle(cellStyle);
+               }
+
+               { // SSN format
+                       row = sheet.createRow(5);
+                       HSSFCell cell = row.createCell((short) 0);
+                       cell.setCellValue(444551234);
+                       HSSFCellStyle cellStyle = wb.createCellStyle();
+                       cellStyle.setDataFormat(format.getFormat("000-00-0000"));
+                       cell.setCellStyle(cellStyle);
+               }
+
+               { // formula cell
+                       row = sheet.createRow(6);
+                       HSSFCell cell = row.createCell((short) 0);
+                       cell.setCellType(HSSFCell.CELL_TYPE_FORMULA);
+                       cell.setCellFormula("SUM(12.25,12.25)/100");
+                       HSSFCellStyle cellStyle = wb.createCellStyle();
+                       cellStyle.setDataFormat(format.getFormat("##.00%;"));
+                       cell.setCellStyle(cellStyle);
+               }
        }
 
        /**
@@ -169,14 +169,14 @@ public class TestHSSFDataFormatter extends TestCase {
                // Valid date formats -- cell values should be date formatted & not "555.555"
                HSSFRow row = wb.getSheetAt(0).getRow(0);
                Iterator it = row.cellIterator();
-               System.out.println("==== VALID DATE FORMATS ====");
+               log("==== VALID DATE FORMATS ====");
                while (it.hasNext()) {
                        HSSFCell cell = (HSSFCell) it.next();
-                       System.out.println(formatter.formatCellValue(cell));
+                       log(formatter.formatCellValue(cell));
 
                        // should not be equal to "555.555"
                        assertTrue( ! "555.555".equals(formatter.formatCellValue(cell)));
-                       
+
                        // should contain "Jul" in the String
                        assertTrue( formatter.formatCellValue(cell).indexOf("Jul") > -1);
                }
@@ -184,70 +184,70 @@ public class TestHSSFDataFormatter extends TestCase {
                // test number formats
                row = wb.getSheetAt(0).getRow(1);
                it = row.cellIterator();
-               System.out.println("\n==== VALID NUMBER FORMATS ====");
+               log("\n==== VALID NUMBER FORMATS ====");
                while (it.hasNext()) {
                        HSSFCell cell = (HSSFCell) it.next();
-                       System.out.println(formatter.formatCellValue(cell));
-                       
+                       log(formatter.formatCellValue(cell));
+
                        // should not be equal to "1234567890.12345"
                        assertTrue( ! "1234567890.12345".equals(formatter.formatCellValue(cell)));
                }
-               
+
                // test bad number formats
                row = wb.getSheetAt(0).getRow(2);
                it = row.cellIterator();
-               System.out.println("\n==== INVALID NUMBER FORMATS ====");
+               log("\n==== INVALID NUMBER FORMATS ====");
                while (it.hasNext()) {
                        HSSFCell cell = (HSSFCell) it.next();
-                       System.out.println(formatter.formatCellValue(cell));
+                       log(formatter.formatCellValue(cell));
                        // should be equal to "1234567890.12345"
                        assertEquals("1234567890.12345", formatter.formatCellValue(cell));
                }
-               
+
                // test Zip+4 format
                row = wb.getSheetAt(0).getRow(3);
                HSSFCell cell = row.getCell(0);
-               System.out.println("\n==== ZIP FORMAT ====");
-               System.out.println(formatter.formatCellValue(cell));
+               log("\n==== ZIP FORMAT ====");
+               log(formatter.formatCellValue(cell));
                assertEquals("12345-6789", formatter.formatCellValue(cell));
-               
+
                // test phone number format
                row = wb.getSheetAt(0).getRow(4);
                cell = row.getCell(0);
-               System.out.println("\n==== PHONE FORMAT ====");
-               System.out.println(formatter.formatCellValue(cell));
+               log("\n==== PHONE FORMAT ====");
+               log(formatter.formatCellValue(cell));
                assertEquals("(555) 123-4567", formatter.formatCellValue(cell));
-               
+
                // test SSN format
                row = wb.getSheetAt(0).getRow(5);
                cell = row.getCell(0);
-               System.out.println("\n==== SSN FORMAT ====");
-               System.out.println(formatter.formatCellValue(cell));
-               assertEquals("444-55-1234", formatter.formatCellValue(cell));           
-               
+               log("\n==== SSN FORMAT ====");
+               log(formatter.formatCellValue(cell));
+               assertEquals("444-55-1234", formatter.formatCellValue(cell));
+
                // null test-- null cell should result in empty String
                assertEquals(formatter.formatCellValue(null), "");
-               
+
                // null test-- null cell should result in empty String
-               assertEquals(formatter.formatCellValue(null), "");              
-               
+               assertEquals(formatter.formatCellValue(null), "");
+
        }
 
        public void testGetFormattedCellValueHSSFCellHSSFFormulaEvaluator() {
                // test formula format
                HSSFRow row = wb.getSheetAt(0).getRow(6);
                HSSFCell cell = row.getCell(0);
-               System.out.println("\n==== FORMULA CELL ====");
-               
+               log("\n==== FORMULA CELL ====");
+
                // first without a formula evaluator
-               System.out.println(formatter.formatCellValue(cell) + "\t (without evaluator)");
-               assertEquals("SUM(12.25,12.25)/100", formatter.formatCellValue(cell));  
-               
-               // now with a formula evaluator         
+               log(formatter.formatCellValue(cell) + "\t (without evaluator)");
+               assertEquals("SUM(12.25,12.25)/100", formatter.formatCellValue(cell));
+
+               // now with a formula evaluator
                HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(wb.getSheetAt(0), wb);
                //! must set current row !
                evaluator.setCurrentRow(row);
-               System.out.println(formatter.formatCellValue(cell, evaluator) + "\t\t\t (with evaluator)");
+               log(formatter.formatCellValue(cell, evaluator) + "\t\t\t (with evaluator)");
                assertEquals("24.50%", formatter.formatCellValue(cell,evaluator));
        }
 
@@ -259,24 +259,23 @@ public class TestHSSFDataFormatter extends TestCase {
         */
        public void testSetDefaultNumberFormat() {
                HSSFRow row = wb.getSheetAt(0).getRow(2);
-               Iterator it = row.cellIterator();       
+               Iterator it = row.cellIterator();
                Format defaultFormat = new DecimalFormat("Balance $#,#00.00 USD;Balance -$#,#00.00 USD");
                formatter.setDefaultNumberFormat(defaultFormat);
                double value = 10d;
-               System.out.println("\n==== DEFAULT NUMBER FORMAT ====");
+               log("\n==== DEFAULT NUMBER FORMAT ====");
                while (it.hasNext()) {
-                       HSSFCell cell = (HSSFCell) it.next();           
+                       HSSFCell cell = (HSSFCell) it.next();
                        cell.setCellValue(cell.getNumericCellValue() * Math.random() / 1000000 - 1000);
-                       System.out.println(formatter.formatCellValue(cell));
+                       log(formatter.formatCellValue(cell));
                        assertTrue(formatter.formatCellValue(cell).startsWith("Balance "));
                        assertTrue(formatter.formatCellValue(cell).endsWith(" USD"));
-               }       
+               }
        }
 
-    public static void main(String [] args) {
-        System.out
-                .println("Testing org.apache.poi.hssf.usermodel.TestHSSFDataFormatter");
-        junit.textui.TestRunner.run(TestHSSFDataFormatter.class);
-    }  
-
+       private static void log(String msg) {
+               if (false) { // successful tests should be silent
+                       System.out.println(msg);
+               }
+       }
 }