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

« back to all changes in this revision

Viewing changes to filters/kword/palmdoc/palmdoc.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:
24
24
 
25
25
PalmDoc::PalmDoc(): PalmDB()
26
26
{
27
 
  m_result = PalmDoc::OK;
28
 
  setText( QString() );
 
27
    m_result = PalmDoc::OK;
 
28
    setText(QString());
29
29
}
30
30
 
31
31
PalmDoc::~PalmDoc()
32
32
{
33
33
}
34
34
 
35
 
bool PalmDoc::load( const char* filename )
 
35
bool PalmDoc::load(const char* filename)
36
36
{
37
 
  bool ok;
38
 
 
39
 
  ok = PalmDB::load( filename );
40
 
  if( !ok )
41
 
  {
42
 
    m_result = PalmDoc::ReadError;
43
 
    return false;
44
 
  }
45
 
 
46
 
  if( type() != "TEXt" )
47
 
  {
48
 
    qDebug( "Type is \"%s\", not \"TEXt\", so this is not Palm DOC!", type().latin1() );
49
 
    m_result = PalmDoc::InvalidFormat;
50
 
    return false;
51
 
  }
52
 
 
53
 
  if( creator() != "REAd" )
54
 
  {
55
 
    qDebug( "Creator is \"%s\", not \"REAd\", so this is not Palm DOC!",
56
 
      creator().latin1() );
57
 
    m_result = PalmDoc::InvalidFormat;
58
 
    return false;
59
 
  }
60
 
 
61
 
  // must have at least two records
62
 
  if( records.count() < 2 )
63
 
  {
64
 
    qDebug( "Palm DOC has at least 2 records!" );
65
 
    m_result = PalmDoc::InvalidFormat;
66
 
    return false;
67
 
  }
68
 
 
69
 
  // the very first record is DOC header
70
 
  // NOTE: this is not PDB header (which is handled in PalmDB) !
71
 
  QByteArray header( *records.at( 0 ) );
72
 
 
73
 
  // format of the DOC
74
 
  int format = ((int)header[0]<<8) + (int)header[1];
75
 
  qDebug( "DOC format: %d (%s)", format,
76
 
     (format==1) ? "Plain" : (format==2) ? "Compressed" : "Unknown" );
77
 
 
78
 
  // supported is only Plain or Compressed
79
 
  if( ( format != 1 ) && ( format != 2 ) )
80
 
  {
81
 
    qDebug( "Unknown format of document!" );
82
 
    m_result = PalmDoc::InvalidFormat;
83
 
    return false;
84
 
  }
85
 
 
86
 
  // initialize
87
 
  setText( QString() );
88
 
 
89
 
  // assemble the records
90
 
  QByteArray rec;
91
 
  unsigned i = 0;
92
 
  for( unsigned r = 1; r < records.count(); r++ )
93
 
  {
94
 
     QByteArray *p = records.at( r );
95
 
     if( !p ) continue;
96
 
     rec.resize( rec.size() + p->size() );
97
 
     for( unsigned s=0; s<p->size(); s++ )
98
 
       rec[i++] = p->at( s );
99
 
  }
100
 
 
101
 
  // if the text is compressed, then uncompress
102
 
  if( format == 2 )
103
 
    setText( uncompress( rec ) );
104
 
 
105
 
  // if the text is not compressed, simply append as string
106
 
  if( format == 1 )
107
 
      setText( QString::fromLatin1( rec.data(),rec.count() ) );
108
 
 
109
 
  // done
110
 
  m_result = OK;
111
 
  return true;
 
37
    bool ok;
 
38
 
 
39
    ok = PalmDB::load(filename);
 
40
    if (!ok) {
 
41
        m_result = PalmDoc::ReadError;
 
42
        return false;
 
43
    }
 
44
 
 
45
    if (type() != "TEXt") {
 
46
        qDebug("Type is \"%s\", not \"TEXt\", so this is not Palm DOC!", qPrintable(type()));
 
47
        m_result = PalmDoc::InvalidFormat;
 
48
        return false;
 
49
    }
 
50
 
 
51
    if (creator() != "REAd") {
 
52
        qDebug("Creator is \"%s\", not \"REAd\", so this is not Palm DOC!",
 
53
               qPrintable(creator()));
 
54
        m_result = PalmDoc::InvalidFormat;
 
55
        return false;
 
56
    }
 
57
 
 
58
    // must have at least two records
 
59
    if (records.count() < 2) {
 
60
        qDebug("Palm DOC has at least 2 records!");
 
61
        m_result = PalmDoc::InvalidFormat;
 
62
        return false;
 
63
    }
 
64
 
 
65
    // the very first record is DOC header
 
66
    // NOTE: this is not PDB header (which is handled in PalmDB) !
 
67
    QByteArray header(*records.at(0));
 
68
 
 
69
    // format of the DOC
 
70
    int format = ((int)header[0] << 8) + (int)header[1];
 
71
    qDebug("DOC format: %d (%s)", format,
 
72
           (format == 1) ? "Plain" : (format == 2) ? "Compressed" : "Unknown");
 
73
 
 
74
    // supported is only Plain or Compressed
 
75
    if ((format != 1) && (format != 2)) {
 
76
        qDebug("Unknown format of document!");
 
77
        m_result = PalmDoc::InvalidFormat;
 
78
        return false;
 
79
    }
 
80
 
 
81
    // initialize
 
82
    setText(QString());
 
83
 
 
84
    // assemble the records
 
85
    QByteArray rec;
 
86
    unsigned i = 0;
 
87
    for (unsigned r = 1; r < records.count(); r++) {
 
88
        QByteArray *p = records.at(r);
 
89
        if (!p) continue;
 
90
        rec.resize(rec.size() + p->size());
 
91
        for (unsigned s = 0; s < p->size(); s++)
 
92
            rec[i++] = p->at(s);
 
93
    }
 
94
 
 
95
    // if the text is compressed, then uncompress
 
96
    if (format == 2)
 
97
        setText(uncompress(rec));
 
98
 
 
99
    // if the text is not compressed, simply append as string
 
100
    if (format == 1)
 
101
        setText(QString::fromLatin1(rec.data(), rec.count()));
 
102
 
 
103
    // done
 
104
    m_result = OK;
 
105
    return true;
112
106
}
113
107
 
114
 
bool PalmDoc::save( const char* filename )
 
108
bool PalmDoc::save(const char* filename)
115
109
{
116
 
  // set proper database type and creator
117
 
  setType( "TEXt" );
118
 
  setCreator( "REAd" );
119
 
 
120
 
  // "touch" the database :-)
121
 
  setModificationDate( QDateTime::currentDateTime() );
122
 
 
123
 
  // Palm record size is always 4 KB
124
 
  unsigned recsize = 4096;
125
 
 
126
 
  // compress the text
127
 
  QByteArray data = compress( text() );
128
 
 
129
 
  // prepare the records
130
 
  records.clear();
131
 
  for( unsigned i=0; i<data.count(); )
132
 
  {
133
 
    QByteArray* ptr = new QByteArray;
134
 
    unsigned rs = data.count() - i;
135
 
    if( rs > recsize ) rs = recsize;
136
 
    ptr->resize( rs );
137
 
    for( unsigned m=0; m<rs; m++ )
138
 
      (*ptr)[m] = data[i++];
139
 
    records.append( ptr );
140
 
  }
141
 
 
142
 
  // prepare the header
143
 
  QByteArray header( 16 );
144
 
  int docsize = m_text.length();
145
 
  header[0] = 0; header[1] = 2;  // 1=plain, 2=compressed
146
 
  header[2] = header[3] = 0; // reserved word, set to 0
147
 
  header[4] = (docsize >> 24) & 255; // uncompressed size
148
 
  header[5] = (docsize >> 16) & 255;
149
 
  header[6] = (docsize >> 8) & 255;
150
 
  header[7] = docsize & 255;
151
 
  header[8] = records.count()>> 8; // no of records
152
 
  header[9] = records.count() & 255;
153
 
  header[10] = recsize >>8; // record size
154
 
  header[11] = recsize & 255;
155
 
  header[12] = header[13] = 0;
156
 
  header[14] = header[15] = 0;
157
 
 
158
 
  // header should be the very first record
159
 
  records.prepend( new QByteArray( header ) );
160
 
 
161
 
  // write to file
162
 
  bool ok = PalmDB::save( filename );
163
 
  if( !ok )
164
 
  {
165
 
    m_result = WriteError;
166
 
    return false;
167
 
  }
168
 
 
169
 
  // done
170
 
  m_result = OK;
171
 
  return true;
 
110
    // set proper database type and creator
 
111
    setType("TEXt");
 
112
    setCreator("REAd");
 
113
 
 
114
    // "touch" the database :-)
 
115
    setModificationDate(QDateTime::currentDateTime());
 
116
 
 
117
    // Palm record size is always 4 KB
 
118
    unsigned recsize = 4096;
 
119
 
 
120
    // compress the text
 
121
    QByteArray data = compress(text());
 
122
 
 
123
    // prepare the records
 
124
    records.clear();
 
125
    for (unsigned i = 0; i < data.count();) {
 
126
        QByteArray* ptr = new QByteArray;
 
127
        unsigned rs = data.count() - i;
 
128
        if (rs > recsize) rs = recsize;
 
129
        ptr->resize(rs);
 
130
        for (unsigned m = 0; m < rs; m++)
 
131
            (*ptr)[m] = data[i++];
 
132
        records.append(ptr);
 
133
    }
 
134
 
 
135
    // prepare the header
 
136
    QByteArray header(16);
 
137
    int docsize = m_text.length();
 
138
    header[0] = 0; header[1] = 2;  // 1=plain, 2=compressed
 
139
    header[2] = header[3] = 0; // reserved word, set to 0
 
140
    header[4] = (docsize >> 24) & 255; // uncompressed size
 
141
    header[5] = (docsize >> 16) & 255;
 
142
    header[6] = (docsize >> 8) & 255;
 
143
    header[7] = docsize & 255;
 
144
    header[8] = records.count() >> 8; // no of records
 
145
    header[9] = records.count() & 255;
 
146
    header[10] = recsize >> 8; // record size
 
147
    header[11] = recsize & 255;
 
148
    header[12] = header[13] = 0;
 
149
    header[14] = header[15] = 0;
 
150
 
 
151
    // header should be the very first record
 
152
    records.prepend(new QByteArray(header));
 
153
 
 
154
    // write to file
 
155
    bool ok = PalmDB::save(filename);
 
156
    if (!ok) {
 
157
        m_result = WriteError;
 
158
        return false;
 
159
    }
 
160
 
 
161
    // done
 
162
    m_result = OK;
 
163
    return true;
172
164
}
173
165
 
174
166
// TODO describe in brief about compression algorithm
175
 
QByteArray PalmDoc::compress( const QString& text )
 
167
QByteArray PalmDoc::compress(const QString& text)
176
168
{
177
 
  QByteArray result;
178
 
  unsigned textlen = text.length();
179
 
  const char *ctext =  text.latin1();
180
 
  unsigned int i, j;
181
 
 
182
 
  // we don't know the compressed size yet
183
 
  // therefore allocate buffer big enough
184
 
  result.resize( textlen );
185
 
 
186
 
  for( i=j=0; i<textlen;  )
187
 
  {
188
 
    int horizon = 2047;
189
 
    int start = (i < horizon) ? 0 : i-horizon;
190
 
    bool match = false;
191
 
    int match_pos=0, match_len=0;
192
 
 
193
 
    // look for match in the buffer
194
 
    for( int back = i-1; (!match) && (back > start); back-- )
195
 
      if( ctext[i] == ctext[back] )
196
 
      if( ctext[i+1] == ctext[back+1] )
197
 
      if( ctext[i+2] == ctext[back+2] )
198
 
      {
199
 
         match = true;
200
 
         match_pos = i-back;
201
 
         match_len = 3;
202
 
 
203
 
         if( i+3 < textlen )
204
 
           if( ctext[i+3] == ctext[back+3] )
205
 
           {
206
 
              match_len = 4;
207
 
              if( i+4 < textlen )
208
 
                if( ctext[i+4] == ctext[back+4] )
209
 
                {
210
 
                  match_len = 5;
211
 
                }
212
 
           }
213
 
 
214
 
      }
215
 
 
216
 
   if( match )
217
 
   {
218
 
     unsigned char p = 0x80 | ((match_pos >> 5)&0x3f);
219
 
     unsigned char q = ((match_pos & 0x1f) << 3) | (match_len-3);
220
 
     result[j++] = p;
221
 
     result[j++] = q;
222
 
     i+= match_len;
223
 
   }
224
 
   else
225
 
   {
226
 
     char ch = ctext[i++] & 0x7f;
227
 
     bool space_pack = false;
228
 
 
229
 
     if( ch == 0x20 )
230
 
       if ( i<textlen )
231
 
         if( ctext[i] >= 0x40 )
232
 
            space_pack = true;
233
 
 
234
 
     if( !space_pack ) result[j++] = ch;
235
 
     else result[j++] = ctext[i++] | 0x80;
236
 
   }
237
 
 
238
 
  }
239
 
 
240
 
  result.resize( j );
241
 
 
242
 
  return result;
 
169
    QByteArray result;
 
170
    unsigned textlen = text.length();
 
171
    const char *ctext =  text.toLatin1();
 
172
    unsigned int i, j;
 
173
 
 
174
    // we don't know the compressed size yet
 
175
    // therefore allocate buffer big enough
 
176
    result.resize(textlen);
 
177
 
 
178
    for (i = j = 0; i < textlen;) {
 
179
        int horizon = 2047;
 
180
        int start = (i < horizon) ? 0 : i - horizon;
 
181
        bool match = false;
 
182
        int match_pos = 0, match_len = 0;
 
183
 
 
184
        // look for match in the buffer
 
185
        for (int back = i - 1; (!match) && (back > start); back--)
 
186
            if (ctext[i] == ctext[back])
 
187
                if (ctext[i+1] == ctext[back+1])
 
188
                    if (ctext[i+2] == ctext[back+2]) {
 
189
                        match = true;
 
190
                        match_pos = i - back;
 
191
                        match_len = 3;
 
192
 
 
193
                        if (i + 3 < textlen)
 
194
                            if (ctext[i+3] == ctext[back+3]) {
 
195
                                match_len = 4;
 
196
                                if (i + 4 < textlen)
 
197
                                    if (ctext[i+4] == ctext[back+4]) {
 
198
                                        match_len = 5;
 
199
                                    }
 
200
                            }
 
201
 
 
202
                    }
 
203
 
 
204
        if (match) {
 
205
            unsigned char p = 0x80 | ((match_pos >> 5) & 0x3f);
 
206
            unsigned char q = ((match_pos & 0x1f) << 3) | (match_len - 3);
 
207
            result[j++] = p;
 
208
            result[j++] = q;
 
209
            i += match_len;
 
210
        } else {
 
211
            char ch = ctext[i++] & 0x7f;
 
212
            bool space_pack = false;
 
213
 
 
214
            if (ch == 0x20)
 
215
                if (i < textlen)
 
216
                    if (ctext[i] >= 0x40)
 
217
                        space_pack = true;
 
218
 
 
219
            if (!space_pack) result[j++] = ch;
 
220
            else result[j++] = ctext[i++] | 0x80;
 
221
        }
 
222
 
 
223
    }
 
224
 
 
225
    result.resize(j);
 
226
 
 
227
    return result;
243
228
}
244
229
 
245
230
#define INRANGE(v,p,q) ((v)>=(p))&&((v)<=(q))
246
231
 
247
232
// TODO describe in brief about decompression algorithm
248
 
QString PalmDoc::uncompress( const QByteArray& rec )
 
233
QString PalmDoc::uncompress(const QByteArray& rec)
249
234
{
250
 
  QString result;
251
 
 
252
 
  for( unsigned i = 0; i < rec.size(); i++ )
253
 
  {
254
 
    unsigned char c = rec[i];
255
 
 
256
 
    if( INRANGE(c,1,8) )
257
 
    {
258
 
      i++;
259
 
      if( i < rec.size() )
260
 
         for( unsigned char v = rec[i]; c>0; c-- )
261
 
            result.append( v );
262
 
    }
263
 
 
264
 
    else if( INRANGE(c,0x09,0x7F) )
265
 
      result.append( c );
266
 
 
267
 
    else if( INRANGE(c,0xC0,0xFF) )
268
 
      result.append( 32 ).append( c^ 0x80 );
269
 
 
270
 
    else if( INRANGE(c,0x80,0xBF) )
271
 
    {
272
 
      unsigned char d = rec[++i];
273
 
      int back = (((c<<8)+d) & 0x3fff) >> 3;
274
 
      int count = (d & 7) + 3;
275
 
      if( result.length()-back >= 0 )
276
 
        for(; count>0; count-- )
277
 
          result.append( result[result.length()-back] );
278
 
    }
279
 
 
280
 
  }
281
 
 
282
 
  return result;
 
235
    QString result;
 
236
 
 
237
    for (unsigned i = 0; i < rec.size(); i++) {
 
238
        unsigned char c = rec[i];
 
239
 
 
240
        if (INRANGE(c, 1, 8)) {
 
241
            i++;
 
242
            if (i < rec.size())
 
243
                for (unsigned char v = rec[i]; c > 0; c--)
 
244
                    result.append(v);
 
245
        }
 
246
 
 
247
        else if (INRANGE(c, 0x09, 0x7F))
 
248
            result.append(c);
 
249
 
 
250
        else if (INRANGE(c, 0xC0, 0xFF))
 
251
            result.append(32).append(c ^ 0x80);
 
252
 
 
253
        else if (INRANGE(c, 0x80, 0xBF)) {
 
254
            unsigned char d = rec[++i];
 
255
            int back = (((c << 8) + d) & 0x3fff) >> 3;
 
256
            int count = (d & 7) + 3;
 
257
            if (result.length() - back >= 0)
 
258
                for (; count > 0; count--)
 
259
                    result.append(result[result.length()-back]);
 
260
        }
 
261
 
 
262
    }
 
263
 
 
264
    return result;
283
265
}