/*
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software
* Foundation.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
* or from the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* Copyright (c) 2001 - 2013 Object Refinery Ltd, Pentaho Corporation and Contributors.. All rights reserved.
*/
package org.pentaho.reporting.engine.classic.core.modules.output.csv;
/**
* The <code>CSVQuoter</code> is a helper class to encode a string for the CSV file format.
*
* @author Thomas Morgner.
*/
public class CSVQuoter {
/**
* The separator used in the CSV file.
*/
private String separator;
/**
* Creates a new CSVQuoter, which uses a comma as the default separator.
*/
public CSVQuoter() {
this( "," );
}
/**
* Creates a new <code>CSVQuoter</code>, which uses the defined separator.
*
* @param separator
* the separator.
* @throws NullPointerException
* if the given separator is <code>null</code>.
*/
public CSVQuoter( final String separator ) {
setSeparator( separator );
}
/**
* Encodes the string, so that the string can safely be used in CSV files. If the string does not need quoting, the
* original string is returned unchanged.
*
* @param original
* the unquoted string.
* @return The quoted string
*/
public String doQuoting( final String original ) {
if ( isQuotingNeeded( original ) ) {
final StringBuffer retval = new StringBuffer( original.length() + 10 );
retval.append( '\"' );
applyQuote( retval, original );
retval.append( '\"' );
return retval.toString();
} else {
return original;
}
}
/**
* Decodes the string, so that all escape sequences get removed. If the string was not quoted, then the string is
* returned unchanged.
*
* @param nativeString
* the quoted string.
* @return The unquoted string.
*/
public String undoQuoting( final String nativeString ) {
if ( isQuotingNeeded( nativeString ) ) {
final StringBuffer b = new StringBuffer( nativeString.length() );
final int length = nativeString.length() - 1;
int start = 1;
int pos = start;
while ( pos != -1 ) {
pos = nativeString.indexOf( "\"\"", start );
if ( pos == -1 ) {
b.append( nativeString.substring( start, length ) );
} else {
b.append( nativeString.substring( start, pos ) );
start = pos + 1;
}
}
return b.toString();
} else {
return nativeString;
}
}
/**
* Tests, whether this string needs to be quoted. A string is encoded if the string contains a newline character, a
* quote character or the defined separator.
*
* @param str
* the string that should be tested.
* @return true, if quoting needs to be applied, false otherwise.
*/
private boolean isQuotingNeeded( final String str ) {
if ( str.indexOf( separator ) != -1 ) {
return true;
}
if ( str.indexOf( '\n' ) != -1 ) {
return true;
}
if ( str.indexOf( '\"', 1 ) != -1 ) {
return true;
}
return false;
}
/**
* Applies the quoting to a given string, and stores the result in the StringBuffer <code>b</code>.
*
* @param b
* the result buffer
* @param original
* the string, that should be quoted.
*/
private void applyQuote( final StringBuffer b, final String original ) {
// This solution needs improvements. Copy blocks instead of single
// characters.
final int length = original.length();
for ( int i = 0; i < length; i++ ) {
final char c = original.charAt( i );
if ( c == '"' ) {
b.append( "\"\"" );
} else {
b.append( c );
}
}
}
/**
* Gets the separator used in this quoter and the CSV file.
*
* @return the separator (never <code>null</code>).
*/
public String getSeparator() {
return separator;
}
/**
* Defines the separator, which is used in the CSV file. If you use different separators for quoting and writing, the
* resulting file will be invalid.
*
* @param separator
* the separator (<code>null</code> not permitted).
*/
public void setSeparator( final String separator ) {
if ( separator == null ) {
throw new NullPointerException();
}
this.separator = separator;
}
}