/* ************************************************************************
#
# DivConq
#
# http://divconq.com/
#
# Copyright:
# Copyright 2014 eTimeline, LLC. All rights reserved.
#
# License:
# See the license.txt file in the project's top-level directory for details.
#
# Authors:
# * Andy White
#
************************************************************************ */
/**
* @author Thomas Davis (sunsetbrew)
* @copyright Copyright (c) 2010, Thomas Davis
* @license http://opensource.org/licenses/mit-license.php MIT License
*/
package divconq.util;
import java.io.BufferedReader;
import java.io.EOFException;
import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;
/**
* CSV4180Reader provides a simple way to import CSV values from a file. The
* reader extends BufferedReader for improved performance.
*/
public class CSVReader extends BufferedReader {
/**
* Create a buffering character-input stream that uses a default-sized input
* buffer.
*
* @param in
* A Reader
*/
public CSVReader(Reader in) {
super(in);
}
/**
* Create a buffering character-input stream that uses an input buffer of
* the specified size.
*
* @param in
* A Reader
* @param sz
* Input-buffer size
*/
public CSVReader(Reader in, int sz) {
super(in, sz);
}
/**
* Indicates if the last field read was at the end of the line.
*
* @return true if last field read was at the end of the line, false
* otherwise or if no fields have been read.
*/
public boolean hasMoreFieldsOnLine() {
return this.moreFieldsOnLine;
}
/**
* Indicates if all the data from the reader has been read.
*
* @return true if all the data from the reader has been read.
*/
public boolean isEOF() {
return this.eof;
}
/**
* Reads the current line's fields into an ArrayList. This is a convenience
* method.
*
* @param fields
* container for the fields in the current row. It will be
* cleared.
* @throws IOException
* on general I/O error
* @throws EOFException
* on end of file
*/
public void readFields(ArrayList<String> fields) throws IOException {
fields.clear();
if (this.eof) {
throw new EOFException();
}
do {
fields.add(readField());
} while (this.moreFieldsOnLine);
}
/**
* Reads the next field from the input removing quotes as necessary.
*
* @return next field
* @throws IOException
* If an I/O error occurs, may be an EOFException on end of
* input.
*/
public String readField() throws IOException {
int c;
final int UNQUOTED = 0;
final int QUOTED = 1;
final int QUOTEDPLUS = 2;
int state = UNQUOTED;
if (this.eof) {
throw new EOFException();
}
this.buffer.setLength(0);
while ((c = this.read()) >= 0) {
if (state == QUOTEDPLUS) {
switch (c) {
case '"':
this.buffer.append('"');
state = QUOTED;
continue;
default:
state = UNQUOTED;
break;
}
}
if (state == QUOTED) {
switch (c) {
default:
this.buffer.append((char) c);
continue;
case '"':
state = QUOTEDPLUS;
continue;
}
}
// (state == UNQUOTED)
switch (c) {
case '"':
state = QUOTED;
continue;
case '\r':
continue;
case '\n':
case ',':
this.moreFieldsOnLine = (c != '\n');
return this.buffer.toString();
default:
this.buffer.append((char) c);
continue;
}
}
this.eof = true;
this.moreFieldsOnLine = false;
return this.buffer.toString();
}
/** @ignore */
private boolean moreFieldsOnLine = true;
/** @ignore */
private boolean eof = false;
/** @ignore */
private final StringBuffer buffer = new StringBuffer();
}