Source for org.jfree.report.util.CSVQuoter

   1: /**
   2:  * ========================================
   3:  * JFreeReport : a free Java report library
   4:  * ========================================
   5:  *
   6:  * Project Info:  http://reporting.pentaho.org/
   7:  *
   8:  * (C) Copyright 2000-2007, by Object Refinery Limited, Pentaho Corporation and Contributors.
   9:  *
  10:  * This library is free software; you can redistribute it and/or modify it under the terms
  11:  * of the GNU Lesser General Public License as published by the Free Software Foundation;
  12:  * either version 2.1 of the License, or (at your option) any later version.
  13:  *
  14:  * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
  15:  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  16:  * See the GNU Lesser General Public License for more details.
  17:  *
  18:  * You should have received a copy of the GNU Lesser General Public License along with this
  19:  * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  20:  * Boston, MA 02111-1307, USA.
  21:  *
  22:  * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
  23:  * in the United States and other countries.]
  24:  *
  25:  * ------------
  26:  * $Id: CSVQuoter.java 2725 2007-04-01 18:49:29Z taqua $
  27:  * ------------
  28:  * (C) Copyright 2000-2005, by Object Refinery Limited.
  29:  * (C) Copyright 2005-2007, by Pentaho Corporation.
  30:  */
  31: 
  32: package org.jfree.report.util;
  33: 
  34: /**
  35:  * The <code>CSVQuoter</code> is a helper class to encode a string for the CSV file
  36:  * format.
  37:  *
  38:  * @author Thomas Morgner.
  39:  */
  40: public class CSVQuoter
  41: {
  42:   /**
  43:    * The separator used in the CSV file.
  44:    */
  45:   private char separator;
  46:   /**
  47:    * The quoting character or a single quote.
  48:    */
  49:   private char quate;
  50:   /**
  51:    * The double quote. This is a string containing the quate two times.
  52:    */
  53:   private String doubleQuate;
  54: 
  55:   /**
  56:    * Creates a new CSVQuoter, which uses a comma as the default separator.
  57:    */
  58:   public CSVQuoter ()
  59:   {
  60:     this(',', '"');
  61:   }
  62: 
  63:   /**
  64:    * Creates a new <code>CSVQuoter</code>, which uses the defined separator.
  65:    *
  66:    * @param separator the separator.
  67:    * @throws NullPointerException if the given separator is <code>null</code>.
  68:    */
  69:   public CSVQuoter (final char separator)
  70:   {
  71:     this(separator,  '"');
  72:   }
  73: 
  74:   /**
  75:    * Creates a new CSVQuoter with the given separator and quoting character.
  76:    *
  77:    * @param separator the separator
  78:    * @param quate the quoting character
  79:    */
  80:   public CSVQuoter (final char separator, final char quate)
  81:   {
  82:     this.separator = separator;
  83:     this.quate = quate;
  84:     this.doubleQuate = "" + quate + quate;
  85:   }
  86: 
  87:   /**
  88:    * Encodes the string, so that the string can safely be used in CSV files. If the string
  89:    * does not need quoting, the original string is returned unchanged.
  90:    *
  91:    * @param original the unquoted string.
  92:    * @return The quoted string
  93:    */
  94:   public String doQuoting (final String original)
  95:   {
  96:     if (isQuotingNeeded(original))
  97:     {
  98:       final StringBuffer retval = new StringBuffer();
  99:       retval.append(quate);
 100:       applyQuote(retval, original);
 101:       retval.append(quate);
 102:       return retval.toString();
 103:     }
 104:     else
 105:     {
 106:       return original;
 107:     }
 108:   }
 109: 
 110:   /**
 111:    * Decodes the string, so that all escape sequences get removed. If the string was not
 112:    * quoted, then the string is returned unchanged.
 113:    *
 114:    * @param nativeString the quoted string.
 115:    * @return The unquoted string.
 116:    */
 117:   public String undoQuoting (final String nativeString)
 118:   {
 119:     if (isQuotingNeeded(nativeString))
 120:     {
 121:       final StringBuffer b = new StringBuffer(nativeString.length());
 122:       final int length = nativeString.length() - 1;
 123:       int start = 1;
 124: 
 125:       int pos = start;
 126:       while (pos != -1)
 127:       {
 128:         pos = nativeString.indexOf(doubleQuate, start);
 129:         if (pos == -1)
 130:         {
 131:           b.append(nativeString.substring(start, length));
 132:         }
 133:         else
 134:         {
 135:           b.append(nativeString.substring(start, pos));
 136:           start = pos + 1;
 137:         }
 138:       }
 139:       return b.toString();
 140:     }
 141:     else
 142:     {
 143:       return nativeString;
 144:     }
 145:   }
 146: 
 147:   /**
 148:    * Tests, whether this string needs to be quoted. A string is encoded if the string
 149:    * contains a newline character, a quote character or the defined separator.
 150:    *
 151:    * @param str the string that should be tested.
 152:    * @return true, if quoting needs to be applied, false otherwise.
 153:    */
 154:   private boolean isQuotingNeeded (final String str)
 155:   {
 156:     if (str.indexOf(separator) != -1)
 157:     {
 158:       return true;
 159:     }
 160:     if (str.indexOf('\n') != -1)
 161:     {
 162:       return true;
 163:     }
 164:     if (str.indexOf(quate, 1) != -1)
 165:     {
 166:       return true;
 167:     }
 168:     return false;
 169:   }
 170: 
 171:   /**
 172:    * Applies the quoting to a given string, and stores the result in the StringBuffer
 173:    * <code>b</code>.
 174:    *
 175:    * @param b        the result buffer
 176:    * @param original the string, that should be quoted.
 177:    */
 178:   private void applyQuote (final StringBuffer b, final String original)
 179:   {
 180:     // This solution needs improvements. Copy blocks instead of single
 181:     // characters.
 182:     final int length = original.length();
 183: 
 184:     for (int i = 0; i < length; i++)
 185:     {
 186:       final char c = original.charAt(i);
 187:       if (c == quate)
 188:       {
 189:         b.append(doubleQuate);
 190:       }
 191:       else
 192:       {
 193:         b.append(c);
 194:       }
 195:     }
 196:   }
 197: 
 198:   /**
 199:    * Gets the separator used in this quoter and the CSV file.
 200:    *
 201:    * @return the separator (never <code>null</code>).
 202:    */
 203:   public char getSeparator ()
 204:   {
 205:     return separator;
 206:   }
 207: 
 208:   /**
 209:    * Returns the quoting character.
 210:    *
 211:    * @return the quote character.
 212:    */
 213:   public char getQuate ()
 214:   {
 215:     return quate;
 216:   }
 217: }