~ubuntu-branches/ubuntu/trusty/libwpd/trusty

« back to all changes in this revision

Viewing changes to src/lib/WPXOLEStream.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Rene Engelhard
  • Date: 2008-02-12 15:22:12 UTC
  • mfrom: (1.2.1 upstream) (10.1.5 gutsy)
  • Revision ID: james.westby@ubuntu.com-20080212152212-beh3l4ahg9b4o3lj
Tags: 0.8.14-1
New upstream release

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* POLE - Portable C++ library to access OLE Storage 
 
2
   Copyright (C) 2002-2005 Ariya Hidayat <ariya@kde.org>
 
3
 
 
4
   Redistribution and use in source and binary forms, with or without 
 
5
   modification, are permitted provided that the following conditions 
 
6
   are met:
 
7
   * Redistributions of source code must retain the above copyright notice, 
 
8
     this list of conditions and the following disclaimer.
 
9
   * Redistributions in binary form must reproduce the above copyright notice, 
 
10
     this list of conditions and the following disclaimer in the documentation 
 
11
     and/or other materials provided with the distribution.
 
12
   * Neither the name of the authors nor the names of its contributors may be 
 
13
     used to endorse or promote products derived from this software without 
 
14
     specific prior written permission.
 
15
 
 
16
   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
 
17
   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
 
18
   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
 
19
   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
 
20
   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
 
21
   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
 
22
   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
 
23
   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
 
24
   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
 
25
   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 
 
26
   THE POSSIBILITY OF SUCH DAMAGE.
 
27
*/
 
28
 
 
29
/*
 
30
 This file taken from libwpg WPGOLEStream.cpp 1.5 Thu Aug 17 21:21:30 2006
 
31
*/
 
32
 
 
33
#include <sstream>
 
34
#include <iostream>
 
35
#include <list>
 
36
#include <string>
 
37
#include <vector>
 
38
 
 
39
#include "WPXOLEStream.h"
 
40
#include <string.h>
 
41
 
 
42
namespace libwpd
 
43
{
 
44
 
 
45
class Header
 
46
{
 
47
  public:
 
48
    unsigned char id[8];       // signature, or magic identifier
 
49
    unsigned b_shift;          // bbat->blockSize = 1 << b_shift
 
50
    unsigned s_shift;          // sbat->blockSize = 1 << s_shift
 
51
    unsigned num_bat;          // blocks allocated for big bat
 
52
    unsigned dirent_start;     // starting block for directory info
 
53
    unsigned threshold;        // switch from small to big file (usually 4K)
 
54
    unsigned sbat_start;       // starting block index to store small bat
 
55
    unsigned num_sbat;         // blocks allocated for small bat
 
56
    unsigned mbat_start;       // starting block to store meta bat
 
57
    unsigned num_mbat;         // blocks allocated for meta bat
 
58
    unsigned long bb_blocks[109];
 
59
    
 
60
    Header();
 
61
    bool valid();
 
62
    void load( const unsigned char* buffer );
 
63
    void save( unsigned char* buffer );
 
64
    void debug();
 
65
};
 
66
 
 
67
class AllocTable
 
68
{
 
69
  public:
 
70
    static const unsigned Eof;
 
71
    static const unsigned Avail;
 
72
    static const unsigned Bat;    
 
73
    static const unsigned MetaBat;    
 
74
    unsigned blockSize;
 
75
    AllocTable();
 
76
    void clear();
 
77
    unsigned long count();
 
78
    void resize( unsigned long newsize );
 
79
    void preserve( unsigned long n );
 
80
    void set( unsigned long index, unsigned long val );
 
81
    unsigned unused();
 
82
    void setChain( std::vector<unsigned long> );
 
83
    std::vector<unsigned long> follow( unsigned long start );
 
84
    unsigned long operator[](unsigned long index );
 
85
    void load( const unsigned char* buffer, unsigned len );
 
86
    void save( unsigned char* buffer );
 
87
  private:
 
88
    std::vector<unsigned long> data;
 
89
    AllocTable( const AllocTable& );
 
90
    AllocTable& operator=( const AllocTable& );
 
91
};
 
92
 
 
93
class DirEntry
 
94
{
 
95
  public:
 
96
    DirEntry() : valid(false), name(), dir(false), size(0), start(0),
 
97
        prev(0), next(0), child(0) {};
 
98
    bool valid;            // false if invalid (should be skipped)
 
99
    std::string name;      // the name, not in unicode anymore 
 
100
    bool dir;              // true if directory   
 
101
    unsigned long size;    // size (not valid if directory)
 
102
    unsigned long start;   // starting block
 
103
    unsigned prev;         // previous sibling
 
104
    unsigned next;         // next sibling
 
105
    unsigned child;        // first child
 
106
};
 
107
 
 
108
class DirTree
 
109
{
 
110
  public:
 
111
    static const unsigned End;
 
112
    DirTree();
 
113
    void clear();
 
114
    unsigned entryCount();
 
115
    DirEntry* entry( unsigned index );
 
116
    DirEntry* entry( const std::string& name );
 
117
    int parent( unsigned index );
 
118
    std::string fullName( unsigned index );
 
119
    std::vector<unsigned> children( unsigned index );
 
120
    void load( unsigned char* buffer, unsigned len );
 
121
    void save( unsigned char* buffer );
 
122
  private:
 
123
    std::vector<DirEntry> entries;
 
124
    DirTree( const DirTree& );
 
125
    DirTree& operator=( const DirTree& );
 
126
};
 
127
 
 
128
class StorageIO
 
129
{
 
130
  public:
 
131
    Storage* storage;         // owner
 
132
    std::stringstream buf;
 
133
    int result;               // result of operation
 
134
    unsigned long bufsize;    // size of the buffer
 
135
    
 
136
    Header* header;           // storage header 
 
137
    DirTree* dirtree;         // directory tree
 
138
    AllocTable* bbat;         // allocation table for big blocks
 
139
    AllocTable* sbat;         // allocation table for small blocks
 
140
    
 
141
    std::vector<unsigned long> sb_blocks; // blocks for "small" files
 
142
       
 
143
    std::list<Stream*> streams;
 
144
 
 
145
    StorageIO( Storage* storage, const std::stringstream &memorystream );
 
146
    ~StorageIO();
 
147
    
 
148
    bool isOLEStream();
 
149
    void load();
 
150
 
 
151
    unsigned long loadBigBlocks( std::vector<unsigned long> blocks, unsigned char* buffer, unsigned long maxlen );
 
152
 
 
153
    unsigned long loadBigBlock( unsigned long block, unsigned char* buffer, unsigned long maxlen );
 
154
 
 
155
    unsigned long loadSmallBlocks( std::vector<unsigned long> blocks, unsigned char* buffer, unsigned long maxlen );
 
156
 
 
157
    unsigned long loadSmallBlock( unsigned long block, unsigned char* buffer, unsigned long maxlen );
 
158
    
 
159
    StreamIO* streamIO( const std::string& name ); 
 
160
 
 
161
  private:  
 
162
    // no copy or assign
 
163
    StorageIO( const StorageIO& );
 
164
    StorageIO& operator=( const StorageIO& );
 
165
 
 
166
};
 
167
 
 
168
class StreamIO
 
169
{
 
170
  public:
 
171
    StorageIO* io;
 
172
    DirEntry* entry;
 
173
    std::string fullName;
 
174
    bool eof;
 
175
    bool fail;
 
176
 
 
177
    StreamIO( StorageIO* io, DirEntry* entry );
 
178
    ~StreamIO();
 
179
    unsigned long size();
 
180
    unsigned long tell();
 
181
    int getch();
 
182
    unsigned long read( unsigned char* data, unsigned long maxlen );
 
183
    unsigned long read( unsigned long pos, unsigned char* data, unsigned long maxlen );
 
184
 
 
185
 
 
186
  private:
 
187
    std::vector<unsigned long> blocks;
 
188
 
 
189
    // no copy or assign
 
190
    StreamIO( const StreamIO& );
 
191
    StreamIO& operator=( const StreamIO& );
 
192
 
 
193
    // pointer for read
 
194
    unsigned long m_pos;
 
195
 
 
196
    // simple cache system to speed-up getch()
 
197
    unsigned char* cache_data;
 
198
    unsigned long cache_size;
 
199
    unsigned long cache_pos;
 
200
    void updateCache();
 
201
};
 
202
 
 
203
} // namespace libwpd
 
204
 
 
205
static inline unsigned long readU16( const unsigned char* ptr )
 
206
{
 
207
  return ptr[0]+(ptr[1]<<8);
 
208
}
 
209
 
 
210
static inline unsigned long readU32( const unsigned char* ptr )
 
211
{
 
212
  return ptr[0]+(ptr[1]<<8)+(ptr[2]<<16)+(ptr[3]<<24);
 
213
}
 
214
 
 
215
static const unsigned char wpsole_magic[] =
 
216
 { 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1 };
 
217
 
 
218
 
 
219
// =========== Header ==========
 
220
 
 
221
libwpd::Header::Header() :
 
222
        b_shift(9),
 
223
        s_shift(6),
 
224
        num_bat(0),
 
225
        dirent_start(0),
 
226
        threshold(4096),
 
227
        sbat_start(0),
 
228
        num_sbat(0),
 
229
        mbat_start(0),
 
230
        num_mbat(0)
 
231
{
 
232
  for( unsigned i = 0; i < 8; i++ )
 
233
    id[i] = wpsole_magic[i];
 
234
  for( unsigned j=0; j<109; j++ )
 
235
    bb_blocks[j] = libwpd::AllocTable::Avail;
 
236
}
 
237
 
 
238
bool libwpd::Header::valid()
 
239
{
 
240
  if( threshold != 4096 ) return false;
 
241
  if( num_bat == 0 ) return false;
 
242
  if( (num_bat > 109) && (num_bat > (num_mbat * 127) + 109)) return false;
 
243
  if( (num_bat < 109) && (num_mbat != 0) ) return false;
 
244
  if( s_shift > b_shift ) return false;
 
245
  if( b_shift <= 6 ) return false;
 
246
  if( b_shift >=31 ) return false;
 
247
 
 
248
  return true;
 
249
}
 
250
 
 
251
void libwpd::Header::load( const unsigned char* buffer )
 
252
{
 
253
  b_shift      = readU16( buffer + 0x1e );
 
254
  s_shift      = readU16( buffer + 0x20 );
 
255
  num_bat      = readU32( buffer + 0x2c );
 
256
  dirent_start = readU32( buffer + 0x30 );
 
257
  threshold    = readU32( buffer + 0x38 );
 
258
  sbat_start   = readU32( buffer + 0x3c );
 
259
  num_sbat     = readU32( buffer + 0x40 );
 
260
  mbat_start   = readU32( buffer + 0x44 );
 
261
  num_mbat     = readU32( buffer + 0x48 );
 
262
 
 
263
  for( unsigned i = 0; i < 8; i++ )
 
264
    id[i] = buffer[i];
 
265
  for( unsigned j=0; j<109; j++ )
 
266
    bb_blocks[j] = readU32( buffer + 0x4C+j*4 );
 
267
}
 
268
 
 
269
 
 
270
 
 
271
// =========== AllocTable ==========
 
272
 
 
273
const unsigned libwpd::AllocTable::Avail = 0xffffffff;
 
274
const unsigned libwpd::AllocTable::Eof = 0xfffffffe;
 
275
const unsigned libwpd::AllocTable::Bat = 0xfffffffd;
 
276
const unsigned libwpd::AllocTable::MetaBat = 0xfffffffc;
 
277
 
 
278
libwpd::AllocTable::AllocTable() :
 
279
        blockSize(4096),
 
280
        data()
 
281
{
 
282
  // initial size
 
283
  resize( 128 );
 
284
}
 
285
 
 
286
unsigned long libwpd::AllocTable::count()
 
287
{
 
288
  return data.size();
 
289
}
 
290
 
 
291
void libwpd::AllocTable::resize( unsigned long newsize )
 
292
{
 
293
  unsigned oldsize = data.size();
 
294
  data.resize( newsize );
 
295
  if( newsize > oldsize )
 
296
    for( unsigned i = oldsize; i<newsize; i++ )
 
297
      data[i] = Avail;
 
298
}
 
299
 
 
300
// make sure there're still free blocks
 
301
void libwpd::AllocTable::preserve( unsigned long n )
 
302
{
 
303
  std::vector<unsigned long> pre;
 
304
  for( unsigned i=0; i < n; i++ )
 
305
    pre.push_back( unused() );
 
306
}
 
307
 
 
308
unsigned long libwpd::AllocTable::operator[]( unsigned long index )
 
309
{
 
310
  unsigned long result;
 
311
  result = data[index];
 
312
  return result;
 
313
}
 
314
 
 
315
void libwpd::AllocTable::set( unsigned long index, unsigned long value )
 
316
{
 
317
  if( index >= count() ) resize( index + 1);
 
318
  data[ index ] = value;
 
319
}
 
320
 
 
321
void libwpd::AllocTable::setChain( std::vector<unsigned long> chain )
 
322
{
 
323
  if( chain.size() )
 
324
  {
 
325
    for( unsigned i=0; i<chain.size()-1; i++ )
 
326
      set( chain[i], chain[i+1] );
 
327
    set( chain[ chain.size()-1 ], AllocTable::Eof );
 
328
  }
 
329
}
 
330
 
 
331
// TODO: optimize this with better search
 
332
static bool already_exist(const std::vector<unsigned long>& chain,
 
333
unsigned long item)
 
334
{
 
335
 for(unsigned i = 0; i < chain.size(); i++)
 
336
   if(chain[i] == item) return true;
 
337
 
 
338
 return false;
 
339
 
340
 
 
341
// follow 
 
342
std::vector<unsigned long> libwpd::AllocTable::follow( unsigned long start )
 
343
{
 
344
  std::vector<unsigned long> chain;
 
345
 
 
346
  if( start >= count() ) return chain; 
 
347
 
 
348
  unsigned long p = start;
 
349
  while( p < count() )
 
350
  {
 
351
    if( p == (unsigned long)Eof ) break;
 
352
    if( p == (unsigned long)Bat ) break;
 
353
    if( p == (unsigned long)MetaBat ) break;
 
354
    if( already_exist(chain, p) ) break; 
 
355
    chain.push_back( p );
 
356
    if( data[p] >= count() ) break;
 
357
    p = data[ p ];
 
358
  }
 
359
 
 
360
  return chain;
 
361
}
 
362
 
 
363
unsigned libwpd::AllocTable::unused()
 
364
{
 
365
  // find first available block
 
366
  for( unsigned i = 0; i < data.size(); i++ )
 
367
    if( data[i] == Avail )
 
368
      return i;
 
369
  
 
370
  // completely full, so enlarge the table
 
371
  unsigned block = data.size();
 
372
  resize( data.size()+10 );
 
373
  return block;      
 
374
}
 
375
 
 
376
void libwpd::AllocTable::load( const unsigned char* buffer, unsigned len )
 
377
{
 
378
  resize( len / 4 );
 
379
  for( unsigned i = 0; i < count(); i++ )
 
380
    set( i, readU32( buffer + i*4 ) );
 
381
}
 
382
 
 
383
// =========== DirTree ==========
 
384
 
 
385
const unsigned libwpd::DirTree::End = 0xffffffff;
 
386
 
 
387
libwpd::DirTree::DirTree() :
 
388
        entries()
 
389
{
 
390
  clear();
 
391
}
 
392
 
 
393
void libwpd::DirTree::clear()
 
394
{
 
395
  // leave only root entry
 
396
  entries.resize( 1 );
 
397
  entries[0].valid = true;
 
398
  entries[0].name = "Root Entry";
 
399
  entries[0].dir = true;
 
400
  entries[0].size = 0;
 
401
  entries[0].start = End;
 
402
  entries[0].prev = End;
 
403
  entries[0].next = End;
 
404
  entries[0].child = End;
 
405
}
 
406
 
 
407
unsigned libwpd::DirTree::entryCount()
 
408
{
 
409
  return entries.size();
 
410
}
 
411
 
 
412
libwpd::DirEntry* libwpd::DirTree::entry( unsigned index )
 
413
{
 
414
  if( index >= entryCount() ) return (libwpd::DirEntry*) 0;
 
415
  return &entries[ index ];
 
416
}
 
417
 
 
418
int libwpd::DirTree::parent( unsigned index )
 
419
{
 
420
  // brute-force, basically we iterate for each entries, find its children
 
421
  // and check if one of the children is 'index'
 
422
  for( unsigned j=0; j<entryCount(); j++ )
 
423
  {
 
424
    std::vector<unsigned> chi = children( j );
 
425
    for( unsigned i=0; i<chi.size();i++ )
 
426
      if( chi[i] == index )
 
427
        return j;
 
428
  }
 
429
        
 
430
  return -1;
 
431
}
 
432
 
 
433
std::string libwpd::DirTree::fullName( unsigned index )
 
434
{
 
435
  // don't use root name ("Root Entry"), just give "/"
 
436
  if( index == 0 ) return "/";
 
437
 
 
438
  std::string result = entry( index )->name;
 
439
  result.insert( 0,  "/" );
 
440
  int p = parent( index );
 
441
  DirEntry * _entry = 0;
 
442
  while( p > 0 )
 
443
  {
 
444
    _entry = entry( p );
 
445
    if (_entry->dir && _entry->valid)
 
446
    {
 
447
      result.insert( 0,  _entry->name);
 
448
      result.insert( 0,  "/" );
 
449
    }
 
450
    --p;
 
451
    index = p;
 
452
    if( index <= 0 ) break;
 
453
  }
 
454
  return result;
 
455
}
 
456
 
 
457
// given a fullname (e.g "/ObjectPool/_1020961869"), find the entry
 
458
libwpd::DirEntry* libwpd::DirTree::entry( const std::string& name )
 
459
{
 
460
 
 
461
   if( !name.length() ) return (libwpd::DirEntry*)0;
 
462
 
 
463
   // quick check for "/" (that's root)
 
464
   if( name == "/" ) return entry( 0 );
 
465
   
 
466
   // split the names, e.g  "/ObjectPool/_1020961869" will become:
 
467
   // "ObjectPool" and "_1020961869" 
 
468
   std::list<std::string> names;
 
469
   std::string::size_type start = 0, end = 0;
 
470
   if( name[0] == '/' ) start++;
 
471
   while( start < name.length() )
 
472
   {
 
473
     end = name.find_first_of( '/', start );
 
474
     if( end == std::string::npos ) end = name.length();
 
475
     names.push_back( name.substr( start, end-start ) );
 
476
     start = end+1;
 
477
   }
 
478
  
 
479
   // start from root 
 
480
   int index = 0 ;
 
481
 
 
482
   // trace one by one   
 
483
   std::list<std::string>::iterator it; 
 
484
 
 
485
   for( it = names.begin(); it != names.end(); ++it )
 
486
   {
 
487
     // find among the children of index
 
488
     std::vector<unsigned> chi = children( index );
 
489
     unsigned child = 0;
 
490
     for( unsigned i = 0; i < chi.size(); i++ )
 
491
     {
 
492
       libwpd::DirEntry* ce = entry( chi[i] );
 
493
       if( ce ) 
 
494
       if( ce->valid && ( ce->name.length()>1 ) )
 
495
       if( ce->name == *it )
 
496
             child = chi[i];
 
497
     }
 
498
     
 
499
     // traverse to the child
 
500
     if( child > 0 ) index = child;
 
501
     else return (libwpd::DirEntry*)0;
 
502
   }
 
503
 
 
504
   return entry( index );
 
505
}
 
506
 
 
507
// helper function: recursively find siblings of index
 
508
void dirtree_find_siblings( libwpd::DirTree* dirtree, std::vector<unsigned>& result, 
 
509
  unsigned index )
 
510
{
 
511
  libwpd::DirEntry* e = dirtree->entry( index );
 
512
  if( !e ) return;
 
513
  if( !e->valid ) return;
 
514
 
 
515
  // prevent infinite loop  
 
516
  for( unsigned i = 0; i < result.size(); i++ )
 
517
    if( result[i] == index ) return;
 
518
 
 
519
  // add myself    
 
520
  result.push_back( index );
 
521
  
 
522
  // visit previous sibling, don't go infinitely
 
523
  unsigned prev = e->prev;
 
524
  if( ( prev > 0 ) && ( prev < dirtree->entryCount() ) )
 
525
  {
 
526
    for( unsigned i = 0; i < result.size(); i++ )
 
527
      if( result[i] == prev ) prev = 0;
 
528
    if( prev ) dirtree_find_siblings( dirtree, result, prev );
 
529
  }
 
530
    
 
531
  // visit next sibling, don't go infinitely
 
532
  unsigned next = e->next;
 
533
  if( ( next > 0 ) && ( next < dirtree->entryCount() ) )
 
534
  {
 
535
    for( unsigned i = 0; i < result.size(); i++ )
 
536
      if( result[i] == next ) next = 0;
 
537
    if( next ) dirtree_find_siblings( dirtree, result, next );
 
538
  }
 
539
}
 
540
 
 
541
std::vector<unsigned> libwpd::DirTree::children( unsigned index )
 
542
{
 
543
  std::vector<unsigned> result;
 
544
  
 
545
  DirEntry* e = entry( index );
 
546
  if( e ) if( e->valid && e->child < entryCount() )
 
547
    dirtree_find_siblings( this, result, e->child );
 
548
    
 
549
  return result;
 
550
}
 
551
 
 
552
void libwpd::DirTree::load( unsigned char* buffer, unsigned size )
 
553
{
 
554
  entries.clear();
 
555
  
 
556
  for( unsigned i = 0; i < size/128; i++ )
 
557
  {
 
558
    unsigned p = i * 128;
 
559
    
 
560
    // would be < 32 if first char in the name isn't printable
 
561
    unsigned prefix = 32;
 
562
    
 
563
    // parse name of this entry, which stored as Unicode 16-bit
 
564
    std::string name;
 
565
    int name_len = readU16( buffer + 0x40+p );
 
566
    if( name_len > 64 ) name_len = 64;
 
567
    for( int j=0; ( buffer[j+p]) && (j<name_len); j+= 2 )
 
568
      name.append( 1, buffer[j+p] );
 
569
      
 
570
    // first char isn't printable ? remove it...
 
571
    if( buffer[p] < 32 )
 
572
    { 
 
573
      prefix = buffer[0]; 
 
574
      name.erase( 0,1 ); 
 
575
    }
 
576
    
 
577
    // 2 = file (aka stream), 1 = directory (aka storage), 5 = root
 
578
    unsigned type = buffer[ 0x42 + p];
 
579
    
 
580
    libwpd::DirEntry e;
 
581
    e.valid = true;
 
582
    e.name = name;
 
583
    e.start = readU32( buffer + 0x74+p );
 
584
    e.size = readU32( buffer + 0x78+p );
 
585
    e.prev = readU32( buffer + 0x44+p );
 
586
    e.next = readU32( buffer + 0x48+p );
 
587
    e.child = readU32( buffer + 0x4C+p );
 
588
    e.dir = ( type!=2 );
 
589
    
 
590
    // sanity checks
 
591
    if( (type != 2) && (type != 1 ) && (type != 5 ) ) e.valid = false;
 
592
    if( name_len < 1 ) e.valid = false;
 
593
    
 
594
    entries.push_back( e );
 
595
  }  
 
596
}
 
597
 
 
598
// =========== StorageIO ==========
 
599
 
 
600
libwpd::StorageIO::StorageIO( libwpd::Storage* st, const std::stringstream &memorystream ) :
 
601
        storage(st),
 
602
        buf( memorystream.str(), std::ios::binary | std::ios::in ),
 
603
        result(libwpd::Storage::Ok),
 
604
        bufsize(0),
 
605
        header(new libwpd::Header()),
 
606
        dirtree(new libwpd::DirTree()),
 
607
        bbat(new libwpd::AllocTable()),
 
608
        sbat(new libwpd::AllocTable()),
 
609
        sb_blocks(),
 
610
        streams()
 
611
{
 
612
  bbat->blockSize = 1 << header->b_shift;
 
613
  sbat->blockSize = 1 << header->s_shift;
 
614
}
 
615
 
 
616
libwpd::StorageIO::~StorageIO()
 
617
{
 
618
  delete sbat;
 
619
  delete bbat;
 
620
  delete dirtree;
 
621
  delete header;
 
622
 
 
623
  std::list<libwpd::Stream*>::iterator it;
 
624
  for( it = streams.begin(); it != streams.end(); ++it )
 
625
    delete *it;
 
626
}
 
627
 
 
628
bool libwpd::StorageIO::isOLEStream()
 
629
{
 
630
  load();
 
631
  return (result == libwpd::Storage::Ok);
 
632
}
 
633
 
 
634
void libwpd::StorageIO::load()
 
635
{
 
636
  unsigned char* buffer = 0;
 
637
  unsigned long buflen = 0;
 
638
  std::vector<unsigned long> blocks;
 
639
  
 
640
  // find size of input file
 
641
  buf.seekg( 0, std::ios::end );
 
642
  bufsize = buf.tellg();
 
643
 
 
644
  // load header
 
645
  buffer = new unsigned char[512];
 
646
  buf.seekg( 0 ); 
 
647
  buf.read( (char*)buffer, 512 );
 
648
  header->load( buffer );
 
649
  delete[] buffer;
 
650
 
 
651
  // check OLE magic id
 
652
  result = libwpd::Storage::NotOLE;
 
653
  for( unsigned i=0; i<8; i++ )
 
654
    if( header->id[i] != wpsole_magic[i] )
 
655
      return;
 
656
 
 
657
  // sanity checks
 
658
  result = libwpd::Storage::BadOLE;
 
659
  if( !header->valid() ) return;
 
660
  if( header->threshold != 4096 ) return;
 
661
 
 
662
  // important block size
 
663
  bbat->blockSize = 1 << header->b_shift;
 
664
  sbat->blockSize = 1 << header->s_shift;
 
665
  
 
666
  // find blocks allocated to store big bat
 
667
  // the first 109 blocks are in header, the rest in meta bat
 
668
  blocks.clear();
 
669
  blocks.resize( header->num_bat );
 
670
  for( unsigned j = 0; j < 109; j++ )
 
671
    if( j >= header->num_bat ) break;
 
672
    else blocks[j] = header->bb_blocks[j];
 
673
  if( (header->num_bat > 109) && (header->num_mbat > 0) )
 
674
  {
 
675
    unsigned char* buffer2 = new unsigned char[ bbat->blockSize ];
 
676
    unsigned k = 109;
 
677
    for( unsigned r = 0; r < header->num_mbat; r++ )
 
678
    {
 
679
      loadBigBlock( header->mbat_start+r, buffer2, bbat->blockSize );
 
680
      for( unsigned s=0; s < bbat->blockSize; s+=4 )
 
681
      {
 
682
        if( k >= header->num_bat ) break;
 
683
        else  blocks[k++] = readU32( buffer2 + s );
 
684
      }  
 
685
     }    
 
686
    delete[] buffer2;
 
687
  }
 
688
 
 
689
  // load big bat
 
690
  buflen = blocks.size()*bbat->blockSize;
 
691
  if( buflen > 0 )
 
692
  {
 
693
    buffer = new unsigned char[ buflen ];  
 
694
    loadBigBlocks( blocks, buffer, buflen );
 
695
    bbat->load( buffer, buflen );
 
696
    delete[] buffer;
 
697
  }  
 
698
 
 
699
  // load small bat
 
700
  blocks.clear();
 
701
  blocks = bbat->follow( header->sbat_start );
 
702
  buflen = blocks.size()*bbat->blockSize;
 
703
  if( buflen > 0 )
 
704
  {
 
705
    buffer = new unsigned char[ buflen ];  
 
706
    loadBigBlocks( blocks, buffer, buflen );
 
707
    sbat->load( buffer, buflen );
 
708
    delete[] buffer;
 
709
  }  
 
710
  
 
711
  // load directory tree
 
712
  blocks.clear();
 
713
  blocks = bbat->follow( header->dirent_start );
 
714
  buflen = blocks.size()*bbat->blockSize;
 
715
  buffer = new unsigned char[ buflen ];  
 
716
  loadBigBlocks( blocks, buffer, buflen );
 
717
  dirtree->load( buffer, buflen );
 
718
  unsigned sb_start = readU32( buffer + 0x74 );
 
719
  delete[] buffer;
 
720
  
 
721
  // fetch block chain as data for small-files
 
722
  sb_blocks = bbat->follow( sb_start ); // small files
 
723
  
 
724
  // so far so good
 
725
  result = libwpd::Storage::Ok;
 
726
}
 
727
 
 
728
libwpd::StreamIO* libwpd::StorageIO::streamIO( const std::string& name )
 
729
{
 
730
  load();
 
731
 
 
732
  // sanity check
 
733
  if( !name.length() ) return (libwpd::StreamIO*)0;
 
734
 
 
735
  // search in the entries
 
736
  libwpd::DirEntry* entry = dirtree->entry( name );
 
737
  if( !entry ) return (libwpd::StreamIO*)0;
 
738
  if( entry->dir ) return (libwpd::StreamIO*)0;
 
739
 
 
740
  libwpd::StreamIO* res = new libwpd::StreamIO( this, entry );
 
741
  res->fullName = name;
 
742
  
 
743
  return res;
 
744
}
 
745
 
 
746
unsigned long libwpd::StorageIO::loadBigBlocks( std::vector<unsigned long> blocks,
 
747
  unsigned char* data, unsigned long maxlen )
 
748
{
 
749
  // sentinel
 
750
  if( !data ) return 0;
 
751
  if( blocks.size() < 1 ) return 0;
 
752
  if( maxlen == 0 ) return 0;
 
753
 
 
754
  // read block one by one, seems fast enough
 
755
  unsigned long bytes = 0;
 
756
  for( unsigned long i=0; (i < blocks.size() ) & ( bytes<maxlen ); i++ )
 
757
  {
 
758
    unsigned long block = blocks[i];
 
759
    unsigned long pos =  bbat->blockSize * ( block+1 );
 
760
    unsigned long p = (bbat->blockSize < maxlen-bytes) ? bbat->blockSize : maxlen-bytes;
 
761
    if( pos + p > bufsize ) p = bufsize - pos;
 
762
    buf.seekg( pos );
 
763
    buf.read( (char*)data + bytes, p );
 
764
    bytes += p;
 
765
  }
 
766
 
 
767
  return bytes;
 
768
}
 
769
 
 
770
unsigned long libwpd::StorageIO::loadBigBlock( unsigned long block,
 
771
  unsigned char* data, unsigned long maxlen )
 
772
{
 
773
  // sentinel
 
774
  if( !data ) return 0;
 
775
 
 
776
  // wraps call for loadBigBlocks
 
777
  std::vector<unsigned long> blocks;
 
778
  blocks.resize( 1 );
 
779
  blocks[ 0 ] = block;
 
780
  
 
781
  return loadBigBlocks( blocks, data, maxlen );
 
782
}
 
783
 
 
784
// return number of bytes which has been read
 
785
unsigned long libwpd::StorageIO::loadSmallBlocks( std::vector<unsigned long> blocks,
 
786
  unsigned char* data, unsigned long maxlen )
 
787
{
 
788
  // sentinel
 
789
  if( !data ) return 0;
 
790
  if( blocks.size() < 1 ) return 0;
 
791
  if( maxlen == 0 ) return 0;
 
792
 
 
793
  // our own local buffer
 
794
  unsigned char* tmpBuf = new unsigned char[ bbat->blockSize ];
 
795
 
 
796
  // read small block one by one
 
797
  unsigned long bytes = 0;
 
798
  for( unsigned long i=0; ( i<blocks.size() ) & ( bytes<maxlen ); i++ )
 
799
  {
 
800
    unsigned long block = blocks[i];
 
801
 
 
802
    // find where the small-block exactly is
 
803
    unsigned long pos = block * sbat->blockSize;
 
804
    unsigned long bbindex = pos / bbat->blockSize;
 
805
    if( bbindex >= sb_blocks.size() ) break;
 
806
 
 
807
    loadBigBlock( sb_blocks[ bbindex ], tmpBuf, bbat->blockSize );
 
808
 
 
809
    // copy the data
 
810
    unsigned offset = pos % bbat->blockSize;
 
811
    unsigned long p = (maxlen-bytes < bbat->blockSize-offset ) ? maxlen-bytes :  bbat->blockSize-offset;
 
812
    p = (sbat->blockSize<p ) ? sbat->blockSize : p;
 
813
    memcpy( data + bytes, tmpBuf + offset, p );
 
814
    bytes += p;
 
815
  }
 
816
  
 
817
  delete[] tmpBuf;
 
818
 
 
819
  return bytes;
 
820
}
 
821
 
 
822
unsigned long libwpd::StorageIO::loadSmallBlock( unsigned long block,
 
823
  unsigned char* data, unsigned long maxlen )
 
824
{
 
825
  // sentinel
 
826
  if( !data ) return 0;
 
827
 
 
828
  // wraps call for loadSmallBlocks
 
829
  std::vector<unsigned long> blocks;
 
830
  blocks.resize( 1 );
 
831
  blocks.assign( 1, block );
 
832
 
 
833
  return loadSmallBlocks( blocks, data, maxlen );
 
834
}
 
835
 
 
836
// =========== StreamIO ==========
 
837
 
 
838
libwpd::StreamIO::StreamIO( libwpd::StorageIO* s, libwpd::DirEntry* e) :
 
839
        io(s),
 
840
        entry(e),
 
841
        fullName(),
 
842
        eof(false),
 
843
        fail(false),
 
844
        blocks(),
 
845
        m_pos(0),
 
846
        cache_data(0),
 
847
        cache_size(4096),
 
848
        cache_pos(0)
 
849
{
 
850
  if( entry->size >= io->header->threshold ) 
 
851
    blocks = io->bbat->follow( entry->start );
 
852
  else
 
853
    blocks = io->sbat->follow( entry->start );
 
854
 
 
855
  // prepare cache
 
856
  cache_data = new unsigned char[cache_size];
 
857
  updateCache();
 
858
}
 
859
 
 
860
// FIXME tell parent we're gone
 
861
libwpd::StreamIO::~StreamIO()
 
862
{
 
863
  delete[] cache_data;  
 
864
}
 
865
 
 
866
unsigned long libwpd::StreamIO::tell()
 
867
{
 
868
  return m_pos;
 
869
}
 
870
 
 
871
int libwpd::StreamIO::getch()
 
872
{
 
873
  // past end-of-file ?
 
874
  if( m_pos > entry->size ) return -1;
 
875
 
 
876
  // need to update cache ?
 
877
  if( !cache_size || ( m_pos < cache_pos ) ||
 
878
    ( m_pos >= cache_pos + cache_size ) )
 
879
      updateCache();
 
880
 
 
881
  // something bad if we don't get good cache
 
882
  if( !cache_size ) return -1;
 
883
 
 
884
  int data = cache_data[m_pos - cache_pos];
 
885
  m_pos++;
 
886
 
 
887
  return data;
 
888
}
 
889
 
 
890
unsigned long libwpd::StreamIO::read( unsigned long pos, unsigned char* data, unsigned long maxlen )
 
891
{
 
892
  // sanity checks
 
893
  if( !data ) return 0;
 
894
  if( maxlen == 0 ) return 0;
 
895
 
 
896
  unsigned long totalbytes = 0;
 
897
  
 
898
  if ( entry->size < io->header->threshold )
 
899
  {
 
900
    // small file
 
901
    unsigned long index = pos / io->sbat->blockSize;
 
902
 
 
903
    if( index >= blocks.size() ) return 0;
 
904
 
 
905
    unsigned char* buf = new unsigned char[ io->sbat->blockSize ];
 
906
    unsigned long offset = pos % io->sbat->blockSize;
 
907
    while( totalbytes < maxlen )
 
908
    {
 
909
      if( index >= blocks.size() ) break;
 
910
      io->loadSmallBlock( blocks[index], buf, io->bbat->blockSize );
 
911
      unsigned long count = io->sbat->blockSize - offset;
 
912
      if( count > maxlen-totalbytes ) count = maxlen-totalbytes;
 
913
      memcpy( data+totalbytes, buf + offset, count );
 
914
      totalbytes += count;
 
915
      offset = 0;
 
916
      index++;
 
917
    }
 
918
    delete[] buf;
 
919
 
 
920
  }
 
921
  else
 
922
  {
 
923
    // big file
 
924
    unsigned long index = pos / io->bbat->blockSize;
 
925
    
 
926
    if( index >= blocks.size() ) return 0;
 
927
    
 
928
    unsigned char* buf = new unsigned char[ io->bbat->blockSize ];
 
929
    unsigned long offset = pos % io->bbat->blockSize;
 
930
    while( totalbytes < maxlen )
 
931
    {
 
932
      if( index >= blocks.size() ) break;
 
933
      io->loadBigBlock( blocks[index], buf, io->bbat->blockSize );
 
934
      unsigned long count = io->bbat->blockSize - offset;
 
935
      if( count > maxlen-totalbytes ) count = maxlen-totalbytes;
 
936
      memcpy( data+totalbytes, buf + offset, count );
 
937
      totalbytes += count;
 
938
      index++;
 
939
      offset = 0;
 
940
    }
 
941
    delete [] buf;
 
942
 
 
943
  }
 
944
 
 
945
  return totalbytes;
 
946
}
 
947
 
 
948
unsigned long libwpd::StreamIO::read( unsigned char* data, unsigned long maxlen )
 
949
{
 
950
  unsigned long bytes = read( tell(), data, maxlen );
 
951
  m_pos += bytes;
 
952
  return bytes;
 
953
}
 
954
 
 
955
void libwpd::StreamIO::updateCache()
 
956
{
 
957
  // sanity check
 
958
  if( !cache_data ) return;
 
959
 
 
960
  cache_pos = m_pos - ( m_pos % cache_size );
 
961
  unsigned long bytes = cache_size;
 
962
  if( cache_pos + bytes > entry->size ) bytes = entry->size - cache_pos;
 
963
  cache_size = read( cache_pos, cache_data, bytes );
 
964
}
 
965
 
 
966
 
 
967
// =========== Storage ==========
 
968
 
 
969
libwpd::Storage::Storage( const std::stringstream &memorystream ) :
 
970
        io(NULL)
 
971
{
 
972
        io = new StorageIO( this, memorystream );
 
973
}
 
974
 
 
975
libwpd::Storage::~Storage()
 
976
{
 
977
  delete io;
 
978
}
 
979
 
 
980
int libwpd::Storage::result()
 
981
{
 
982
  return io->result;
 
983
}
 
984
 
 
985
bool libwpd::Storage::isOLEStream()
 
986
{
 
987
  return io->isOLEStream();
 
988
}
 
989
 
 
990
// =========== Stream ==========
 
991
 
 
992
libwpd::Stream::Stream( libwpd::Storage* storage, const std::string& name ) :
 
993
        io(storage->io->streamIO( name ))
 
994
{
 
995
}
 
996
 
 
997
// FIXME tell parent we're gone
 
998
libwpd::Stream::~Stream()
 
999
{
 
1000
  delete io;
 
1001
}
 
1002
 
 
1003
unsigned long libwpd::Stream::size()
 
1004
{
 
1005
  return io ? io->entry->size : 0;
 
1006
}
 
1007
 
 
1008
unsigned long libwpd::Stream::read( unsigned char* data, unsigned long maxlen )
 
1009
{
 
1010
  return io ? io->read( data, maxlen ) : 0;
 
1011
}