1
/* This file is part of the KDE project
2
Copyright (C) 2002 by Thomas Franke and Andreas Pietzowski <andreas@pietzowski.de>
3
Ariya Hidayat <ariyahidayat@yahoo.de>
5
This library is free software; you can redistribute it and/or
6
modify it under the terms of the GNU Library General Public
7
License as published by the Free Software Foundation; either
8
version 2 of the License, or (at your option) any later version.
10
This library is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
Library General Public License for more details.
15
You should have received a copy of the GNU Library General Public License
16
along with this library; see the file COPYING.LIB. If not, write to
17
the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18
Boston, MA 02111-1307, USA.
22
#include <qdatetime.h>
23
#include <qdatastream.h>
26
#include <qstringlist.h>
31
DBase::DBase(): m_recordCount( 0 )
33
fields.setAutoDelete( true );
42
// Headerdefinition in dBASE
46
// unsigned char version 0 dBASE-Version (3)
47
// unsigned char last_update[3] 1-3 Date of last update
48
// unsigned long records 4-7 Number of records
49
// unsigned short header_length 8-9 headerlength
50
// unsigned short record_length 10-11 recordlength
51
// unsigned char reserved[20] 12-31 reserverd info from dBase
54
bool DBase::load( const QString& filename )
57
m_file.setName( filename );
58
if( !m_file.open(IO_ReadOnly) )
61
m_stream.setDevice( &m_file );
62
m_stream.setByteOrder( QDataStream::LittleEndian );
64
unsigned filesize = m_file.size();
69
m_version = ver & 0x7f; // bit 7: has memo ?
71
// only dBASE V.3 is supported
75
// date of last update
77
m_stream >> y >> m >> d;
78
// because dBASE saves 102 instead of 2002 (very Y2K-save ;-)
79
m_lastUpdate.setYMD( y+1900, m, d );
81
// check for valid date
82
if( !m_lastUpdate.isValid() ) return false;
87
m_recordCount = norec;
90
Q_UINT16 header_length;
91
m_stream >> header_length;
92
m_headerLength = header_length;
95
Q_UINT16 record_length;
96
m_stream >> record_length;
97
m_recordLength = record_length;
99
// read the remaining chars
101
for (int foo = 0; foo < 20; ++foo)
104
// size of file must match
105
if( filesize < m_headerLength + m_recordLength * m_recordCount )
108
// Now read the headers of the columns and their type
112
// unsigned char field_name[11] 0-10 Fieldname
113
// unsigned char field_type 11 Fieldtype
114
// unsigned long field_address 12-15 Fielddataaddress
115
// unsigned char field_length 16 Fieldlength
116
// unsigned char field_decimals 17 decimals
117
// unsigned char reserved[14] 18-31 reserved for internal dBASE-stuff
120
for( unsigned i = 1; i < m_headerLength/32; ++i )
122
DBaseField* field = new DBaseField;
126
for ( int j = 0; j < 11; ++j)
127
m_stream >> colname[j];
129
field->name = QString( (const char*) &colname[0] );
136
case 'C': field->type = DBaseField::Character; break;
137
case 'N': field->type = DBaseField::Numeric; break;
138
case 'D': field->type = DBaseField::Date; break;
139
case 'M': field->type = DBaseField::Memo; break;
140
case 'L': field->type = DBaseField::Logical; break;
141
default: field->type = DBaseField::Unknown; break;
151
field->length = colsize;
155
m_stream >> decimals;
156
field->decimals = decimals;
158
// read remaining chars
160
for ( int foo = 0; foo < 14; ++foo )
164
fields.append( field );
167
// set the index to the first record
168
m_stream.device()->at( m_headerLength );
173
QStringList DBase::readRecord( unsigned recno )
177
// out of range ? return empty strings
178
if( recno >= m_recordCount )
180
for( unsigned i=0; i<fields.count(); i++)
185
// seek to where the record is
186
unsigned filepos = m_headerLength + recno * m_recordLength;
187
m_stream.device()->at( filepos );
189
// first char == '*' means the record is deleted
190
// so we just skip it
192
m_stream >> delmarker;
193
if( delmarker == 0x2a )
197
for( unsigned i=0; i<fields.count(); i++ )
198
switch( fields.at(i)->type )
200
// Numeric or Character
201
case DBaseField::Numeric:
202
case DBaseField::Character:
206
for( unsigned j=0; j<fields.at(i)->length; j++ )
207
{ m_stream >> ch; str += QChar(ch); }
208
result.append( str );
212
case DBaseField::Logical:
218
case 'Y': case 'y': case 'T': case 't': result.append( "True" ); break;
219
case 'N': case 'n': case 'F': case 'f': result.append( "False" ); break;
220
default: result.append( "" ); break;
224
// Date, stored as YYYYMMDD
225
// Note: convert it to YYYY-MM-DD
226
case DBaseField::Date:
230
for( unsigned j=0; j<fields.at(i)->length; j++ )
231
{ m_stream >> ch; str += QChar(ch); }
232
str.insert( 6, '-' );
233
str.insert( 4, '-' );
234
result.append( str );
237
// Unknown/Unimplemented
238
case DBaseField::Unknown:
239
case DBaseField::Memo:
241
result.append( "" ); // unknown
250
if( m_file.isOpen() ) m_file.close();