~ubuntu-branches/ubuntu/precise/koffice/precise

« back to all changes in this revision

Viewing changes to filters/kspread/dbase/dbase.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jonathan Riddell
  • Date: 2010-09-21 15:36:35 UTC
  • mfrom: (1.4.1 upstream) (60.2.11 maverick)
  • Revision ID: james.westby@ubuntu.com-20100921153635-6tejqkiro2u21ydi
Tags: 1:2.2.2-0ubuntu3
Add kubuntu_03_fix-crash-on-closing-sqlite-connection-2.2.2.diff and
kubuntu_04_support-large-memo-values-for-msaccess-2.2.2.diff as
recommended by upstream http://kexi-
project.org/wiki/wikiview/index.php@Kexi2.2_Patches.html#sqlite_stab
ility

Show diffs side-by-side

added added

removed removed

Lines of Context:
27
27
 
28
28
#include <dbase.h>
29
29
 
30
 
DBase::DBase(): m_recordCount( 0 )
 
30
DBase::DBase(): m_recordCount(0)
31
31
{
32
32
}
33
33
 
34
34
DBase::~DBase()
35
35
{
36
 
  while(!fields.isEmpty()) delete fields.takeFirst();
37
 
  close();
 
36
    while (!fields.isEmpty()) delete fields.takeFirst();
 
37
    close();
38
38
}
39
39
 
40
 
  // Headerdefinition in dBASE
41
 
  //
42
 
  //  Type                            char   Content
43
 
  //
44
 
  //  unsigned char version           0      dBASE-Version (3)
45
 
  //  unsigned char last_update[3]    1-3    Date of last update
46
 
  //  unsigned long records           4-7    Number of records
47
 
  //  unsigned short header_length    8-9    headerlength
48
 
  //  unsigned short record_length    10-11  recordlength
49
 
  //  unsigned char reserved[20]      12-31  reserverd info from dBase
50
 
  //
 
40
// Headerdefinition in dBASE
 
41
//
 
42
//  Type                            char   Content
 
43
//
 
44
//  unsigned char version           0      dBASE-Version (3)
 
45
//  unsigned char last_update[3]    1-3    Date of last update
 
46
//  unsigned long records           4-7    Number of records
 
47
//  unsigned short header_length    8-9    headerlength
 
48
//  unsigned short record_length    10-11  recordlength
 
49
//  unsigned char reserved[20]      12-31  reserverd info from dBase
 
50
//
51
51
 
52
 
bool DBase::load( const QString& filename )
 
52
bool DBase::load(const QString& filename)
53
53
{
54
54
 
55
 
  m_file.setFileName( filename );
56
 
  if( !m_file.open(QIODevice::ReadOnly) )
57
 
    return false;
58
 
 
59
 
  m_stream.setDevice( &m_file );
60
 
  m_stream.setByteOrder( QDataStream::LittleEndian );
61
 
 
62
 
  unsigned filesize = m_file.size();
63
 
 
64
 
  // read dBASE version
65
 
  quint8 ver;
66
 
  m_stream >> ver;
67
 
  m_version = ver & 0x7f; // bit 7: has memo ?
68
 
 
69
 
  // only dBASE V.3 is supported
70
 
  if ( m_version != 3 )
71
 
     return false;
72
 
 
73
 
  // date of last update
74
 
  quint8 y, m, d;
75
 
  m_stream >> y >> m >> d;
76
 
  // because dBASE saves 102 instead of 2002 (very Y2K-save ;-)
77
 
  m_lastUpdate.setYMD( y+1900, m, d );
78
 
 
79
 
  // check for valid date
80
 
  if( !m_lastUpdate.isValid() ) return false;
81
 
 
82
 
  // number of records
83
 
  quint32 norec;
84
 
  m_stream >> norec;
85
 
  m_recordCount = norec;
86
 
 
87
 
  // header-length
88
 
  quint16 header_length;
89
 
  m_stream >> header_length;
90
 
  m_headerLength = header_length;
91
 
 
92
 
  // record-length
93
 
  quint16 record_length;
94
 
  m_stream >> record_length;
95
 
  m_recordLength = record_length;
96
 
 
97
 
  // read the remaining chars
98
 
  quint8 dummy;
99
 
  for (int foo = 0; foo < 20; ++foo)
100
 
    m_stream >> dummy;
101
 
 
102
 
  // size of file must match
103
 
  if( filesize < m_headerLength + m_recordLength * m_recordCount )
104
 
    return false;
105
 
 
106
 
  // Now read the headers of the columns and their type
107
 
 
108
 
  // Type                              char     Content
109
 
  //
110
 
  // unsigned char field_name[11]      0-10     Fieldname
111
 
  // unsigned char field_type          11       Fieldtype
112
 
  // unsigned long field_address       12-15    Fielddataaddress
113
 
  // unsigned char field_length        16       Fieldlength
114
 
  // unsigned char field_decimals      17       decimals
115
 
  // unsigned char reserved[14]        18-31    reserved for internal dBASE-stuff
116
 
 
117
 
  while(!fields.isEmpty()) delete fields.takeFirst();
118
 
  for( unsigned i = 1; i < m_headerLength/32; ++i )
119
 
  {
120
 
    DBaseField* field = new DBaseField;
121
 
 
122
 
    // columnn-name
123
 
    quint8 colname[12];
124
 
    for ( int j = 0; j < 11; ++j)
125
 
       m_stream >> colname[j];
126
 
    colname[11] = '\0';
127
 
    field->name = QString( (const char*) &colname[0] );
128
 
 
129
 
    // type of column
130
 
    quint8 coltype;
131
 
    m_stream >> coltype;
132
 
    switch( coltype )
133
 
    {
134
 
      case 'C': field->type = DBaseField::Character; break;
135
 
      case 'N': field->type = DBaseField::Numeric; break;
136
 
      case 'D': field->type = DBaseField::Date; break;
137
 
      case 'M': field->type = DBaseField::Memo; break;
138
 
      case 'L': field->type = DBaseField::Logical; break;
139
 
      default: field->type = DBaseField::Unknown; break;
140
 
    }
141
 
 
142
 
    // fileddataaddress
143
 
    quint32 addr;
144
 
    m_stream >> addr;
145
 
 
146
 
    // columnlength
147
 
    quint8 colsize;
148
 
    m_stream >> colsize;
149
 
    field->length = colsize;
150
 
 
151
 
    // decimals
152
 
    quint8 decimals;
153
 
    m_stream >> decimals;
154
 
    field->decimals = decimals;
155
 
 
156
 
    // read remaining chars
 
55
    m_file.setFileName(filename);
 
56
    if (!m_file.open(QIODevice::ReadOnly))
 
57
        return false;
 
58
 
 
59
    m_stream.setDevice(&m_file);
 
60
    m_stream.setByteOrder(QDataStream::LittleEndian);
 
61
 
 
62
    unsigned filesize = m_file.size();
 
63
 
 
64
    // read dBASE version
 
65
    quint8 ver;
 
66
    m_stream >> ver;
 
67
    m_version = ver & 0x7f; // bit 7: has memo ?
 
68
 
 
69
    // only dBASE V.3 is supported
 
70
    if (m_version != 3)
 
71
        return false;
 
72
 
 
73
    // date of last update
 
74
    quint8 y, m, d;
 
75
    m_stream >> y >> m >> d;
 
76
    // because dBASE saves 102 instead of 2002 (very Y2K-save ;-)
 
77
    m_lastUpdate.setYMD(y + 1900, m, d);
 
78
 
 
79
    // check for valid date
 
80
    if (!m_lastUpdate.isValid()) return false;
 
81
 
 
82
    // number of records
 
83
    quint32 norec;
 
84
    m_stream >> norec;
 
85
    m_recordCount = norec;
 
86
 
 
87
    // header-length
 
88
    quint16 header_length;
 
89
    m_stream >> header_length;
 
90
    m_headerLength = header_length;
 
91
 
 
92
    // record-length
 
93
    quint16 record_length;
 
94
    m_stream >> record_length;
 
95
    m_recordLength = record_length;
 
96
 
 
97
    // read the remaining chars
157
98
    quint8 dummy;
158
 
    for ( int foo = 0; foo < 14; ++foo )
159
 
      m_stream >> dummy;
160
 
 
161
 
    // now append
162
 
    fields.append( field );
163
 
  }
164
 
 
165
 
  // set the index to the first record
166
 
  m_stream.device()->seek( m_headerLength );
167
 
 
168
 
  return true;
 
99
    for (int foo = 0; foo < 20; ++foo)
 
100
        m_stream >> dummy;
 
101
 
 
102
    // size of file must match
 
103
    if (filesize < m_headerLength + m_recordLength * m_recordCount)
 
104
        return false;
 
105
 
 
106
    // Now read the headers of the columns and their type
 
107
 
 
108
    // Type                              char     Content
 
109
    //
 
110
    // unsigned char field_name[11]      0-10     Fieldname
 
111
    // unsigned char field_type          11       Fieldtype
 
112
    // unsigned long field_address       12-15    Fielddataaddress
 
113
    // unsigned char field_length        16       Fieldlength
 
114
    // unsigned char field_decimals      17       decimals
 
115
    // unsigned char reserved[14]        18-31    reserved for internal dBASE-stuff
 
116
 
 
117
    while (!fields.isEmpty()) delete fields.takeFirst();
 
118
    for (unsigned i = 1; i < m_headerLength / 32; ++i) {
 
119
        DBaseField* field = new DBaseField;
 
120
 
 
121
        // columnn-name
 
122
        quint8 colname[12];
 
123
        for (int j = 0; j < 11; ++j)
 
124
            m_stream >> colname[j];
 
125
        colname[11] = '\0';
 
126
        field->name = QString((const char*) & colname[0]);
 
127
 
 
128
        // type of column
 
129
        quint8 coltype;
 
130
        m_stream >> coltype;
 
131
        switch (coltype) {
 
132
        case 'C': field->type = DBaseField::Character; break;
 
133
        case 'N': field->type = DBaseField::Numeric; break;
 
134
        case 'D': field->type = DBaseField::Date; break;
 
135
        case 'M': field->type = DBaseField::Memo; break;
 
136
        case 'L': field->type = DBaseField::Logical; break;
 
137
        default: field->type = DBaseField::Unknown; break;
 
138
        }
 
139
 
 
140
        // fileddataaddress
 
141
        quint32 addr;
 
142
        m_stream >> addr;
 
143
 
 
144
        // columnlength
 
145
        quint8 colsize;
 
146
        m_stream >> colsize;
 
147
        field->length = colsize;
 
148
 
 
149
        // decimals
 
150
        quint8 decimals;
 
151
        m_stream >> decimals;
 
152
        field->decimals = decimals;
 
153
 
 
154
        // read remaining chars
 
155
        quint8 dummy;
 
156
        for (int foo = 0; foo < 14; ++foo)
 
157
            m_stream >> dummy;
 
158
 
 
159
        // now append
 
160
        fields.append(field);
 
161
    }
 
162
 
 
163
    // set the index to the first record
 
164
    m_stream.device()->seek(m_headerLength);
 
165
 
 
166
    return true;
169
167
}
170
168
 
171
 
QStringList DBase::readRecord( unsigned recno )
 
169
QStringList DBase::readRecord(unsigned recno)
172
170
{
173
 
  QStringList result;
174
 
 
175
 
  // out of range ? return empty strings
176
 
  if( recno >= m_recordCount )
177
 
  {
178
 
    for( unsigned i=0; i<fields.count(); i++)
179
 
      result.append( "" );
 
171
    QStringList result;
 
172
 
 
173
    // out of range ? return empty strings
 
174
    if (recno >= m_recordCount) {
 
175
        for (int i = 0; i < fields.count(); i++)
 
176
            result.append("");
 
177
        return result;
 
178
    }
 
179
 
 
180
    // seek to where the record is
 
181
    qint64 filepos = m_headerLength + recno * m_recordLength;
 
182
    m_stream.device()->seek(filepos);
 
183
 
 
184
    // first char == '*' means the record is deleted
 
185
    // so we just skip it
 
186
    quint8 delmarker;
 
187
    m_stream >> delmarker;
 
188
    if (delmarker == 0x2a)
 
189
        return result;
 
190
 
 
191
    // load it
 
192
    for (int i = 0; i < fields.count(); i++)
 
193
        switch (fields.at(i)->type) {
 
194
            // Numeric or Character
 
195
        case DBaseField::Numeric:
 
196
        case DBaseField::Character: {
 
197
            QString str;
 
198
            quint8 ch;
 
199
            for (unsigned j = 0; j < fields.at(i)->length; j++) {
 
200
                m_stream >> ch; str += QChar(ch);
 
201
            }
 
202
            result.append(str);
 
203
        }
 
204
        break;
 
205
 
 
206
        // Logical
 
207
        case DBaseField::Logical: {
 
208
            quint8 ch;
 
209
            m_stream >> ch;
 
210
            switch (ch) {
 
211
            case 'Y': case 'y': case 'T': case 't': result.append("True"); break;
 
212
            case 'N': case 'n': case 'F': case 'f': result.append("False"); break;
 
213
            default: result.append(""); break;
 
214
            }
 
215
        }
 
216
        break;
 
217
 
 
218
        // Date, stored as YYYYMMDD
 
219
        // Note: convert it to YYYY-MM-DD
 
220
        case DBaseField::Date: {
 
221
            QString str;
 
222
            quint8 ch;
 
223
            for (unsigned j = 0; j < fields.at(i)->length; j++) {
 
224
                m_stream >> ch; str += QChar(ch);
 
225
            }
 
226
            str.insert(6, '-');
 
227
            str.insert(4, '-');
 
228
            result.append(str);
 
229
        }
 
230
        break;
 
231
 
 
232
        // Unknown/Unimplemented
 
233
        case DBaseField::Unknown:
 
234
        case DBaseField::Memo:
 
235
        default:
 
236
            result.append("");   // unknown
 
237
            break;
 
238
        }
 
239
 
180
240
    return result;
181
 
  }
182
 
 
183
 
  // seek to where the record is
184
 
  qint64 filepos = m_headerLength + recno * m_recordLength;
185
 
  m_stream.device()->seek( filepos );
186
 
 
187
 
  // first char == '*' means the record is deleted
188
 
  // so we just skip it
189
 
  quint8 delmarker;
190
 
  m_stream >> delmarker;
191
 
  if( delmarker == 0x2a )
192
 
   return result;
193
 
 
194
 
  // load it
195
 
  for( unsigned i=0; i<fields.count(); i++ )
196
 
    switch( fields.at(i)->type )
197
 
    {
198
 
      // Numeric or Character
199
 
      case DBaseField::Numeric:
200
 
      case DBaseField::Character:
201
 
      {
202
 
        QString str;
203
 
        quint8 ch;
204
 
        for( unsigned j=0; j<fields.at(i)->length; j++ )
205
 
        {  m_stream >> ch; str += QChar(ch); }
206
 
        result.append( str );
207
 
      }  break;
208
 
 
209
 
      // Logical
210
 
      case DBaseField::Logical:
211
 
      {
212
 
        quint8 ch;
213
 
        m_stream >> ch;
214
 
        switch( ch )
215
 
        {
216
 
          case 'Y': case 'y': case 'T': case 't': result.append( "True" ); break;
217
 
          case 'N': case 'n': case 'F': case 'f': result.append( "False" ); break;
218
 
          default: result.append( "" ); break;
219
 
        }
220
 
      } break;
221
 
 
222
 
      // Date, stored as YYYYMMDD
223
 
      // Note: convert it to YYYY-MM-DD
224
 
      case DBaseField::Date:
225
 
      {
226
 
        QString str;
227
 
        quint8 ch;
228
 
        for( unsigned j=0; j<fields.at(i)->length; j++ )
229
 
        {  m_stream >> ch; str += QChar(ch); }
230
 
        str.insert( 6, '-' );
231
 
        str.insert( 4, '-' );
232
 
        result.append( str );
233
 
      } break;
234
 
 
235
 
      // Unknown/Unimplemented
236
 
      case DBaseField::Unknown:
237
 
      case DBaseField::Memo:
238
 
      default:
239
 
        result.append( "" ); // unknown
240
 
        break;
241
 
    }
242
 
 
243
 
  return result;
244
241
}
245
242
 
246
243
void DBase::close()
247
244
{
248
 
  if( m_file.isOpen() ) m_file.close();
 
245
    if (m_file.isOpen()) m_file.close();
249
246
}