1
/* POLE - Portable C++ library to access OLE Storage
2
Copyright (C) 2002-2005 Ariya Hidayat <ariya@kde.org>
4
Redistribution and use in source and binary forms, with or without
5
modification, are permitted provided that the following conditions
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.
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.
30
This file taken from libwpg WPGOLEStream.cpp 1.5 Thu Aug 17 21:21:30 2006
39
#include "WPXOLEStream.h"
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];
62
void load( const unsigned char* buffer );
63
void save( unsigned char* buffer );
70
static const unsigned Eof;
71
static const unsigned Avail;
72
static const unsigned Bat;
73
static const unsigned MetaBat;
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 );
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 );
88
std::vector<unsigned long> data;
89
AllocTable( const AllocTable& );
90
AllocTable& operator=( const AllocTable& );
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
111
static const unsigned End;
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 );
123
std::vector<DirEntry> entries;
124
DirTree( const DirTree& );
125
DirTree& operator=( const DirTree& );
131
Storage* storage; // owner
132
std::stringstream buf;
133
int result; // result of operation
134
unsigned long bufsize; // size of the buffer
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
141
std::vector<unsigned long> sb_blocks; // blocks for "small" files
143
std::list<Stream*> streams;
145
StorageIO( Storage* storage, const std::stringstream &memorystream );
151
unsigned long loadBigBlocks( std::vector<unsigned long> blocks, unsigned char* buffer, unsigned long maxlen );
153
unsigned long loadBigBlock( unsigned long block, unsigned char* buffer, unsigned long maxlen );
155
unsigned long loadSmallBlocks( std::vector<unsigned long> blocks, unsigned char* buffer, unsigned long maxlen );
157
unsigned long loadSmallBlock( unsigned long block, unsigned char* buffer, unsigned long maxlen );
159
StreamIO* streamIO( const std::string& name );
163
StorageIO( const StorageIO& );
164
StorageIO& operator=( const StorageIO& );
173
std::string fullName;
177
StreamIO( StorageIO* io, DirEntry* entry );
179
unsigned long size();
180
unsigned long tell();
182
unsigned long read( unsigned char* data, unsigned long maxlen );
183
unsigned long read( unsigned long pos, unsigned char* data, unsigned long maxlen );
187
std::vector<unsigned long> blocks;
190
StreamIO( const StreamIO& );
191
StreamIO& operator=( const StreamIO& );
196
// simple cache system to speed-up getch()
197
unsigned char* cache_data;
198
unsigned long cache_size;
199
unsigned long cache_pos;
203
} // namespace libwpd
205
static inline unsigned long readU16( const unsigned char* ptr )
207
return ptr[0]+(ptr[1]<<8);
210
static inline unsigned long readU32( const unsigned char* ptr )
212
return ptr[0]+(ptr[1]<<8)+(ptr[2]<<16)+(ptr[3]<<24);
215
static const unsigned char wpsole_magic[] =
216
{ 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1 };
219
// =========== Header ==========
221
libwpd::Header::Header() :
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;
238
bool libwpd::Header::valid()
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;
251
void libwpd::Header::load( const unsigned char* buffer )
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 );
263
for( unsigned i = 0; i < 8; i++ )
265
for( unsigned j=0; j<109; j++ )
266
bb_blocks[j] = readU32( buffer + 0x4C+j*4 );
271
// =========== AllocTable ==========
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;
278
libwpd::AllocTable::AllocTable() :
286
unsigned long libwpd::AllocTable::count()
291
void libwpd::AllocTable::resize( unsigned long newsize )
293
unsigned oldsize = data.size();
294
data.resize( newsize );
295
if( newsize > oldsize )
296
for( unsigned i = oldsize; i<newsize; i++ )
300
// make sure there're still free blocks
301
void libwpd::AllocTable::preserve( unsigned long n )
303
std::vector<unsigned long> pre;
304
for( unsigned i=0; i < n; i++ )
305
pre.push_back( unused() );
308
unsigned long libwpd::AllocTable::operator[]( unsigned long index )
310
unsigned long result;
311
result = data[index];
315
void libwpd::AllocTable::set( unsigned long index, unsigned long value )
317
if( index >= count() ) resize( index + 1);
318
data[ index ] = value;
321
void libwpd::AllocTable::setChain( std::vector<unsigned long> chain )
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 );
331
// TODO: optimize this with better search
332
static bool already_exist(const std::vector<unsigned long>& chain,
335
for(unsigned i = 0; i < chain.size(); i++)
336
if(chain[i] == item) return true;
342
std::vector<unsigned long> libwpd::AllocTable::follow( unsigned long start )
344
std::vector<unsigned long> chain;
346
if( start >= count() ) return chain;
348
unsigned long p = start;
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;
363
unsigned libwpd::AllocTable::unused()
365
// find first available block
366
for( unsigned i = 0; i < data.size(); i++ )
367
if( data[i] == Avail )
370
// completely full, so enlarge the table
371
unsigned block = data.size();
372
resize( data.size()+10 );
376
void libwpd::AllocTable::load( const unsigned char* buffer, unsigned len )
379
for( unsigned i = 0; i < count(); i++ )
380
set( i, readU32( buffer + i*4 ) );
383
// =========== DirTree ==========
385
const unsigned libwpd::DirTree::End = 0xffffffff;
387
libwpd::DirTree::DirTree() :
393
void libwpd::DirTree::clear()
395
// leave only root entry
397
entries[0].valid = true;
398
entries[0].name = "Root Entry";
399
entries[0].dir = true;
401
entries[0].start = End;
402
entries[0].prev = End;
403
entries[0].next = End;
404
entries[0].child = End;
407
unsigned libwpd::DirTree::entryCount()
409
return entries.size();
412
libwpd::DirEntry* libwpd::DirTree::entry( unsigned index )
414
if( index >= entryCount() ) return (libwpd::DirEntry*) 0;
415
return &entries[ index ];
418
int libwpd::DirTree::parent( unsigned index )
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++ )
424
std::vector<unsigned> chi = children( j );
425
for( unsigned i=0; i<chi.size();i++ )
426
if( chi[i] == index )
433
std::string libwpd::DirTree::fullName( unsigned index )
435
// don't use root name ("Root Entry"), just give "/"
436
if( index == 0 ) return "/";
438
std::string result = entry( index )->name;
439
result.insert( 0, "/" );
440
int p = parent( index );
441
DirEntry * _entry = 0;
445
if (_entry->dir && _entry->valid)
447
result.insert( 0, _entry->name);
448
result.insert( 0, "/" );
452
if( index <= 0 ) break;
457
// given a fullname (e.g "/ObjectPool/_1020961869"), find the entry
458
libwpd::DirEntry* libwpd::DirTree::entry( const std::string& name )
461
if( !name.length() ) return (libwpd::DirEntry*)0;
463
// quick check for "/" (that's root)
464
if( name == "/" ) return entry( 0 );
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() )
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 ) );
483
std::list<std::string>::iterator it;
485
for( it = names.begin(); it != names.end(); ++it )
487
// find among the children of index
488
std::vector<unsigned> chi = children( index );
490
for( unsigned i = 0; i < chi.size(); i++ )
492
libwpd::DirEntry* ce = entry( chi[i] );
494
if( ce->valid && ( ce->name.length()>1 ) )
495
if( ce->name == *it )
499
// traverse to the child
500
if( child > 0 ) index = child;
501
else return (libwpd::DirEntry*)0;
504
return entry( index );
507
// helper function: recursively find siblings of index
508
void dirtree_find_siblings( libwpd::DirTree* dirtree, std::vector<unsigned>& result,
511
libwpd::DirEntry* e = dirtree->entry( index );
513
if( !e->valid ) return;
515
// prevent infinite loop
516
for( unsigned i = 0; i < result.size(); i++ )
517
if( result[i] == index ) return;
520
result.push_back( index );
522
// visit previous sibling, don't go infinitely
523
unsigned prev = e->prev;
524
if( ( prev > 0 ) && ( prev < dirtree->entryCount() ) )
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 );
531
// visit next sibling, don't go infinitely
532
unsigned next = e->next;
533
if( ( next > 0 ) && ( next < dirtree->entryCount() ) )
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 );
541
std::vector<unsigned> libwpd::DirTree::children( unsigned index )
543
std::vector<unsigned> result;
545
DirEntry* e = entry( index );
546
if( e ) if( e->valid && e->child < entryCount() )
547
dirtree_find_siblings( this, result, e->child );
552
void libwpd::DirTree::load( unsigned char* buffer, unsigned size )
556
for( unsigned i = 0; i < size/128; i++ )
558
unsigned p = i * 128;
560
// would be < 32 if first char in the name isn't printable
561
unsigned prefix = 32;
563
// parse name of this entry, which stored as Unicode 16-bit
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] );
570
// first char isn't printable ? remove it...
577
// 2 = file (aka stream), 1 = directory (aka storage), 5 = root
578
unsigned type = buffer[ 0x42 + p];
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 );
591
if( (type != 2) && (type != 1 ) && (type != 5 ) ) e.valid = false;
592
if( name_len < 1 ) e.valid = false;
594
entries.push_back( e );
598
// =========== StorageIO ==========
600
libwpd::StorageIO::StorageIO( libwpd::Storage* st, const std::stringstream &memorystream ) :
602
buf( memorystream.str(), std::ios::binary | std::ios::in ),
603
result(libwpd::Storage::Ok),
605
header(new libwpd::Header()),
606
dirtree(new libwpd::DirTree()),
607
bbat(new libwpd::AllocTable()),
608
sbat(new libwpd::AllocTable()),
612
bbat->blockSize = 1 << header->b_shift;
613
sbat->blockSize = 1 << header->s_shift;
616
libwpd::StorageIO::~StorageIO()
623
std::list<libwpd::Stream*>::iterator it;
624
for( it = streams.begin(); it != streams.end(); ++it )
628
bool libwpd::StorageIO::isOLEStream()
631
return (result == libwpd::Storage::Ok);
634
void libwpd::StorageIO::load()
636
unsigned char* buffer = 0;
637
unsigned long buflen = 0;
638
std::vector<unsigned long> blocks;
640
// find size of input file
641
buf.seekg( 0, std::ios::end );
642
bufsize = buf.tellg();
645
buffer = new unsigned char[512];
647
buf.read( (char*)buffer, 512 );
648
header->load( buffer );
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] )
658
result = libwpd::Storage::BadOLE;
659
if( !header->valid() ) return;
660
if( header->threshold != 4096 ) return;
662
// important block size
663
bbat->blockSize = 1 << header->b_shift;
664
sbat->blockSize = 1 << header->s_shift;
666
// find blocks allocated to store big bat
667
// the first 109 blocks are in header, the rest in meta bat
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) )
675
unsigned char* buffer2 = new unsigned char[ bbat->blockSize ];
677
for( unsigned r = 0; r < header->num_mbat; r++ )
679
loadBigBlock( header->mbat_start+r, buffer2, bbat->blockSize );
680
for( unsigned s=0; s < bbat->blockSize; s+=4 )
682
if( k >= header->num_bat ) break;
683
else blocks[k++] = readU32( buffer2 + s );
690
buflen = blocks.size()*bbat->blockSize;
693
buffer = new unsigned char[ buflen ];
694
loadBigBlocks( blocks, buffer, buflen );
695
bbat->load( buffer, buflen );
701
blocks = bbat->follow( header->sbat_start );
702
buflen = blocks.size()*bbat->blockSize;
705
buffer = new unsigned char[ buflen ];
706
loadBigBlocks( blocks, buffer, buflen );
707
sbat->load( buffer, buflen );
711
// load directory tree
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 );
721
// fetch block chain as data for small-files
722
sb_blocks = bbat->follow( sb_start ); // small files
725
result = libwpd::Storage::Ok;
728
libwpd::StreamIO* libwpd::StorageIO::streamIO( const std::string& name )
733
if( !name.length() ) return (libwpd::StreamIO*)0;
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;
740
libwpd::StreamIO* res = new libwpd::StreamIO( this, entry );
741
res->fullName = name;
746
unsigned long libwpd::StorageIO::loadBigBlocks( std::vector<unsigned long> blocks,
747
unsigned char* data, unsigned long maxlen )
750
if( !data ) return 0;
751
if( blocks.size() < 1 ) return 0;
752
if( maxlen == 0 ) return 0;
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++ )
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;
763
buf.read( (char*)data + bytes, p );
770
unsigned long libwpd::StorageIO::loadBigBlock( unsigned long block,
771
unsigned char* data, unsigned long maxlen )
774
if( !data ) return 0;
776
// wraps call for loadBigBlocks
777
std::vector<unsigned long> blocks;
781
return loadBigBlocks( blocks, data, maxlen );
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 )
789
if( !data ) return 0;
790
if( blocks.size() < 1 ) return 0;
791
if( maxlen == 0 ) return 0;
793
// our own local buffer
794
unsigned char* tmpBuf = new unsigned char[ bbat->blockSize ];
796
// read small block one by one
797
unsigned long bytes = 0;
798
for( unsigned long i=0; ( i<blocks.size() ) & ( bytes<maxlen ); i++ )
800
unsigned long block = blocks[i];
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;
807
loadBigBlock( sb_blocks[ bbindex ], tmpBuf, bbat->blockSize );
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 );
822
unsigned long libwpd::StorageIO::loadSmallBlock( unsigned long block,
823
unsigned char* data, unsigned long maxlen )
826
if( !data ) return 0;
828
// wraps call for loadSmallBlocks
829
std::vector<unsigned long> blocks;
831
blocks.assign( 1, block );
833
return loadSmallBlocks( blocks, data, maxlen );
836
// =========== StreamIO ==========
838
libwpd::StreamIO::StreamIO( libwpd::StorageIO* s, libwpd::DirEntry* e) :
850
if( entry->size >= io->header->threshold )
851
blocks = io->bbat->follow( entry->start );
853
blocks = io->sbat->follow( entry->start );
856
cache_data = new unsigned char[cache_size];
860
// FIXME tell parent we're gone
861
libwpd::StreamIO::~StreamIO()
866
unsigned long libwpd::StreamIO::tell()
871
int libwpd::StreamIO::getch()
873
// past end-of-file ?
874
if( m_pos > entry->size ) return -1;
876
// need to update cache ?
877
if( !cache_size || ( m_pos < cache_pos ) ||
878
( m_pos >= cache_pos + cache_size ) )
881
// something bad if we don't get good cache
882
if( !cache_size ) return -1;
884
int data = cache_data[m_pos - cache_pos];
890
unsigned long libwpd::StreamIO::read( unsigned long pos, unsigned char* data, unsigned long maxlen )
893
if( !data ) return 0;
894
if( maxlen == 0 ) return 0;
896
unsigned long totalbytes = 0;
898
if ( entry->size < io->header->threshold )
901
unsigned long index = pos / io->sbat->blockSize;
903
if( index >= blocks.size() ) return 0;
905
unsigned char* buf = new unsigned char[ io->sbat->blockSize ];
906
unsigned long offset = pos % io->sbat->blockSize;
907
while( totalbytes < maxlen )
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 );
924
unsigned long index = pos / io->bbat->blockSize;
926
if( index >= blocks.size() ) return 0;
928
unsigned char* buf = new unsigned char[ io->bbat->blockSize ];
929
unsigned long offset = pos % io->bbat->blockSize;
930
while( totalbytes < maxlen )
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 );
948
unsigned long libwpd::StreamIO::read( unsigned char* data, unsigned long maxlen )
950
unsigned long bytes = read( tell(), data, maxlen );
955
void libwpd::StreamIO::updateCache()
958
if( !cache_data ) return;
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 );
967
// =========== Storage ==========
969
libwpd::Storage::Storage( const std::stringstream &memorystream ) :
972
io = new StorageIO( this, memorystream );
975
libwpd::Storage::~Storage()
980
int libwpd::Storage::result()
985
bool libwpd::Storage::isOLEStream()
987
return io->isOLEStream();
990
// =========== Stream ==========
992
libwpd::Stream::Stream( libwpd::Storage* storage, const std::string& name ) :
993
io(storage->io->streamIO( name ))
997
// FIXME tell parent we're gone
998
libwpd::Stream::~Stream()
1003
unsigned long libwpd::Stream::size()
1005
return io ? io->entry->size : 0;
1008
unsigned long libwpd::Stream::read( unsigned char* data, unsigned long maxlen )
1010
return io ? io->read( data, maxlen ) : 0;