/*
* $Id: CSVFormat.java,v 1.5 2005/12/19 12:31:29 oldman1004 Exp $
*
* Copyright(c) 2002 Infomata
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.infomata.data;
import java.util.Iterator;
/**
* Implementation DataFormat interface for CSV formated files.
*
* @author <a href="mailto:oldman1004@gmail.com">skim</a>
* @version $Revision: 1.5 $
*/
public class CSVFormat implements DataFormat {
/**
* Converts a set of data into a line in data file.
* @see com.infomata.data.DataFormat#format(DataRow)
* @param row row of data to be converted in to String
* @return properly CSV formatted line of data.
*/
public String format(DataRow row) {
StringBuffer o = new StringBuffer();
boolean first = true;
Iterator items = row.iterator();
while (items.hasNext()) {
if (first) {
first = false;
}
else
{
o.append(",");
}
String cell = (String)items.next();
o.append(encode(cell));
}
return o.toString();
} // format(DataRow)
/**
* Parses a line of data properly formatted in CSV format
* into set of data.
* @see com.infomata.data.DataFormat#parseLine(String)
* @param line CSV formated line of data
* @return row of data
*/
public DataRow parseLine(String line) {
DataRow res = null;
if (row == null) {
row = new DataRow();
}
else {
line = remainder + NEW_LINE + line;
}
int offset = 0;
boolean paired = true;
if (line != null) {
char[] cs = line.toCharArray();
for (int i = 0; i < cs.length; i++) {
if (cs[i] == QUOTE) {
paired = !paired;
}
else if (cs[i] == COMMA && paired) {
row.add(decode(cs, offset, i - offset));
offset = i + 1;
}
}
if (paired) {
if (offset < cs.length) {
row.add(decode(cs, offset, cs.length - offset));
}
else if (cs[offset - 1] == COMMA)
{
row.addEmpty();
}
res = row;
row = null;
}
else {
remainder = new String(cs, offset, cs.length - offset);
}
}
return res;
} // parseLine(String)
/**
* Helper method to convert one data item into
* CSV compliant format.
*
* @param datum data item
* @return CSV encoded string
*/
private String encode(String datum) {
String res = null;
if (datum == null) {
res = "null";
}
else if (datum.length() == 0) {
res = "";
}
else if (datum.indexOf(QUOTE) >= 0
|| datum.indexOf(COMMA) >= 0
|| datum.indexOf(NEW_LINE) >= 0
|| Character.isWhitespace(datum.charAt(0))) {
StringBuffer o = new StringBuffer();
o.append(QUOTE);
char[] cs = datum.toCharArray();
for (int i = 0; i < cs.length; i++) {
if (cs[i] == QUOTE) {
o.append(QUOTE); // add 1 more.
}
o.append(cs[i]);
}
o.append(QUOTE);
res = o.toString();
}
else {
res = datum;
}
return res;
} // encode(String)
/**
* Helper method to remove CSV encoding from CSV formated
* data cell.
*
* @param cs a <code>char[]</code> value
* @param offset an <code>int</code> value
* @param len an <code>int</code> value
* @return a <code>String</code> value
*/
private static String decode(char[] cs, int offset, int len) {
while (Character.isWhitespace(cs[offset]) && offset < cs.length) {
offset += 1;
len -= 1;
}
int end = offset + len - 1;
StringBuffer o = new StringBuffer();
// decode escaped content.
if (cs[offset] == QUOTE && cs[end] == QUOTE) {
for (int i = offset + 1; i < end; i++) {
// remove doubled '"'
if (cs[i] == QUOTE) {
i++;
}
if (i < end) {
o.append(cs[i]);
}
}
}
else {
o.append(cs, offset, len);
}
return o.toString();
} // decode(char[], int, int)
private DataRow row = null;
private String remainder = null;
/**
* Double quote
*/
private static final char QUOTE = '"';
/**
* new line character.
*/
private static final char NEW_LINE = '\n';
/**
* Delimiter (comma)
*/
private static final char COMMA = ',';
}