12
Redistribution and use in source and binary forms, with or without
13
modification, are permitted provided that the following conditions
13
Redistribution and use in source and binary forms, with or without
14
modification, are permitted provided that the following conditions
15
* Redistributions of source code must retain the above copyright notice,
16
* Redistributions of source code must retain the above copyright notice,
16
17
this list of conditions and the following disclaimer.
17
* Redistributions in binary form must reproduce the above copyright notice,
18
this list of conditions and the following disclaimer in the documentation
18
* Redistributions in binary form must reproduce the above copyright notice,
19
this list of conditions and the following disclaimer in the documentation
19
20
and/or other materials provided with the distribution.
20
* Neither the name of the authors nor the names of its contributors may be
21
used to endorse or promote products derived from this software without
21
* Neither the name of the authors nor the names of its contributors may be
22
used to endorse or promote products derived from this software without
22
23
specific prior written permission.
24
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
28
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
25
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
29
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
34
35
THE POSSIBILITY OF SUCH DAMAGE.
56
unsigned char id[8]; // signature, or magic identifier
57
unsigned b_shift; // bbat->blockSize = 1 << b_shift
58
unsigned s_shift; // sbat->blockSize = 1 << s_shift
59
unsigned num_bat; // blocks allocated for big bat
60
unsigned dirent_start; // starting block for directory info
61
unsigned threshold; // switch from small to big file (usually 4K)
62
unsigned sbat_start; // starting block index to store small bat
63
unsigned num_sbat; // blocks allocated for small bat
64
unsigned mbat_start; // starting block to store meta bat
65
unsigned num_mbat; // blocks allocated for meta bat
66
unsigned long bb_blocks[109];
70
void load( const unsigned char* buffer );
71
void save( unsigned char* buffer );
57
unsigned char id[8]; // signature, or magic identifier
58
unsigned b_shift; // bbat->blockSize = 1 << b_shift
59
unsigned s_shift; // sbat->blockSize = 1 << s_shift
60
unsigned num_bat; // blocks allocated for big bat
61
unsigned dirent_start; // starting block for directory info
62
unsigned threshold; // switch from small to big file (usually 4K)
63
unsigned sbat_start; // starting block index to store small bat
64
unsigned num_sbat; // blocks allocated for small bat
65
unsigned mbat_start; // starting block to store meta bat
66
unsigned num_mbat; // blocks allocated for meta bat
67
unsigned long bb_blocks[109];
71
void load( const unsigned char *buffer );
72
void save( unsigned char *buffer );
78
static const unsigned Eof;
79
static const unsigned Avail;
80
static const unsigned Bat;
81
static const unsigned MetaBat;
85
unsigned long count();
86
void resize( unsigned long newsize );
87
void preserve( unsigned long n );
88
void set( unsigned long index, unsigned long val );
90
void setChain( std::vector<unsigned long> );
91
std::vector<unsigned long> follow( unsigned long start );
92
unsigned long operator[](unsigned long index );
93
void load( const unsigned char* buffer, unsigned len );
94
void save( unsigned char* buffer );
96
std::vector<unsigned long> data;
97
AllocTable( const AllocTable& );
98
AllocTable& operator=( const AllocTable& );
79
static const unsigned Eof;
80
static const unsigned Avail;
81
static const unsigned Bat;
82
static const unsigned MetaBat;
86
unsigned long count();
87
void resize( unsigned long newsize );
88
void preserve( unsigned long n );
89
void set( unsigned long index, unsigned long val );
91
void setChain( std::vector<unsigned long> );
92
std::vector<unsigned long> follow( unsigned long start );
93
unsigned long operator[](unsigned long index );
94
void load( const unsigned char *buffer, unsigned len );
95
void save( unsigned char *buffer );
97
std::vector<unsigned long> data;
98
AllocTable( const AllocTable & );
99
AllocTable &operator=( const AllocTable & );
104
DirEntry() : valid(false), name(), dir(false), size(0), start(0),
105
prev(0), next(0), child(0) {};
106
bool valid; // false if invalid (should be skipped)
107
std::string name; // the name, not in unicode anymore
108
bool dir; // true if directory
109
unsigned long size; // size (not valid if directory)
110
unsigned long start; // starting block
111
unsigned prev; // previous sibling
112
unsigned next; // next sibling
113
unsigned child; // first child
105
DirEntry() : valid(false), name(), dir(false), size(0), start(0),
106
prev(0), next(0), child(0) {};
107
bool valid; // false if invalid (should be skipped)
108
std::string name; // the name, not in unicode anymore
109
bool dir; // true if directory
110
unsigned long size; // size (not valid if directory)
111
unsigned long start; // starting block
112
unsigned prev; // previous sibling
113
unsigned next; // next sibling
114
unsigned child; // first child
119
static const unsigned End;
122
unsigned entryCount();
123
DirEntry* entry( unsigned index );
124
DirEntry* entry( const std::string& name );
125
int parent( unsigned index );
126
std::string fullName( unsigned index );
127
std::vector<unsigned> children( unsigned index );
128
unsigned find_child( unsigned index, const std::string& name );
129
void load( unsigned char* buffer, unsigned len );
130
void save( unsigned char* buffer );
132
std::vector<DirEntry> entries;
133
DirTree( const DirTree& );
134
DirTree& operator=( const DirTree& );
120
static const unsigned End;
123
unsigned entryCount();
124
DirEntry *entry( unsigned index );
125
DirEntry *entry( const std::string &name );
126
int parent( unsigned index );
127
std::string fullName( unsigned index );
128
std::vector<unsigned> children( unsigned index );
129
unsigned find_child( unsigned index, const std::string &name );
130
void load( unsigned char *buffer, unsigned len );
131
void save( unsigned char *buffer );
133
std::vector<DirEntry> entries;
134
DirTree( const DirTree & );
135
DirTree &operator=( const DirTree & );
140
Storage* storage; // owner
141
std::stringstream buf;
142
int result; // result of operation
143
unsigned long bufsize; // size of the buffer
145
Header* header; // storage header
146
DirTree* dirtree; // directory tree
147
AllocTable* bbat; // allocation table for big blocks
148
AllocTable* sbat; // allocation table for small blocks
150
std::vector<unsigned long> sb_blocks; // blocks for "small" files
152
std::list<Stream*> streams;
154
StorageIO( Storage* storage, const std::stringstream &memorystream );
160
unsigned long loadBigBlocks( std::vector<unsigned long> blocks, unsigned char* buffer, unsigned long maxlen );
162
unsigned long loadBigBlock( unsigned long block, unsigned char* buffer, unsigned long maxlen );
164
unsigned long loadSmallBlocks( std::vector<unsigned long> blocks, unsigned char* buffer, unsigned long maxlen );
166
unsigned long loadSmallBlock( unsigned long block, unsigned char* buffer, unsigned long maxlen );
168
StreamIO* streamIO( const std::string& name );
172
StorageIO( const StorageIO& );
173
StorageIO& operator=( const StorageIO& );
141
Storage *storage; // owner
142
std::stringstream buf;
143
int result; // result of operation
144
unsigned long bufsize; // size of the buffer
146
Header *header; // storage header
147
DirTree *dirtree; // directory tree
148
AllocTable *bbat; // allocation table for big blocks
149
AllocTable *sbat; // allocation table for small blocks
151
std::vector<unsigned long> sb_blocks; // blocks for "small" files
153
std::list<Stream *> streams;
155
StorageIO( Storage *storage, const std::stringstream &memorystream );
161
unsigned long loadBigBlocks( std::vector<unsigned long> blocks, unsigned char *buffer, unsigned long maxlen );
163
unsigned long loadBigBlock( unsigned long block, unsigned char *buffer, unsigned long maxlen );
165
unsigned long loadSmallBlocks( std::vector<unsigned long> blocks, unsigned char *buffer, unsigned long maxlen );
167
unsigned long loadSmallBlock( unsigned long block, unsigned char *buffer, unsigned long maxlen );
169
StreamIO *streamIO( const std::string &name );
173
StorageIO( const StorageIO & );
174
StorageIO &operator=( const StorageIO & );
182
std::string fullName;
186
StreamIO( StorageIO* io, DirEntry* entry );
188
unsigned long size();
189
unsigned long tell();
191
unsigned long read( unsigned char* data, unsigned long maxlen );
192
unsigned long read( unsigned long pos, unsigned char* data, unsigned long maxlen );
196
std::vector<unsigned long> blocks;
199
StreamIO( const StreamIO& );
200
StreamIO& operator=( const StreamIO& );
205
// simple cache system to speed-up getch()
206
unsigned char* cache_data;
207
unsigned long cache_size;
208
unsigned long cache_pos;
183
std::string fullName;
187
StreamIO( StorageIO *io, DirEntry *entry );
189
unsigned long size();
190
unsigned long tell();
192
unsigned long read( unsigned char *data, unsigned long maxlen );
193
unsigned long read( unsigned long pos, unsigned char *data, unsigned long maxlen );
197
std::vector<unsigned long> blocks;
200
StreamIO( const StreamIO & );
201
StreamIO &operator=( const StreamIO & );
206
// simple cache system to speed-up getch()
207
unsigned char *cache_data;
208
unsigned long cache_size;
209
unsigned long cache_pos;
212
213
} // namespace libwpd
214
static inline unsigned long readU16( const unsigned char* ptr )
215
static inline unsigned long readU16( const unsigned char *ptr )
216
return ptr[0]+(ptr[1]<<8);
217
return ptr[0]+(ptr[1]<<8);
219
static inline unsigned long readU32( const unsigned char* ptr )
220
static inline unsigned long readU32( const unsigned char *ptr )
221
return ptr[0]+(ptr[1]<<8)+(ptr[2]<<16)+(ptr[3]<<24);
222
return ptr[0]+(ptr[1]<<8)+(ptr[2]<<16)+(ptr[3]<<24);
224
225
static const unsigned char wpsole_magic[] =
225
{ 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1 };
226
{ 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1 };
228
229
// =========== Header ==========
241
for( unsigned i = 0; i < 8; i++ )
242
id[i] = wpsole_magic[i];
243
for( unsigned j=0; j<109; j++ )
244
bb_blocks[j] = libwpd::AllocTable::Avail;
242
for( unsigned i = 0; i < 8; i++ )
243
id[i] = wpsole_magic[i];
244
for( unsigned j=0; j<109; j++ )
245
bb_blocks[j] = libwpd::AllocTable::Avail;
247
248
bool libwpd::Header::valid()
249
if( threshold != 4096 ) return false;
250
if( num_bat == 0 ) return false;
251
if( (num_bat > 109) && (num_bat > (num_mbat * 127) + 109)) return false;
252
if( (num_bat < 109) && (num_mbat != 0) ) return false;
253
if( s_shift > b_shift ) return false;
254
if( b_shift <= 6 ) return false;
255
if( b_shift >=31 ) return false;
250
if( threshold != 4096 ) return false;
251
if( num_bat == 0 ) return false;
252
if( (num_bat > 109) && (num_bat > (num_mbat * 127) + 109)) return false;
253
if( (num_bat < 109) && (num_mbat != 0) ) return false;
254
if( s_shift > b_shift ) return false;
255
if( b_shift <= 6 ) return false;
256
if( b_shift >=31 ) return false;
260
void libwpd::Header::load( const unsigned char* buffer )
261
void libwpd::Header::load( const unsigned char *buffer )
262
b_shift = readU16( buffer + 0x1e );
263
s_shift = readU16( buffer + 0x20 );
264
num_bat = readU32( buffer + 0x2c );
265
dirent_start = readU32( buffer + 0x30 );
266
threshold = readU32( buffer + 0x38 );
267
sbat_start = readU32( buffer + 0x3c );
268
num_sbat = readU32( buffer + 0x40 );
269
mbat_start = readU32( buffer + 0x44 );
270
num_mbat = readU32( buffer + 0x48 );
263
b_shift = readU16( buffer + 0x1e );
264
s_shift = readU16( buffer + 0x20 );
265
num_bat = readU32( buffer + 0x2c );
266
dirent_start = readU32( buffer + 0x30 );
267
threshold = readU32( buffer + 0x38 );
268
sbat_start = readU32( buffer + 0x3c );
269
num_sbat = readU32( buffer + 0x40 );
270
mbat_start = readU32( buffer + 0x44 );
271
num_mbat = readU32( buffer + 0x48 );
272
for( unsigned i = 0; i < 8; i++ )
274
for( unsigned j=0; j<109; j++ )
275
bb_blocks[j] = readU32( buffer + 0x4C+j*4 );
273
for( unsigned i = 0; i < 8; i++ )
275
for( unsigned j=0; j<109; j++ )
276
bb_blocks[j] = readU32( buffer + 0x4C+j*4 );
280
281
// =========== AllocTable ==========
282
283
const unsigned libwpd::AllocTable::Avail = 0xffffffff;
295
296
unsigned long libwpd::AllocTable::count()
300
301
void libwpd::AllocTable::resize( unsigned long newsize )
302
unsigned oldsize = data.size();
303
data.resize( newsize );
304
if( newsize > oldsize )
305
for( unsigned i = oldsize; i<newsize; i++ )
303
unsigned oldsize = data.size();
304
data.resize( newsize );
305
if( newsize > oldsize )
306
for( unsigned i = oldsize; i<newsize; i++ )
309
310
// make sure there're still free blocks
310
311
void libwpd::AllocTable::preserve( unsigned long n )
312
std::vector<unsigned long> pre;
313
for( unsigned i=0; i < n; i++ )
314
pre.push_back( unused() );
313
std::vector<unsigned long> pre;
314
for( unsigned i=0; i < n; i++ )
315
pre.push_back( unused() );
317
318
unsigned long libwpd::AllocTable::operator[]( unsigned long index )
319
unsigned long result;
320
result = data[index];
320
unsigned long result;
321
result = data[index];
324
325
void libwpd::AllocTable::set( unsigned long index, unsigned long value )
326
if( index >= count() ) resize( index + 1);
327
data[ index ] = value;
327
if( index >= count() ) resize( index + 1);
328
data[ index ] = value;
330
331
void libwpd::AllocTable::setChain( std::vector<unsigned long> chain )
334
for( unsigned i=0; i<chain.size()-1; i++ )
335
set( chain[i], chain[i+1] );
336
set( chain[ chain.size()-1 ], AllocTable::Eof );
335
for( unsigned i=0; i<chain.size()-1; i++ )
336
set( chain[i], chain[i+1] );
337
set( chain[ chain.size()-1 ], AllocTable::Eof );
340
341
// TODO: optimize this with better search
341
342
static bool already_exist(const std::vector<unsigned long>& chain,
342
343
unsigned long item)
344
for(unsigned i = 0; i < chain.size(); i++)
345
if(chain[i] == item) return true;
345
for(unsigned i = 0; i < chain.size(); i++)
346
if(chain[i] == item) return true;
351
352
std::vector<unsigned long> libwpd::AllocTable::follow( unsigned long start )
353
std::vector<unsigned long> chain;
355
if( start >= count() ) return chain;
357
unsigned long p = start;
360
if( p == (unsigned long)Eof ) break;
361
if( p == (unsigned long)Bat ) break;
362
if( p == (unsigned long)MetaBat ) break;
363
if( already_exist(chain, p) ) break;
364
chain.push_back( p );
365
if( data[p] >= count() ) break;
354
std::vector<unsigned long> chain;
356
if( start >= count() ) return chain;
358
unsigned long p = start;
361
if( p == (unsigned long)Eof ) break;
362
if( p == (unsigned long)Bat ) break;
363
if( p == (unsigned long)MetaBat ) break;
364
if( already_exist(chain, p) ) break;
365
chain.push_back( p );
366
if( data[p] >= count() ) break;
372
373
unsigned libwpd::AllocTable::unused()
374
// find first available block
375
for( unsigned i = 0; i < data.size(); i++ )
376
if( data[i] == Avail )
379
// completely full, so enlarge the table
380
unsigned block = data.size();
381
resize( data.size()+10 );
375
// find first available block
376
for( unsigned i = 0; i < data.size(); i++ )
377
if( data[i] == Avail )
380
// completely full, so enlarge the table
381
unsigned block = data.size();
382
resize( data.size()+10 );
385
void libwpd::AllocTable::load( const unsigned char* buffer, unsigned len )
386
void libwpd::AllocTable::load( const unsigned char *buffer, unsigned len )
388
for( unsigned i = 0; i < count(); i++ )
389
set( i, readU32( buffer + i*4 ) );
389
for( unsigned i = 0; i < count(); i++ )
390
set( i, readU32( buffer + i*4 ) );
392
393
// =========== DirTree ==========
396
397
libwpd::DirTree::DirTree() :
402
403
void libwpd::DirTree::clear()
404
// leave only root entry
406
entries[0].valid = true;
407
entries[0].name = "Root Entry";
408
entries[0].dir = true;
410
entries[0].start = End;
411
entries[0].prev = End;
412
entries[0].next = End;
413
entries[0].child = End;
405
// leave only root entry
407
entries[0].valid = true;
408
entries[0].name = "Root Entry";
409
entries[0].dir = true;
411
entries[0].start = End;
412
entries[0].prev = End;
413
entries[0].next = End;
414
entries[0].child = End;
416
417
unsigned libwpd::DirTree::entryCount()
418
return entries.size();
419
return entries.size();
421
libwpd::DirEntry* libwpd::DirTree::entry( unsigned index )
422
libwpd::DirEntry *libwpd::DirTree::entry( unsigned index )
423
if( index >= entryCount() ) return (libwpd::DirEntry*) 0;
424
return &entries[ index ];
424
if( index >= entryCount() ) return (libwpd::DirEntry *) 0;
425
return &entries[ index ];
427
428
int libwpd::DirTree::parent( unsigned index )
429
// brute-force, basically we iterate for each entries, find its children
430
// and check if one of the children is 'index'
431
for( unsigned j=0; j<entryCount(); j++ )
433
std::vector<unsigned> chi = children( j );
434
for( unsigned i=0; i<chi.size();i++ )
435
if( chi[i] == index )
430
// brute-force, basically we iterate for each entries, find its children
431
// and check if one of the children is 'index'
432
for( unsigned j=0; j<entryCount(); j++ )
434
std::vector<unsigned> chi = children( j );
435
for( unsigned i=0; i<chi.size(); i++ )
436
if( chi[i] == index )
442
443
std::string libwpd::DirTree::fullName( unsigned index )
444
// don't use root name ("Root Entry"), just give "/"
445
if( index == 0 ) return "/";
447
std::string result = entry( index )->name;
448
result.insert( 0, "/" );
449
int p = parent( index );
450
DirEntry * _entry = 0;
452
std::vector<int> seens;
458
if (_entry->dir && _entry->valid)
460
result.insert( 0, _entry->name);
461
result.insert( 0, "/" );
469
for (int i = 0; i < int(seens.size()); i++) {
470
if (seens[i] == p) { ok = false; break; }
445
// don't use root name ("Root Entry"), just give "/"
446
if( index == 0 ) return "/";
448
std::string result = entry( index )->name;
449
result.insert( 0, "/" );
450
int p = parent( index );
451
DirEntry *_entry = 0;
453
std::vector<int> seens;
459
if (_entry->dir && _entry->valid)
461
result.insert( 0, _entry->name);
462
result.insert( 0, "/" );
470
for (int i = 0; i < int(seens.size()); i++)
478
484
// given a fullname (e.g "/ObjectPool/_1020961869"), find the entry
479
libwpd::DirEntry* libwpd::DirTree::entry( const std::string& name )
485
libwpd::DirEntry *libwpd::DirTree::entry( const std::string &name )
482
if( !name.length() ) return (libwpd::DirEntry*)0;
484
// quick check for "/" (that's root)
485
if( name == "/" ) return entry( 0 );
487
// split the names, e.g "/ObjectPool/_1020961869" will become:
488
// "ObjectPool" and "_1020961869"
489
std::list<std::string> names;
490
std::string::size_type start = 0, end = 0;
491
if( name[0] == '/' ) start++;
492
while( start < name.length() )
494
end = name.find_first_of( '/', start );
495
if( end == std::string::npos ) end = name.length();
496
names.push_back( name.substr( start, end-start ) );
504
std::list<std::string>::iterator it;
506
for( it = names.begin(); it != names.end(); ++it )
509
// dima: performace optimisation of the previous
510
child = find_child( index, *it );
511
// traverse to the child
512
if( child > 0 ) index = child;
513
else return (libwpd::DirEntry*)0;
516
return entry( index );
488
if( !name.length() ) return (libwpd::DirEntry *)0;
490
// quick check for "/" (that's root)
491
if( name == "/" ) return entry( 0 );
493
// split the names, e.g "/ObjectPool/_1020961869" will become:
494
// "ObjectPool" and "_1020961869"
495
std::list<std::string> names;
496
std::string::size_type start = 0, end = 0;
497
if( name[0] == '/' ) start++;
498
while( start < name.length() )
500
end = name.find_first_of( '/', start );
501
if( end == std::string::npos ) end = name.length();
502
names.push_back( name.substr( start, end-start ) );
510
std::list<std::string>::iterator it;
512
for( it = names.begin(); it != names.end(); ++it )
515
// dima: performace optimisation of the previous
516
child = find_child( index, *it );
517
// traverse to the child
518
if( child > 0 ) index = child;
519
else return (libwpd::DirEntry *)0;
522
return entry( index );
519
525
// helper function: recursively find siblings of index
520
static void dirtree_find_siblings( libwpd::DirTree* dirtree, std::vector<unsigned>& result,
523
libwpd::DirEntry* e = dirtree->entry( index );
525
if( !e->valid ) return;
527
// prevent infinite loop
528
for( unsigned i = 0; i < result.size(); i++ )
529
if( result[i] == index ) return;
532
result.push_back( index );
534
// visit previous sibling, don't go infinitely
535
unsigned prev = e->prev;
536
if( ( prev > 0 ) && ( prev < dirtree->entryCount() ) )
538
for( unsigned i = 0; i < result.size(); i++ )
539
if( result[i] == prev ) prev = 0;
540
if( prev ) dirtree_find_siblings( dirtree, result, prev );
543
// visit next sibling, don't go infinitely
544
unsigned next = e->next;
545
if( ( next > 0 ) && ( next < dirtree->entryCount() ) )
547
for( unsigned i = 0; i < result.size(); i++ )
548
if( result[i] == next ) next = 0;
549
if( next ) dirtree_find_siblings( dirtree, result, next );
553
static unsigned dirtree_find_sibling( libwpd::DirTree* dirtree, unsigned index, const std::string& name ) {
555
unsigned count = dirtree->entryCount();
556
libwpd::DirEntry* e = dirtree->entry( index );
557
if (!e || !e->valid) return 0;
558
if (e->name == name) return index;
560
if (e->next>0 && e->next<count) {
561
unsigned r = dirtree_find_sibling( dirtree, e->next, name );
565
if (e->prev>0 && e->prev<count) {
566
unsigned r = dirtree_find_sibling( dirtree, e->prev, name );
573
unsigned libwpd::DirTree::find_child( unsigned index, const std::string& name ) {
575
unsigned count = entryCount();
576
libwpd::DirEntry* p = entry( index );
577
if (p && p->valid && p->child < count )
578
return dirtree_find_sibling( this, p->child, name );
526
static void dirtree_find_siblings( libwpd::DirTree *dirtree, std::vector<unsigned>& result,
529
libwpd::DirEntry *e = dirtree->entry( index );
531
if( !e->valid ) return;
533
// prevent infinite loop
534
for( unsigned i = 0; i < result.size(); i++ )
535
if( result[i] == index ) return;
538
result.push_back( index );
540
// visit previous sibling, don't go infinitely
541
unsigned prev = e->prev;
542
if( ( prev > 0 ) && ( prev < dirtree->entryCount() ) )
544
for( unsigned i = 0; i < result.size(); i++ )
545
if( result[i] == prev ) prev = 0;
546
if( prev ) dirtree_find_siblings( dirtree, result, prev );
549
// visit next sibling, don't go infinitely
550
unsigned next = e->next;
551
if( ( next > 0 ) && ( next < dirtree->entryCount() ) )
553
for( unsigned i = 0; i < result.size(); i++ )
554
if( result[i] == next ) next = 0;
555
if( next ) dirtree_find_siblings( dirtree, result, next );
559
static unsigned dirtree_find_sibling( libwpd::DirTree *dirtree, unsigned index, const std::string &name )
562
unsigned count = dirtree->entryCount();
563
libwpd::DirEntry *e = dirtree->entry( index );
564
if (!e || !e->valid) return 0;
565
if (e->name == name) return index;
567
if (e->next>0 && e->next<count)
569
unsigned r = dirtree_find_sibling( dirtree, e->next, name );
573
if (e->prev>0 && e->prev<count)
575
unsigned r = dirtree_find_sibling( dirtree, e->prev, name );
582
unsigned libwpd::DirTree::find_child( unsigned index, const std::string &name )
585
unsigned count = entryCount();
586
libwpd::DirEntry *p = entry( index );
587
if (p && p->valid && p->child < count )
588
return dirtree_find_sibling( this, p->child, name );
583
593
std::vector<unsigned> libwpd::DirTree::children( unsigned index )
585
std::vector<unsigned> result;
587
DirEntry* e = entry( index );
588
if( e ) if( e->valid && e->child < entryCount() )
589
dirtree_find_siblings( this, result, e->child );
595
std::vector<unsigned> result;
597
DirEntry *e = entry( index );
598
if( e ) if( e->valid && e->child < entryCount() )
599
dirtree_find_siblings( this, result, e->child );
594
void libwpd::DirTree::load( unsigned char* buffer, unsigned size )
604
void libwpd::DirTree::load( unsigned char *buffer, unsigned size )
598
for( unsigned i = 0; i < size/128; i++ )
600
unsigned p = i * 128;
602
// parse name of this entry, which stored as Unicode 16-bit
604
int name_len = readU16( buffer + 0x40+p );
605
if( name_len > 64 ) name_len = 64;
606
for( int j=0; ( buffer[j+p]) && (j<name_len); j+= 2 )
607
name.append( 1, buffer[j+p] );
609
// would be < 32 if first char in the name isn't printable
610
// first char isn't printable ? remove it...
614
// 2 = file (aka stream), 1 = directory (aka storage), 5 = root
615
unsigned type = buffer[ 0x42 + p];
620
e.start = readU32( buffer + 0x74+p );
621
e.size = readU32( buffer + 0x78+p );
622
e.prev = readU32( buffer + 0x44+p );
623
e.next = readU32( buffer + 0x48+p );
624
e.child = readU32( buffer + 0x4C+p );
628
if( (type != 2) && (type != 1 ) && (type != 5 ) ) e.valid = false;
629
if( name_len < 1 ) e.valid = false;
631
entries.push_back( e );
608
for( unsigned i = 0; i < size/128; i++ )
610
unsigned p = i * 128;
612
// parse name of this entry, which stored as Unicode 16-bit
614
int name_len = readU16( buffer + 0x40+p );
615
if( name_len > 64 ) name_len = 64;
616
for( int j=0; ( buffer[j+p]) && (j<name_len); j+= 2 )
617
name.append( 1, buffer[j+p] );
619
// would be < 32 if first char in the name isn't printable
620
// first char isn't printable ? remove it...
624
// 2 = file (aka stream), 1 = directory (aka storage), 5 = root
625
unsigned type = buffer[ 0x42 + p];
630
e.start = readU32( buffer + 0x74+p );
631
e.size = readU32( buffer + 0x78+p );
632
e.prev = readU32( buffer + 0x44+p );
633
e.next = readU32( buffer + 0x48+p );
634
e.child = readU32( buffer + 0x4C+p );
638
if( (type != 2) && (type != 1 ) && (type != 5 ) ) e.valid = false;
639
if( name_len < 1 ) e.valid = false;
641
entries.push_back( e );
635
645
// =========== StorageIO ==========
637
libwpd::StorageIO::StorageIO( libwpd::Storage* st, const std::stringstream &memorystream ) :
647
libwpd::StorageIO::StorageIO( libwpd::Storage *st, const std::stringstream &memorystream ) :
639
649
buf( memorystream.str(), std::ios::binary | std::ios::in ),
640
650
result(libwpd::Storage::Ok),
649
bbat->blockSize = 1 << header->b_shift;
650
sbat->blockSize = 1 << header->s_shift;
659
bbat->blockSize = 1 << header->b_shift;
660
sbat->blockSize = 1 << header->s_shift;
653
663
libwpd::StorageIO::~StorageIO()
660
std::list<libwpd::Stream*>::iterator it;
661
for( it = streams.begin(); it != streams.end(); ++it )
670
std::list<libwpd::Stream *>::iterator it;
671
for( it = streams.begin(); it != streams.end(); ++it )
665
675
bool libwpd::StorageIO::isOLEStream()
668
return (result == libwpd::Storage::Ok);
678
return (result == libwpd::Storage::Ok);
671
681
void libwpd::StorageIO::load()
673
unsigned char* buffer = 0;
674
unsigned long buflen = 0;
675
std::vector<unsigned long> blocks;
677
// find size of input file
678
buf.seekg( 0, std::ios::end );
679
bufsize = buf.tellg();
682
buffer = new unsigned char[512];
684
buf.read( (char*)buffer, 512 );
685
header->load( buffer );
688
// check OLE magic id
689
result = libwpd::Storage::NotOLE;
690
for( unsigned i=0; i<8; i++ )
691
if( header->id[i] != wpsole_magic[i] )
695
result = libwpd::Storage::BadOLE;
696
if( !header->valid() ) return;
697
if( header->threshold != 4096 ) return;
699
// important block size
700
bbat->blockSize = 1 << header->b_shift;
701
sbat->blockSize = 1 << header->s_shift;
703
// find blocks allocated to store big bat
704
// the first 109 blocks are in header, the rest in meta bat
706
blocks.resize( header->num_bat );
707
for( unsigned j = 0; j < 109; j++ )
708
if( j >= header->num_bat ) break;
709
else blocks[j] = header->bb_blocks[j];
710
if( (header->num_bat > 109) && (header->num_mbat > 0) )
712
unsigned char* buffer2 = new unsigned char[ bbat->blockSize ];
715
for( unsigned r = 0; r < header->num_mbat; r++ )
717
if(r == 0) // 1st meta bat location is in file header.
718
sector = header->mbat_start;
719
else // next meta bat location is the last current block value.
720
sector = blocks[--k];
721
loadBigBlock( sector, buffer2, bbat->blockSize );
722
for( unsigned s=0; s < bbat->blockSize; s+=4 )
724
if( k >= header->num_bat ) break;
725
else blocks[k++] = readU32( buffer2 + s );
728
loadBigBlock( header->mbat_start+r, buffer2, bbat->blockSize );
729
for( unsigned s=0; s < bbat->blockSize; s+=4 )
731
if( k >= header->num_bat ) break;
732
else blocks[k++] = readU32( buffer2 + s );
740
buflen = blocks.size()*bbat->blockSize;
743
buffer = new unsigned char[ buflen ];
744
loadBigBlocks( blocks, buffer, buflen );
745
bbat->load( buffer, buflen );
751
blocks = bbat->follow( header->sbat_start );
752
buflen = blocks.size()*bbat->blockSize;
755
buffer = new unsigned char[ buflen ];
756
loadBigBlocks( blocks, buffer, buflen );
757
sbat->load( buffer, buflen );
761
// load directory tree
763
blocks = bbat->follow( header->dirent_start );
764
buflen = blocks.size()*bbat->blockSize;
765
buffer = new unsigned char[ buflen ];
766
loadBigBlocks( blocks, buffer, buflen );
767
dirtree->load( buffer, buflen );
768
unsigned sb_start = readU32( buffer + 0x74 );
771
// fetch block chain as data for small-files
772
sb_blocks = bbat->follow( sb_start ); // small files
775
result = libwpd::Storage::Ok;
683
unsigned char *buffer = 0;
684
unsigned long buflen = 0;
685
std::vector<unsigned long> blocks;
687
// find size of input file
688
buf.seekg( 0, std::ios::end );
689
bufsize = buf.tellg();
692
buffer = new unsigned char[512];
694
buf.read( (char *)buffer, 512 );
695
header->load( buffer );
698
// check OLE magic id
699
result = libwpd::Storage::NotOLE;
700
for( unsigned i=0; i<8; i++ )
701
if( header->id[i] != wpsole_magic[i] )
705
result = libwpd::Storage::BadOLE;
706
if( !header->valid() ) return;
707
if( header->threshold != 4096 ) return;
709
// important block size
710
bbat->blockSize = 1 << header->b_shift;
711
sbat->blockSize = 1 << header->s_shift;
713
// find blocks allocated to store big bat
714
// the first 109 blocks are in header, the rest in meta bat
716
blocks.resize( header->num_bat );
717
for( unsigned j = 0; j < 109; j++ )
718
if( j >= header->num_bat ) break;
719
else blocks[j] = header->bb_blocks[j];
720
if( (header->num_bat > 109) && (header->num_mbat > 0) )
722
unsigned char *buffer2 = new unsigned char[ bbat->blockSize ];
725
for( unsigned r = 0; r < header->num_mbat; r++ )
727
if(r == 0) // 1st meta bat location is in file header.
728
sector = header->mbat_start;
729
else // next meta bat location is the last current block value.
730
sector = blocks[--k];
731
loadBigBlock( sector, buffer2, bbat->blockSize );
732
for( unsigned s=0; s < bbat->blockSize; s+=4 )
734
if( k >= header->num_bat ) break;
735
else blocks[k++] = readU32( buffer2 + s );
738
loadBigBlock( header->mbat_start+r, buffer2, bbat->blockSize );
739
for( unsigned s=0; s < bbat->blockSize; s+=4 )
741
if( k >= header->num_bat ) break;
742
else blocks[k++] = readU32( buffer2 + s );
750
buflen = blocks.size()*bbat->blockSize;
753
buffer = new unsigned char[ buflen ];
754
loadBigBlocks( blocks, buffer, buflen );
755
bbat->load( buffer, buflen );
761
blocks = bbat->follow( header->sbat_start );
762
buflen = blocks.size()*bbat->blockSize;
765
buffer = new unsigned char[ buflen ];
766
loadBigBlocks( blocks, buffer, buflen );
767
sbat->load( buffer, buflen );
771
// load directory tree
773
blocks = bbat->follow( header->dirent_start );
774
buflen = blocks.size()*bbat->blockSize;
775
buffer = new unsigned char[ buflen ];
776
loadBigBlocks( blocks, buffer, buflen );
777
dirtree->load( buffer, buflen );
778
unsigned sb_start = readU32( buffer + 0x74 );
781
// fetch block chain as data for small-files
782
sb_blocks = bbat->follow( sb_start ); // small files
785
result = libwpd::Storage::Ok;
778
libwpd::StreamIO* libwpd::StorageIO::streamIO( const std::string& name )
788
libwpd::StreamIO *libwpd::StorageIO::streamIO( const std::string &name )
783
if( !name.length() ) return (libwpd::StreamIO*)0;
785
// search in the entries
786
libwpd::DirEntry* entry = dirtree->entry( name );
787
if( !entry ) return (libwpd::StreamIO*)0;
788
if( entry->dir ) return (libwpd::StreamIO*)0;
790
libwpd::StreamIO* res = new libwpd::StreamIO( this, entry );
791
res->fullName = name;
793
if( !name.length() ) return (libwpd::StreamIO *)0;
795
// search in the entries
796
libwpd::DirEntry *entry = dirtree->entry( name );
797
if( !entry ) return (libwpd::StreamIO *)0;
798
if( entry->dir ) return (libwpd::StreamIO *)0;
800
libwpd::StreamIO *res = new libwpd::StreamIO( this, entry );
801
res->fullName = name;
796
806
unsigned long libwpd::StorageIO::loadBigBlocks( std::vector<unsigned long> blocks,
797
unsigned char* data, unsigned long maxlen )
807
unsigned char *data, unsigned long maxlen )
800
if( !data ) return 0;
801
if( blocks.size() < 1 ) return 0;
802
if( maxlen == 0 ) return 0;
804
// read block one by one, seems fast enough
805
unsigned long bytes = 0;
806
for( unsigned long i=0; (i < blocks.size() ) & ( bytes<maxlen ); i++ )
808
unsigned long block = blocks[i];
809
unsigned long pos = bbat->blockSize * ( block+1 );
810
unsigned long p = (bbat->blockSize < maxlen-bytes) ? bbat->blockSize : maxlen-bytes;
811
if( pos + p > bufsize ) p = bufsize - pos;
813
buf.read( (char*)data + bytes, p );
810
if( !data ) return 0;
811
if( blocks.size() < 1 ) return 0;
812
if( maxlen == 0 ) return 0;
814
// read block one by one, seems fast enough
815
unsigned long bytes = 0;
816
for( unsigned long i=0; (i < blocks.size() ) & ( bytes<maxlen ); i++ )
818
unsigned long block = blocks[i];
819
unsigned long pos = bbat->blockSize * ( block+1 );
820
unsigned long p = (bbat->blockSize < maxlen-bytes) ? bbat->blockSize : maxlen-bytes;
821
if( pos + p > bufsize ) p = bufsize - pos;
823
buf.read( (char *)data + bytes, p );
820
830
unsigned long libwpd::StorageIO::loadBigBlock( unsigned long block,
821
unsigned char* data, unsigned long maxlen )
831
unsigned char *data, unsigned long maxlen )
824
if( !data ) return 0;
826
// wraps call for loadBigBlocks
827
std::vector<unsigned long> blocks;
831
return loadBigBlocks( blocks, data, maxlen );
834
if( !data ) return 0;
836
// wraps call for loadBigBlocks
837
std::vector<unsigned long> blocks;
841
return loadBigBlocks( blocks, data, maxlen );
834
844
// return number of bytes which has been read
835
845
unsigned long libwpd::StorageIO::loadSmallBlocks( std::vector<unsigned long> blocks,
836
unsigned char* data, unsigned long maxlen )
846
unsigned char *data, unsigned long maxlen )
839
if( !data ) return 0;
840
if( blocks.size() < 1 ) return 0;
841
if( maxlen == 0 ) return 0;
843
// our own local buffer
844
unsigned char* tmpBuf = new unsigned char[ bbat->blockSize ];
846
// read small block one by one
847
unsigned long bytes = 0;
848
for( unsigned long i=0; ( i<blocks.size() ) & ( bytes<maxlen ); i++ )
850
unsigned long block = blocks[i];
852
// find where the small-block exactly is
853
unsigned long pos = block * sbat->blockSize;
854
unsigned long bbindex = pos / bbat->blockSize;
855
if( bbindex >= sb_blocks.size() ) break;
857
loadBigBlock( sb_blocks[ bbindex ], tmpBuf, bbat->blockSize );
860
unsigned offset = pos % bbat->blockSize;
861
unsigned long p = (maxlen-bytes < bbat->blockSize-offset ) ? maxlen-bytes : bbat->blockSize-offset;
862
p = (sbat->blockSize<p ) ? sbat->blockSize : p;
863
memcpy( data + bytes, tmpBuf + offset, p );
849
if( !data ) return 0;
850
if( blocks.size() < 1 ) return 0;
851
if( maxlen == 0 ) return 0;
853
// our own local buffer
854
unsigned char *tmpBuf = new unsigned char[ bbat->blockSize ];
856
// read small block one by one
857
unsigned long bytes = 0;
858
for( unsigned long i=0; ( i<blocks.size() ) & ( bytes<maxlen ); i++ )
860
unsigned long block = blocks[i];
862
// find where the small-block exactly is
863
unsigned long pos = block * sbat->blockSize;
864
unsigned long bbindex = pos / bbat->blockSize;
865
if( bbindex >= sb_blocks.size() ) break;
867
loadBigBlock( sb_blocks[ bbindex ], tmpBuf, bbat->blockSize );
870
unsigned offset = pos % bbat->blockSize;
871
unsigned long p = (maxlen-bytes < bbat->blockSize-offset ) ? maxlen-bytes : bbat->blockSize-offset;
872
p = (sbat->blockSize<p ) ? sbat->blockSize : p;
873
memcpy( data + bytes, tmpBuf + offset, p );
872
882
unsigned long libwpd::StorageIO::loadSmallBlock( unsigned long block,
873
unsigned char* data, unsigned long maxlen )
883
unsigned char *data, unsigned long maxlen )
876
if( !data ) return 0;
878
// wraps call for loadSmallBlocks
879
std::vector<unsigned long> blocks;
881
blocks.assign( 1, block );
883
return loadSmallBlocks( blocks, data, maxlen );
886
if( !data ) return 0;
888
// wraps call for loadSmallBlocks
889
std::vector<unsigned long> blocks;
891
blocks.assign( 1, block );
893
return loadSmallBlocks( blocks, data, maxlen );
886
896
// =========== StreamIO ==========
888
libwpd::StreamIO::StreamIO( libwpd::StorageIO* s, libwpd::DirEntry* e) :
898
libwpd::StreamIO::StreamIO( libwpd::StorageIO *s, libwpd::DirEntry *e) :
897
907
cache_size(4096),
900
if( entry->size >= io->header->threshold )
901
blocks = io->bbat->follow( entry->start );
903
blocks = io->sbat->follow( entry->start );
910
if( entry->size >= io->header->threshold )
911
blocks = io->bbat->follow( entry->start );
913
blocks = io->sbat->follow( entry->start );
906
cache_data = new unsigned char[cache_size];
916
cache_data = new unsigned char[cache_size];
910
920
// FIXME tell parent we're gone
911
921
libwpd::StreamIO::~StreamIO()
916
926
unsigned long libwpd::StreamIO::tell()
921
931
int libwpd::StreamIO::getch()
923
// past end-of-file ?
924
if( m_pos > entry->size ) return -1;
926
// need to update cache ?
927
if( !cache_size || ( m_pos < cache_pos ) ||
928
( m_pos >= cache_pos + cache_size ) )
931
// something bad if we don't get good cache
932
if( !cache_size ) return -1;
934
int data = cache_data[m_pos - cache_pos];
940
unsigned long libwpd::StreamIO::read( unsigned long pos, unsigned char* data, unsigned long maxlen )
943
if( !data ) return 0;
944
if( maxlen == 0 ) return 0;
946
unsigned long totalbytes = 0;
948
if ( entry->size < io->header->threshold )
951
unsigned long index = pos / io->sbat->blockSize;
953
if( index >= blocks.size() ) return 0;
955
unsigned char* buf = new unsigned char[ io->sbat->blockSize ];
956
unsigned long offset = pos % io->sbat->blockSize;
957
while( totalbytes < maxlen )
959
if( index >= blocks.size() ) break;
960
io->loadSmallBlock( blocks[index], buf, io->bbat->blockSize );
961
unsigned long count = io->sbat->blockSize - offset;
962
if( count > maxlen-totalbytes ) count = maxlen-totalbytes;
963
memcpy( data+totalbytes, buf + offset, count );
974
unsigned long index = pos / io->bbat->blockSize;
976
if( index >= blocks.size() ) return 0;
978
unsigned char* buf = new unsigned char[ io->bbat->blockSize ];
979
unsigned long offset = pos % io->bbat->blockSize;
980
while( totalbytes < maxlen )
982
if( index >= blocks.size() ) break;
983
io->loadBigBlock( blocks[index], buf, io->bbat->blockSize );
984
unsigned long count = io->bbat->blockSize - offset;
985
if( count > maxlen-totalbytes ) count = maxlen-totalbytes;
986
memcpy( data+totalbytes, buf + offset, count );
998
unsigned long libwpd::StreamIO::read( unsigned char* data, unsigned long maxlen )
1000
unsigned long bytes = read( tell(), data, maxlen );
933
// past end-of-file ?
934
if( m_pos > entry->size ) return -1;
936
// need to update cache ?
937
if( !cache_size || ( m_pos < cache_pos ) ||
938
( m_pos >= cache_pos + cache_size ) )
941
// something bad if we don't get good cache
942
if( !cache_size ) return -1;
944
int data = cache_data[m_pos - cache_pos];
950
unsigned long libwpd::StreamIO::read( unsigned long pos, unsigned char *data, unsigned long maxlen )
953
if( !data ) return 0;
954
if( maxlen == 0 ) return 0;
956
unsigned long totalbytes = 0;
958
if ( entry->size < io->header->threshold )
961
unsigned long index = pos / io->sbat->blockSize;
963
if( index >= blocks.size() ) return 0;
965
unsigned char *buf = new unsigned char[ io->sbat->blockSize ];
966
unsigned long offset = pos % io->sbat->blockSize;
967
while( totalbytes < maxlen )
969
if( index >= blocks.size() ) break;
970
io->loadSmallBlock( blocks[index], buf, io->bbat->blockSize );
971
unsigned long count = io->sbat->blockSize - offset;
972
if( count > maxlen-totalbytes ) count = maxlen-totalbytes;
973
memcpy( data+totalbytes, buf + offset, count );
984
unsigned long index = pos / io->bbat->blockSize;
986
if( index >= blocks.size() ) return 0;
988
unsigned char *buf = new unsigned char[ io->bbat->blockSize ];
989
unsigned long offset = pos % io->bbat->blockSize;
990
while( totalbytes < maxlen )
992
if( index >= blocks.size() ) break;
993
io->loadBigBlock( blocks[index], buf, io->bbat->blockSize );
994
unsigned long count = io->bbat->blockSize - offset;
995
if( count > maxlen-totalbytes ) count = maxlen-totalbytes;
996
memcpy( data+totalbytes, buf + offset, count );
1008
unsigned long libwpd::StreamIO::read( unsigned char *data, unsigned long maxlen )
1010
unsigned long bytes = read( tell(), data, maxlen );
1005
1015
void libwpd::StreamIO::updateCache()
1008
if( !cache_data ) return;
1018
if( !cache_data ) return;
1010
cache_pos = m_pos - ( m_pos % cache_size );
1011
unsigned long bytes = cache_size;
1012
if( cache_pos + bytes > entry->size ) bytes = entry->size - cache_pos;
1013
cache_size = read( cache_pos, cache_data, bytes );
1020
cache_pos = m_pos - ( m_pos % cache_size );
1021
unsigned long bytes = cache_size;
1022
if( cache_pos + bytes > entry->size ) bytes = entry->size - cache_pos;
1023
cache_size = read( cache_pos, cache_data, bytes );