001: /**
002: * ========================================
003: * JFreeReport : a free Java report library
004: * ========================================
005: *
006: * Project Info: http://reporting.pentaho.org/
007: *
008: * (C) Copyright 2000-2007, by Object Refinery Limited, Pentaho Corporation and Contributors.
009: *
010: * This library is free software; you can redistribute it and/or modify it under the terms
011: * of the GNU Lesser General Public License as published by the Free Software Foundation;
012: * either version 2.1 of the License, or (at your option) any later version.
013: *
014: * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
015: * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
016: * See the GNU Lesser General Public License for more details.
017: *
018: * You should have received a copy of the GNU Lesser General Public License along with this
019: * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
020: * Boston, MA 02111-1307, USA.
021: *
022: * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
023: * in the United States and other countries.]
024: *
025: * ------------
026: * $Id: CSVQuoter.java 3048 2007-07-28 18:02:42Z tmorgner $
027: * ------------
028: * (C) Copyright 2000-2005, by Object Refinery Limited.
029: * (C) Copyright 2005-2007, by Pentaho Corporation.
030: */package org.jfree.report.util;
031:
032: /**
033: * The <code>CSVQuoter</code> is a helper class to encode a string for the CSV file
034: * format.
035: *
036: * @author Thomas Morgner.
037: */
038: public class CSVQuoter {
039: /**
040: * The separator used in the CSV file.
041: */
042: private char separator;
043: /**
044: * The quoting character or a single quote.
045: */
046: private char quate;
047: /**
048: * The double quote. This is a string containing the quate two times.
049: */
050: private String doubleQuate;
051:
052: /**
053: * Creates a new CSVQuoter, which uses a comma as the default separator.
054: */
055: public CSVQuoter() {
056: this (',', '"');
057: }
058:
059: /**
060: * Creates a new <code>CSVQuoter</code>, which uses the defined separator.
061: *
062: * @param separator the separator.
063: * @throws NullPointerException if the given separator is <code>null</code>.
064: */
065: public CSVQuoter(final char separator) {
066: this (separator, '"');
067: }
068:
069: /**
070: * Creates a new CSVQuoter with the given separator and quoting character.
071: *
072: * @param separator the separator
073: * @param quate the quoting character
074: */
075: public CSVQuoter(final char separator, final char quate) {
076: this .separator = separator;
077: this .quate = quate;
078: this .doubleQuate = "" + quate + quate;
079: }
080:
081: /**
082: * Encodes the string, so that the string can safely be used in CSV files. If the string
083: * does not need quoting, the original string is returned unchanged.
084: *
085: * @param original the unquoted string.
086: * @return The quoted string
087: */
088: public String doQuoting(final String original) {
089: if (isQuotingNeeded(original)) {
090: final StringBuffer retval = new StringBuffer();
091: retval.append(quate);
092: applyQuote(retval, original);
093: retval.append(quate);
094: return retval.toString();
095: } else {
096: return original;
097: }
098: }
099:
100: /**
101: * Decodes the string, so that all escape sequences get removed. If the string was not
102: * quoted, then the string is returned unchanged.
103: *
104: * @param nativeString the quoted string.
105: * @return The unquoted string.
106: */
107: public String undoQuoting(final String nativeString) {
108: if (isQuotingNeeded(nativeString)) {
109: final StringBuffer b = new StringBuffer(nativeString
110: .length());
111: final int length = nativeString.length() - 1;
112: int start = 1;
113:
114: int pos = start;
115: while (pos != -1) {
116: pos = nativeString.indexOf(doubleQuate, start);
117: if (pos == -1) {
118: b.append(nativeString.substring(start, length));
119: } else {
120: b.append(nativeString.substring(start, pos));
121: start = pos + 1;
122: }
123: }
124: return b.toString();
125: } else {
126: return nativeString;
127: }
128: }
129:
130: /**
131: * Tests, whether this string needs to be quoted. A string is encoded if the string
132: * contains a newline character, a quote character or the defined separator.
133: *
134: * @param str the string that should be tested.
135: * @return true, if quoting needs to be applied, false otherwise.
136: */
137: private boolean isQuotingNeeded(final String str) {
138: if (str.indexOf(separator) != -1) {
139: return true;
140: }
141: if (str.indexOf('\n') != -1) {
142: return true;
143: }
144: if (str.indexOf(quate, 1) != -1) {
145: return true;
146: }
147: return false;
148: }
149:
150: /**
151: * Applies the quoting to a given string, and stores the result in the StringBuffer
152: * <code>b</code>.
153: *
154: * @param b the result buffer
155: * @param original the string, that should be quoted.
156: */
157: private void applyQuote(final StringBuffer b, final String original) {
158: // This solution needs improvements. Copy blocks instead of single
159: // characters.
160: final int length = original.length();
161:
162: for (int i = 0; i < length; i++) {
163: final char c = original.charAt(i);
164: if (c == quate) {
165: b.append(doubleQuate);
166: } else {
167: b.append(c);
168: }
169: }
170: }
171:
172: /**
173: * Gets the separator used in this quoter and the CSV file.
174: *
175: * @return the separator (never <code>null</code>).
176: */
177: public char getSeparator() {
178: return separator;
179: }
180:
181: /**
182: * Returns the quoting character.
183: *
184: * @return the quote character.
185: */
186: public char getQuate() {
187: return quate;
188: }
189: }
|