2
Copyright (c) 2009 Tobias Koenig <tokoe@kde.org>
4
This library is free software; you can redistribute it and/or modify it
5
under the terms of the GNU Library General Public License as published by
6
the Free Software Foundation; either version 2 of the License, or (at your
7
option) any later version.
9
This library is distributed in the hope that it will be useful, but WITHOUT
10
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
12
License for more details.
14
You should have received a copy of the GNU Library General Public License
15
along with this library; see the file COPYING.LIB. If not, write to the
16
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20
#include "qcsvreader.h"
22
#include <QtCore/QStringList>
23
#include <QtCore/QTextCodec>
24
#include <QtCore/QTextStream>
26
QCsvBuilderInterface::~QCsvBuilderInterface()
30
class QCsvReader::Private
33
Private( QCsvBuilderInterface *builder )
36
mTextQuote = QChar( '"' );
37
mDelimiter = QChar( ' ' );
39
mCodec = QTextCodec::codecForLocale();
41
mIgnoreDuplicates = true;
44
void emitBeginLine( uint row );
45
void emitEndLine( uint row );
46
void emitField( const QString &data, int row, int column );
48
QCsvBuilderInterface *mBuilder;
54
bool mIgnoreDuplicates;
57
void QCsvReader::Private::emitBeginLine( uint row )
59
if ( (row - mStartRow) > 0 )
60
mBuilder->beginLine();
63
void QCsvReader::Private::emitEndLine( uint row )
65
if ( (row - mStartRow) > 0 )
69
void QCsvReader::Private::emitField( const QString &data, int row, int column )
71
if ( (row - mStartRow) > 0 )
72
mBuilder->field( data, row - mStartRow - 1, column - 1 );
75
QCsvReader::QCsvReader( QCsvBuilderInterface *builder )
76
: d( new Private( builder ) )
81
QCsvReader::~QCsvReader()
86
bool QCsvReader::read( QIODevice *device )
89
bool lastCharDelimiter = false;
90
bool ignoreDups = d->mIgnoreDuplicates;
91
enum { S_START, S_QUOTED_FIELD, S_MAYBE_END_OF_QUOTED_FIELD, S_END_OF_QUOTED_FIELD,
92
S_MAYBE_NORMAL_FIELD, S_NORMAL_FIELD } state = S_START;
100
d->emitBeginLine( row );
102
if ( !device->isOpen() ) {
103
d->mBuilder->error( "Device is not open" );
104
d->emitEndLine( row );
109
QTextStream inputStream( device );
110
inputStream.setCodec( d->mCodec );
113
while ( !inputStream.atEnd() ) {
114
inputStream >> x; // read one char
116
if ( x == '\r' ) inputStream >> x; // eat '\r', to handle DOS/LOSEDOWS files correctly
120
if ( x == d->mTextQuote ) {
121
state = S_QUOTED_FIELD;
122
} else if ( x == d->mDelimiter ) {
123
if ( ( ignoreDups == false ) || ( lastCharDelimiter == false ) )
125
lastCharDelimiter = true;
126
} else if ( x == '\n' ) {
127
d->emitEndLine( row );
130
d->emitBeginLine( row );
133
state = S_MAYBE_NORMAL_FIELD;
137
if ( x == d->mTextQuote ) {
138
state = S_MAYBE_END_OF_QUOTED_FIELD;
139
} else if ( x == '\n' && d->mTextQuote.isNull() ) {
140
d->emitField( field, row, column );
143
d->emitEndLine( row );
146
d->emitBeginLine( row );
148
if ( ( ignoreDups == false ) || ( lastCharDelimiter == false ) )
150
lastCharDelimiter = true;
157
case S_MAYBE_END_OF_QUOTED_FIELD:
158
if ( x == d->mTextQuote ) {
160
state = S_QUOTED_FIELD;
161
} else if ( x == d->mDelimiter || x == '\n' ) {
162
d->emitField( field, row, column );
165
d->emitEndLine( row );
168
d->emitBeginLine( row );
170
if ( ( ignoreDups == false ) || ( lastCharDelimiter == false ) )
172
lastCharDelimiter = true;
176
state = S_END_OF_QUOTED_FIELD;
179
case S_END_OF_QUOTED_FIELD:
180
if ( x == d->mDelimiter || x == '\n' ) {
181
d->emitField( field, row, column );
184
d->emitEndLine( row );
187
d->emitBeginLine( row );
189
if ( ( ignoreDups == false ) || ( lastCharDelimiter == false ) )
191
lastCharDelimiter = true;
195
state = S_END_OF_QUOTED_FIELD;
198
case S_MAYBE_NORMAL_FIELD:
199
if ( x == d->mTextQuote ) {
201
state = S_QUOTED_FIELD;
205
if ( x == d->mDelimiter || x == '\n' ) {
206
d->emitField( field, row, column );
209
d->emitEndLine( row );
212
d->emitBeginLine( row );
214
if ( ( ignoreDups == false ) || ( lastCharDelimiter == false ) )
216
lastCharDelimiter = true;
223
if ( x != d->mDelimiter )
224
lastCharDelimiter = false;
226
if ( column > maxColumn )
230
// file with only one line without '\n'
231
if ( field.length() > 0 ) {
232
d->emitField( field, row, column );
237
d->emitEndLine( row );
243
void QCsvReader::setTextQuote( const QChar &textQuote )
245
d->mTextQuote = textQuote;
248
QChar QCsvReader::textQuote() const
250
return d->mTextQuote;
253
void QCsvReader::setDelimiter( const QChar &delimiter )
255
d->mDelimiter = delimiter;
258
QChar QCsvReader::delimiter() const
260
return d->mDelimiter;
263
void QCsvReader::setStartRow( uint startRow )
265
d->mStartRow = startRow;
268
uint QCsvReader::startRow() const
273
void QCsvReader::setTextCodec( QTextCodec *textCodec )
275
d->mCodec = textCodec;
278
QTextCodec *QCsvReader::textCodec() const
284
class QCsvStandardBuilder::Private
294
QString mLastErrorString;
297
QList<QStringList> mRows;
300
void QCsvStandardBuilder::Private::init()
305
mLastErrorString.clear();
308
QCsvStandardBuilder::QCsvStandardBuilder()
313
QCsvStandardBuilder::~QCsvStandardBuilder()
318
QString QCsvStandardBuilder::lastErrorString() const
320
return d->mLastErrorString;
323
uint QCsvStandardBuilder::rowCount() const
328
uint QCsvStandardBuilder::columnCount() const
330
return d->mColumnCount;
333
QString QCsvStandardBuilder::data( uint row, uint column ) const
335
if ( row > d->mRowCount || column > d->mColumnCount || column >= (uint)d->mRows[ row ].count() )
338
return d->mRows[ row ][ column ];
341
void QCsvStandardBuilder::begin()
346
void QCsvStandardBuilder::beginLine()
348
d->mRows.append( QStringList() );
352
void QCsvStandardBuilder::field( const QString &data, uint row, uint column )
354
const uint size = d->mRows[ row ].size();
355
if ( column >= size ) {
356
for ( uint i = column; i < size + 1; ++i )
357
d->mRows[ row ].append( QString() );
360
d->mRows[ row ][ column ] = data;
362
d->mColumnCount = qMax( d->mColumnCount, column + 1 );
365
void QCsvStandardBuilder::endLine()
369
void QCsvStandardBuilder::end()
373
void QCsvStandardBuilder::error( const QString &errorMsg )
375
d->mLastErrorString = errorMsg;
378
#include "qcsvreader.moc"