~ubuntu-branches/ubuntu/saucy/libwpd/saucy

« back to all changes in this revision

Viewing changes to src/lib/WPXOLEStream.cpp

  • Committer: Package Import Robot
  • Author(s): Rene Engelhard
  • Date: 2011-11-29 23:31:13 UTC
  • mfrom: (1.2.5)
  • Revision ID: package-import@ubuntu.com-20111129233113-xdtwca9h0y6wdxst
Tags: 0.9.4-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 
 
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
 
2
/* POLE - Portable C++ library to access OLE Storage
2
3
   Copyright (C) 2002-2005 Ariya Hidayat <ariya@kde.org>
3
4
 
4
5
   Performance optimization: Dmitry Fedorov
9
10
 
10
11
   Version: 0.4
11
12
 
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
14
15
   are met:
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.
23
24
 
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.
35
36
*/
36
37
 
52
53
 
53
54
class Header
54
55
{
55
 
  public:
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];
67
 
    
68
 
    Header();
69
 
    bool valid();
70
 
    void load( const unsigned char* buffer );
71
 
    void save( unsigned char* buffer );
72
 
    void debug();
 
56
public:
 
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];
 
68
 
 
69
        Header();
 
70
        bool valid();
 
71
        void load( const unsigned char *buffer );
 
72
        void save( unsigned char *buffer );
 
73
        void debug();
73
74
};
74
75
 
75
76
class AllocTable
76
77
{
77
 
  public:
78
 
    static const unsigned Eof;
79
 
    static const unsigned Avail;
80
 
    static const unsigned Bat;    
81
 
    static const unsigned MetaBat;    
82
 
    unsigned blockSize;
83
 
    AllocTable();
84
 
    void clear();
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 );
89
 
    unsigned unused();
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 );
95
 
  private:
96
 
    std::vector<unsigned long> data;
97
 
    AllocTable( const AllocTable& );
98
 
    AllocTable& operator=( const AllocTable& );
 
78
public:
 
79
        static const unsigned Eof;
 
80
        static const unsigned Avail;
 
81
        static const unsigned Bat;
 
82
        static const unsigned MetaBat;
 
83
        unsigned blockSize;
 
84
        AllocTable();
 
85
        void clear();
 
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 );
 
90
        unsigned unused();
 
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 );
 
96
private:
 
97
        std::vector<unsigned long> data;
 
98
        AllocTable( const AllocTable & );
 
99
        AllocTable &operator=( const AllocTable & );
99
100
};
100
101
 
101
102
class DirEntry
102
103
{
103
 
  public:
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
 
104
public:
 
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
114
115
};
115
116
 
116
117
class DirTree
117
118
{
118
 
  public:
119
 
    static const unsigned End;
120
 
    DirTree();
121
 
    void clear();
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 );
131
 
  private:
132
 
    std::vector<DirEntry> entries;
133
 
    DirTree( const DirTree& );
134
 
    DirTree& operator=( const DirTree& );
 
119
public:
 
120
        static const unsigned End;
 
121
        DirTree();
 
122
        void clear();
 
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 );
 
132
private:
 
133
        std::vector<DirEntry> entries;
 
134
        DirTree( const DirTree & );
 
135
        DirTree &operator=( const DirTree & );
135
136
};
136
137
 
137
138
class StorageIO
138
139
{
139
 
  public:
140
 
    Storage* storage;         // owner
141
 
    std::stringstream buf;
142
 
    int result;               // result of operation
143
 
    unsigned long bufsize;    // size of the buffer
144
 
    
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
149
 
    
150
 
    std::vector<unsigned long> sb_blocks; // blocks for "small" files
151
 
       
152
 
    std::list<Stream*> streams;
153
 
 
154
 
    StorageIO( Storage* storage, const std::stringstream &memorystream );
155
 
    ~StorageIO();
156
 
    
157
 
    bool isOLEStream();
158
 
    void load();
159
 
 
160
 
    unsigned long loadBigBlocks( std::vector<unsigned long> blocks, unsigned char* buffer, unsigned long maxlen );
161
 
 
162
 
    unsigned long loadBigBlock( unsigned long block, unsigned char* buffer, unsigned long maxlen );
163
 
 
164
 
    unsigned long loadSmallBlocks( std::vector<unsigned long> blocks, unsigned char* buffer, unsigned long maxlen );
165
 
 
166
 
    unsigned long loadSmallBlock( unsigned long block, unsigned char* buffer, unsigned long maxlen );
167
 
    
168
 
    StreamIO* streamIO( const std::string& name ); 
169
 
 
170
 
  private:  
171
 
    // no copy or assign
172
 
    StorageIO( const StorageIO& );
173
 
    StorageIO& operator=( const StorageIO& );
 
140
public:
 
141
        Storage *storage;         // owner
 
142
        std::stringstream buf;
 
143
        int result;               // result of operation
 
144
        unsigned long bufsize;    // size of the buffer
 
145
 
 
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
 
150
 
 
151
        std::vector<unsigned long> sb_blocks; // blocks for "small" files
 
152
 
 
153
        std::list<Stream *> streams;
 
154
 
 
155
        StorageIO( Storage *storage, const std::stringstream &memorystream );
 
156
        ~StorageIO();
 
157
 
 
158
        bool isOLEStream();
 
159
        void load();
 
160
 
 
161
        unsigned long loadBigBlocks( std::vector<unsigned long> blocks, unsigned char *buffer, unsigned long maxlen );
 
162
 
 
163
        unsigned long loadBigBlock( unsigned long block, unsigned char *buffer, unsigned long maxlen );
 
164
 
 
165
        unsigned long loadSmallBlocks( std::vector<unsigned long> blocks, unsigned char *buffer, unsigned long maxlen );
 
166
 
 
167
        unsigned long loadSmallBlock( unsigned long block, unsigned char *buffer, unsigned long maxlen );
 
168
 
 
169
        StreamIO *streamIO( const std::string &name );
 
170
 
 
171
private:
 
172
        // no copy or assign
 
173
        StorageIO( const StorageIO & );
 
174
        StorageIO &operator=( const StorageIO & );
174
175
 
175
176
};
176
177
 
177
178
class StreamIO
178
179
{
179
 
  public:
180
 
    StorageIO* io;
181
 
    DirEntry* entry;
182
 
    std::string fullName;
183
 
    bool eof;
184
 
    bool fail;
185
 
 
186
 
    StreamIO( StorageIO* io, DirEntry* entry );
187
 
    ~StreamIO();
188
 
    unsigned long size();
189
 
    unsigned long tell();
190
 
    int getch();
191
 
    unsigned long read( unsigned char* data, unsigned long maxlen );
192
 
    unsigned long read( unsigned long pos, unsigned char* data, unsigned long maxlen );
193
 
 
194
 
 
195
 
  private:
196
 
    std::vector<unsigned long> blocks;
197
 
 
198
 
    // no copy or assign
199
 
    StreamIO( const StreamIO& );
200
 
    StreamIO& operator=( const StreamIO& );
201
 
 
202
 
    // pointer for read
203
 
    unsigned long m_pos;
204
 
 
205
 
    // simple cache system to speed-up getch()
206
 
    unsigned char* cache_data;
207
 
    unsigned long cache_size;
208
 
    unsigned long cache_pos;
209
 
    void updateCache();
 
180
public:
 
181
        StorageIO *io;
 
182
        DirEntry *entry;
 
183
        std::string fullName;
 
184
        bool eof;
 
185
        bool fail;
 
186
 
 
187
        StreamIO( StorageIO *io, DirEntry *entry );
 
188
        ~StreamIO();
 
189
        unsigned long size();
 
190
        unsigned long tell();
 
191
        int getch();
 
192
        unsigned long read( unsigned char *data, unsigned long maxlen );
 
193
        unsigned long read( unsigned long pos, unsigned char *data, unsigned long maxlen );
 
194
 
 
195
 
 
196
private:
 
197
        std::vector<unsigned long> blocks;
 
198
 
 
199
        // no copy or assign
 
200
        StreamIO( const StreamIO & );
 
201
        StreamIO &operator=( const StreamIO & );
 
202
 
 
203
        // pointer for read
 
204
        unsigned long m_pos;
 
205
 
 
206
        // simple cache system to speed-up getch()
 
207
        unsigned char *cache_data;
 
208
        unsigned long cache_size;
 
209
        unsigned long cache_pos;
 
210
        void updateCache();
210
211
};
211
212
 
212
213
} // namespace libwpd
213
214
 
214
 
static inline unsigned long readU16( const unsigned char* ptr )
 
215
static inline unsigned long readU16( const unsigned char *ptr )
215
216
{
216
 
  return ptr[0]+(ptr[1]<<8);
 
217
        return ptr[0]+(ptr[1]<<8);
217
218
}
218
219
 
219
 
static inline unsigned long readU32( const unsigned char* ptr )
 
220
static inline unsigned long readU32( const unsigned char *ptr )
220
221
{
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);
222
223
}
223
224
 
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 };
226
227
 
227
228
 
228
229
// =========== Header ==========
238
239
        mbat_start(0),
239
240
        num_mbat(0)
240
241
{
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;
245
246
}
246
247
 
247
248
bool libwpd::Header::valid()
248
249
{
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;
256
257
 
257
 
  return true;
 
258
        return true;
258
259
}
259
260
 
260
 
void libwpd::Header::load( const unsigned char* buffer )
 
261
void libwpd::Header::load( const unsigned char *buffer )
261
262
{
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 );
271
272
 
272
 
  for( unsigned i = 0; i < 8; i++ )
273
 
    id[i] = buffer[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++ )
 
274
                id[i] = buffer[i];
 
275
        for( unsigned j=0; j<109; j++ )
 
276
                bb_blocks[j] = readU32( buffer + 0x4C+j*4 );
276
277
}
277
278
 
278
279
 
279
 
 
 
280
 
280
281
// =========== AllocTable ==========
281
282
 
282
283
const unsigned libwpd::AllocTable::Avail = 0xffffffff;
288
289
        blockSize(4096),
289
290
        data()
290
291
{
291
 
  // initial size
292
 
  resize( 128 );
 
292
        // initial size
 
293
        resize( 128 );
293
294
}
294
295
 
295
296
unsigned long libwpd::AllocTable::count()
296
297
{
297
 
  return data.size();
 
298
        return data.size();
298
299
}
299
300
 
300
301
void libwpd::AllocTable::resize( unsigned long newsize )
301
302
{
302
 
  unsigned oldsize = data.size();
303
 
  data.resize( newsize );
304
 
  if( newsize > oldsize )
305
 
    for( unsigned i = oldsize; i<newsize; i++ )
306
 
      data[i] = Avail;
 
303
        unsigned oldsize = data.size();
 
304
        data.resize( newsize );
 
305
        if( newsize > oldsize )
 
306
                for( unsigned i = oldsize; i<newsize; i++ )
 
307
                        data[i] = Avail;
307
308
}
308
309
 
309
310
// make sure there're still free blocks
310
311
void libwpd::AllocTable::preserve( unsigned long n )
311
312
{
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() );
315
316
}
316
317
 
317
318
unsigned long libwpd::AllocTable::operator[]( unsigned long index )
318
319
{
319
 
  unsigned long result;
320
 
  result = data[index];
321
 
  return result;
 
320
        unsigned long result;
 
321
        result = data[index];
 
322
        return result;
322
323
}
323
324
 
324
325
void libwpd::AllocTable::set( unsigned long index, unsigned long value )
325
326
{
326
 
  if( index >= count() ) resize( index + 1);
327
 
  data[ index ] = value;
 
327
        if( index >= count() ) resize( index + 1);
 
328
        data[ index ] = value;
328
329
}
329
330
 
330
331
void libwpd::AllocTable::setChain( std::vector<unsigned long> chain )
331
332
{
332
 
  if( chain.size() )
333
 
  {
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 );
337
 
  }
 
333
        if( chain.size() )
 
334
        {
 
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 );
 
338
        }
338
339
}
339
340
 
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)
343
344
{
344
 
 for(unsigned i = 0; i < chain.size(); i++)
345
 
   if(chain[i] == item) return true;
346
 
 
347
 
 return false;
348
 
349
 
 
350
 
// follow 
 
345
        for(unsigned i = 0; i < chain.size(); i++)
 
346
                if(chain[i] == item) return true;
 
347
 
 
348
        return false;
 
349
}
 
350
 
 
351
// follow
351
352
std::vector<unsigned long> libwpd::AllocTable::follow( unsigned long start )
352
353
{
353
 
  std::vector<unsigned long> chain;
354
 
 
355
 
  if( start >= count() ) return chain; 
356
 
 
357
 
  unsigned long p = start;
358
 
  while( p < count() )
359
 
  {
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;
366
 
    p = data[ p ];
367
 
  }
368
 
 
369
 
  return chain;
 
354
        std::vector<unsigned long> chain;
 
355
 
 
356
        if( start >= count() ) return chain;
 
357
 
 
358
        unsigned long p = start;
 
359
        while( p < count() )
 
360
        {
 
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;
 
367
                p = data[ p ];
 
368
        }
 
369
 
 
370
        return chain;
370
371
}
371
372
 
372
373
unsigned libwpd::AllocTable::unused()
373
374
{
374
 
  // find first available block
375
 
  for( unsigned i = 0; i < data.size(); i++ )
376
 
    if( data[i] == Avail )
377
 
      return i;
378
 
  
379
 
  // completely full, so enlarge the table
380
 
  unsigned block = data.size();
381
 
  resize( data.size()+10 );
382
 
  return block;      
 
375
        // find first available block
 
376
        for( unsigned i = 0; i < data.size(); i++ )
 
377
                if( data[i] == Avail )
 
378
                        return i;
 
379
 
 
380
        // completely full, so enlarge the table
 
381
        unsigned block = data.size();
 
382
        resize( data.size()+10 );
 
383
        return block;
383
384
}
384
385
 
385
 
void libwpd::AllocTable::load( const unsigned char* buffer, unsigned len )
 
386
void libwpd::AllocTable::load( const unsigned char *buffer, unsigned len )
386
387
{
387
 
  resize( len / 4 );
388
 
  for( unsigned i = 0; i < count(); i++ )
389
 
    set( i, readU32( buffer + i*4 ) );
 
388
        resize( len / 4 );
 
389
        for( unsigned i = 0; i < count(); i++ )
 
390
                set( i, readU32( buffer + i*4 ) );
390
391
}
391
392
 
392
393
// =========== DirTree ==========
396
397
libwpd::DirTree::DirTree() :
397
398
        entries()
398
399
{
399
 
  clear();
 
400
        clear();
400
401
}
401
402
 
402
403
void libwpd::DirTree::clear()
403
404
{
404
 
  // leave only root entry
405
 
  entries.resize( 1 );
406
 
  entries[0].valid = true;
407
 
  entries[0].name = "Root Entry";
408
 
  entries[0].dir = true;
409
 
  entries[0].size = 0;
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
 
406
        entries.resize( 1 );
 
407
        entries[0].valid = true;
 
408
        entries[0].name = "Root Entry";
 
409
        entries[0].dir = true;
 
410
        entries[0].size = 0;
 
411
        entries[0].start = End;
 
412
        entries[0].prev = End;
 
413
        entries[0].next = End;
 
414
        entries[0].child = End;
414
415
}
415
416
 
416
417
unsigned libwpd::DirTree::entryCount()
417
418
{
418
 
  return entries.size();
 
419
        return entries.size();
419
420
}
420
421
 
421
 
libwpd::DirEntry* libwpd::DirTree::entry( unsigned index )
 
422
libwpd::DirEntry *libwpd::DirTree::entry( unsigned index )
422
423
{
423
 
  if( index >= entryCount() ) return (libwpd::DirEntry*) 0;
424
 
  return &entries[ index ];
 
424
        if( index >= entryCount() ) return (libwpd::DirEntry *) 0;
 
425
        return &entries[ index ];
425
426
}
426
427
 
427
428
int libwpd::DirTree::parent( unsigned index )
428
429
{
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++ )
432
 
  {
433
 
    std::vector<unsigned> chi = children( j );
434
 
    for( unsigned i=0; i<chi.size();i++ )
435
 
      if( chi[i] == index )
436
 
        return j;
437
 
  }
438
 
        
439
 
  return -1;
 
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++ )
 
433
        {
 
434
                std::vector<unsigned> chi = children( j );
 
435
                for( unsigned i=0; i<chi.size(); i++ )
 
436
                        if( chi[i] == index )
 
437
                                return j;
 
438
        }
 
439
 
 
440
        return -1;
440
441
}
441
442
 
442
443
std::string libwpd::DirTree::fullName( unsigned index )
443
444
{
444
 
  // don't use root name ("Root Entry"), just give "/"
445
 
  if( index == 0 ) return "/";
446
 
 
447
 
  std::string result = entry( index )->name;
448
 
  result.insert( 0,  "/" );
449
 
  int p = parent( index );
450
 
  DirEntry * _entry = 0;
451
 
 
452
 
  std::vector<int> seens;
453
 
  seens.push_back(p);
454
 
 
455
 
  while( p > 0 )
456
 
  {
457
 
    _entry = entry( p );
458
 
    if (_entry->dir && _entry->valid)
459
 
    {
460
 
      result.insert( 0,  _entry->name);
461
 
      result.insert( 0,  "/" );
462
 
    }
463
 
 
464
 
    p = parent(p);
465
 
    if (p < 0) break;
466
 
 
467
 
    bool ok = true;
468
 
    // sanity check
469
 
    for (int i = 0; i < int(seens.size()); i++) {
470
 
      if (seens[i] == p) { ok = false; break; }
471
 
    }
472
 
    if (!ok) break;
473
 
    seens.push_back(p);
474
 
  }
475
 
  return result;
 
445
        // don't use root name ("Root Entry"), just give "/"
 
446
        if( index == 0 ) return "/";
 
447
 
 
448
        std::string result = entry( index )->name;
 
449
        result.insert( 0,  "/" );
 
450
        int p = parent( index );
 
451
        DirEntry *_entry = 0;
 
452
 
 
453
        std::vector<int> seens;
 
454
        seens.push_back(p);
 
455
 
 
456
        while( p > 0 )
 
457
        {
 
458
                _entry = entry( p );
 
459
                if (_entry->dir && _entry->valid)
 
460
                {
 
461
                        result.insert( 0,  _entry->name);
 
462
                        result.insert( 0,  "/" );
 
463
                }
 
464
 
 
465
                p = parent(p);
 
466
                if (p < 0) break;
 
467
 
 
468
                bool ok = true;
 
469
                // sanity check
 
470
                for (int i = 0; i < int(seens.size()); i++)
 
471
                {
 
472
                        if (seens[i] == p)
 
473
                        {
 
474
                                ok = false;
 
475
                                break;
 
476
                        }
 
477
                }
 
478
                if (!ok) break;
 
479
                seens.push_back(p);
 
480
        }
 
481
        return result;
476
482
}
477
483
 
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 )
480
486
{
481
487
 
482
 
   if( !name.length() ) return (libwpd::DirEntry*)0;
483
 
 
484
 
   // quick check for "/" (that's root)
485
 
   if( name == "/" ) return entry( 0 );
486
 
   
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() )
493
 
   {
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 ) );
497
 
     start = end+1;
498
 
   }
499
 
  
500
 
   // start from root 
501
 
   int index = 0 ;
502
 
 
503
 
   // trace one by one   
504
 
   std::list<std::string>::iterator it; 
505
 
 
506
 
   for( it = names.begin(); it != names.end(); ++it )
507
 
   {
508
 
     unsigned child = 0;
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;
514
 
   }
515
 
 
516
 
   return entry( index );
 
488
        if( !name.length() ) return (libwpd::DirEntry *)0;
 
489
 
 
490
        // quick check for "/" (that's root)
 
491
        if( name == "/" ) return entry( 0 );
 
492
 
 
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() )
 
499
        {
 
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 ) );
 
503
                start = end+1;
 
504
        }
 
505
 
 
506
        // start from root
 
507
        int index = 0 ;
 
508
 
 
509
        // trace one by one
 
510
        std::list<std::string>::iterator it;
 
511
 
 
512
        for( it = names.begin(); it != names.end(); ++it )
 
513
        {
 
514
                unsigned child = 0;
 
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;
 
520
        }
 
521
 
 
522
        return entry( index );
517
523
}
518
524
 
519
525
// helper function: recursively find siblings of index
520
 
static void dirtree_find_siblings( libwpd::DirTree* dirtree, std::vector<unsigned>& result, 
521
 
  unsigned index )
522
 
{
523
 
  libwpd::DirEntry* e = dirtree->entry( index );
524
 
  if( !e ) return;
525
 
  if( !e->valid ) return;
526
 
 
527
 
  // prevent infinite loop  
528
 
  for( unsigned i = 0; i < result.size(); i++ )
529
 
    if( result[i] == index ) return;
530
 
 
531
 
  // add myself    
532
 
  result.push_back( index );
533
 
  
534
 
  // visit previous sibling, don't go infinitely
535
 
  unsigned prev = e->prev;
536
 
  if( ( prev > 0 ) && ( prev < dirtree->entryCount() ) )
537
 
  {
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 );
541
 
  }
542
 
    
543
 
  // visit next sibling, don't go infinitely
544
 
  unsigned next = e->next;
545
 
  if( ( next > 0 ) && ( next < dirtree->entryCount() ) )
546
 
  {
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 );
550
 
  }
551
 
}
552
 
 
553
 
static unsigned dirtree_find_sibling( libwpd::DirTree* dirtree, unsigned index, const std::string& name ) {
554
 
 
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;
559
 
 
560
 
  if (e->next>0 && e->next<count) {
561
 
    unsigned r = dirtree_find_sibling( dirtree, e->next, name );
562
 
    if (r>0) return r;
563
 
  }
564
 
 
565
 
  if (e->prev>0 && e->prev<count) {
566
 
    unsigned r = dirtree_find_sibling( dirtree, e->prev, name );
567
 
    if (r>0) return r;
568
 
  }
569
 
 
570
 
  return 0;
571
 
}
572
 
 
573
 
unsigned libwpd::DirTree::find_child( unsigned index, const std::string& name ) {
574
 
  
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 );
579
 
 
580
 
  return 0;
 
526
static void dirtree_find_siblings( libwpd::DirTree *dirtree, std::vector<unsigned>& result,
 
527
unsigned index )
 
528
{
 
529
        libwpd::DirEntry *e = dirtree->entry( index );
 
530
        if( !e ) return;
 
531
        if( !e->valid ) return;
 
532
 
 
533
        // prevent infinite loop
 
534
        for( unsigned i = 0; i < result.size(); i++ )
 
535
                if( result[i] == index ) return;
 
536
 
 
537
        // add myself
 
538
        result.push_back( index );
 
539
 
 
540
        // visit previous sibling, don't go infinitely
 
541
        unsigned prev = e->prev;
 
542
        if( ( prev > 0 ) && ( prev < dirtree->entryCount() ) )
 
543
        {
 
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 );
 
547
        }
 
548
 
 
549
        // visit next sibling, don't go infinitely
 
550
        unsigned next = e->next;
 
551
        if( ( next > 0 ) && ( next < dirtree->entryCount() ) )
 
552
        {
 
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 );
 
556
        }
 
557
}
 
558
 
 
559
static unsigned dirtree_find_sibling( libwpd::DirTree *dirtree, unsigned index, const std::string &name )
 
560
{
 
561
 
 
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;
 
566
 
 
567
        if (e->next>0 && e->next<count)
 
568
        {
 
569
                unsigned r = dirtree_find_sibling( dirtree, e->next, name );
 
570
                if (r>0) return r;
 
571
        }
 
572
 
 
573
        if (e->prev>0 && e->prev<count)
 
574
        {
 
575
                unsigned r = dirtree_find_sibling( dirtree, e->prev, name );
 
576
                if (r>0) return r;
 
577
        }
 
578
 
 
579
        return 0;
 
580
}
 
581
 
 
582
unsigned libwpd::DirTree::find_child( unsigned index, const std::string &name )
 
583
{
 
584
 
 
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 );
 
589
 
 
590
        return 0;
581
591
}
582
592
 
583
593
std::vector<unsigned> libwpd::DirTree::children( unsigned index )
584
594
{
585
 
  std::vector<unsigned> result;
586
 
  
587
 
  DirEntry* e = entry( index );
588
 
  if( e ) if( e->valid && e->child < entryCount() )
589
 
    dirtree_find_siblings( this, result, e->child );
590
 
    
591
 
  return result;
 
595
        std::vector<unsigned> result;
 
596
 
 
597
        DirEntry *e = entry( index );
 
598
        if( e ) if( e->valid && e->child < entryCount() )
 
599
                        dirtree_find_siblings( this, result, e->child );
 
600
 
 
601
        return result;
592
602
}
593
603
 
594
 
void libwpd::DirTree::load( unsigned char* buffer, unsigned size )
 
604
void libwpd::DirTree::load( unsigned char *buffer, unsigned size )
595
605
{
596
 
  entries.clear();
597
 
  
598
 
  for( unsigned i = 0; i < size/128; i++ )
599
 
  {
600
 
    unsigned p = i * 128;
601
 
    
602
 
    // parse name of this entry, which stored as Unicode 16-bit
603
 
    std::string name;
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] );
608
 
      
609
 
    // would be < 32 if first char in the name isn't printable
610
 
    // first char isn't printable ? remove it...
611
 
    if( buffer[p] < 32 )
612
 
      name.erase( 0,1 ); 
613
 
    
614
 
    // 2 = file (aka stream), 1 = directory (aka storage), 5 = root
615
 
    unsigned type = buffer[ 0x42 + p];
616
 
    
617
 
    libwpd::DirEntry e;
618
 
    e.valid = true;
619
 
    e.name = name;
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 );
625
 
    e.dir = ( type!=2 );
626
 
    
627
 
    // sanity checks
628
 
    if( (type != 2) && (type != 1 ) && (type != 5 ) ) e.valid = false;
629
 
    if( name_len < 1 ) e.valid = false;
630
 
    
631
 
    entries.push_back( e );
632
 
  }  
 
606
        entries.clear();
 
607
 
 
608
        for( unsigned i = 0; i < size/128; i++ )
 
609
        {
 
610
                unsigned p = i * 128;
 
611
 
 
612
                // parse name of this entry, which stored as Unicode 16-bit
 
613
                std::string name;
 
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] );
 
618
 
 
619
                // would be < 32 if first char in the name isn't printable
 
620
                // first char isn't printable ? remove it...
 
621
                if( buffer[p] < 32 )
 
622
                        name.erase( 0,1 );
 
623
 
 
624
                // 2 = file (aka stream), 1 = directory (aka storage), 5 = root
 
625
                unsigned type = buffer[ 0x42 + p];
 
626
 
 
627
                libwpd::DirEntry e;
 
628
                e.valid = true;
 
629
                e.name = name;
 
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 );
 
635
                e.dir = ( type!=2 );
 
636
 
 
637
                // sanity checks
 
638
                if( (type != 2) && (type != 1 ) && (type != 5 ) ) e.valid = false;
 
639
                if( name_len < 1 ) e.valid = false;
 
640
 
 
641
                entries.push_back( e );
 
642
        }
633
643
}
634
644
 
635
645
// =========== StorageIO ==========
636
646
 
637
 
libwpd::StorageIO::StorageIO( libwpd::Storage* st, const std::stringstream &memorystream ) :
 
647
libwpd::StorageIO::StorageIO( libwpd::Storage *st, const std::stringstream &memorystream ) :
638
648
        storage(st),
639
649
        buf( memorystream.str(), std::ios::binary | std::ios::in ),
640
650
        result(libwpd::Storage::Ok),
646
656
        sb_blocks(),
647
657
        streams()
648
658
{
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;
651
661
}
652
662
 
653
663
libwpd::StorageIO::~StorageIO()
654
664
{
655
 
  delete sbat;
656
 
  delete bbat;
657
 
  delete dirtree;
658
 
  delete header;
 
665
        delete sbat;
 
666
        delete bbat;
 
667
        delete dirtree;
 
668
        delete header;
659
669
 
660
 
  std::list<libwpd::Stream*>::iterator it;
661
 
  for( it = streams.begin(); it != streams.end(); ++it )
662
 
    delete *it;
 
670
        std::list<libwpd::Stream *>::iterator it;
 
671
        for( it = streams.begin(); it != streams.end(); ++it )
 
672
                delete *it;
663
673
}
664
674
 
665
675
bool libwpd::StorageIO::isOLEStream()
666
676
{
667
 
  load();
668
 
  return (result == libwpd::Storage::Ok);
 
677
        load();
 
678
        return (result == libwpd::Storage::Ok);
669
679
}
670
680
 
671
681
void libwpd::StorageIO::load()
672
682
{
673
 
  unsigned char* buffer = 0;
674
 
  unsigned long buflen = 0;
675
 
  std::vector<unsigned long> blocks;
676
 
  
677
 
  // find size of input file
678
 
  buf.seekg( 0, std::ios::end );
679
 
  bufsize = buf.tellg();
680
 
 
681
 
  // load header
682
 
  buffer = new unsigned char[512];
683
 
  buf.seekg( 0 ); 
684
 
  buf.read( (char*)buffer, 512 );
685
 
  header->load( buffer );
686
 
  delete[] buffer;
687
 
 
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] )
692
 
      return;
693
 
 
694
 
  // sanity checks
695
 
  result = libwpd::Storage::BadOLE;
696
 
  if( !header->valid() ) return;
697
 
  if( header->threshold != 4096 ) return;
698
 
 
699
 
  // important block size
700
 
  bbat->blockSize = 1 << header->b_shift;
701
 
  sbat->blockSize = 1 << header->s_shift;
702
 
  
703
 
  // find blocks allocated to store big bat
704
 
  // the first 109 blocks are in header, the rest in meta bat
705
 
  blocks.clear();
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) )
711
 
  {
712
 
    unsigned char* buffer2 = new unsigned char[ bbat->blockSize ];
713
 
    unsigned k = 109;
714
 
    unsigned sector;
715
 
    for( unsigned r = 0; r < header->num_mbat; r++ )
716
 
    {
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 )
723
 
      {
724
 
        if( k >= header->num_bat ) break;
725
 
        else  blocks[k++] = readU32( buffer2 + s );
726
 
      }
727
 
      /* 
728
 
      loadBigBlock( header->mbat_start+r, buffer2, bbat->blockSize );
729
 
      for( unsigned s=0; s < bbat->blockSize; s+=4 )
730
 
      {
731
 
        if( k >= header->num_bat ) break;
732
 
        else  blocks[k++] = readU32( buffer2 + s );
733
 
      }  
734
 
      */
735
 
     }    
736
 
    delete[] buffer2;
737
 
  }
738
 
 
739
 
  // load big bat
740
 
  buflen = blocks.size()*bbat->blockSize;
741
 
  if( buflen > 0 )
742
 
  {
743
 
    buffer = new unsigned char[ buflen ];  
744
 
    loadBigBlocks( blocks, buffer, buflen );
745
 
    bbat->load( buffer, buflen );
746
 
    delete[] buffer;
747
 
  }  
748
 
 
749
 
  // load small bat
750
 
  blocks.clear();
751
 
  blocks = bbat->follow( header->sbat_start );
752
 
  buflen = blocks.size()*bbat->blockSize;
753
 
  if( buflen > 0 )
754
 
  {
755
 
    buffer = new unsigned char[ buflen ];  
756
 
    loadBigBlocks( blocks, buffer, buflen );
757
 
    sbat->load( buffer, buflen );
758
 
    delete[] buffer;
759
 
  }  
760
 
  
761
 
  // load directory tree
762
 
  blocks.clear();
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 );
769
 
  delete[] buffer;
770
 
  
771
 
  // fetch block chain as data for small-files
772
 
  sb_blocks = bbat->follow( sb_start ); // small files
773
 
  
774
 
  // so far so good
775
 
  result = libwpd::Storage::Ok;
 
683
        unsigned char *buffer = 0;
 
684
        unsigned long buflen = 0;
 
685
        std::vector<unsigned long> blocks;
 
686
 
 
687
        // find size of input file
 
688
        buf.seekg( 0, std::ios::end );
 
689
        bufsize = buf.tellg();
 
690
 
 
691
        // load header
 
692
        buffer = new unsigned char[512];
 
693
        buf.seekg( 0 );
 
694
        buf.read( (char *)buffer, 512 );
 
695
        header->load( buffer );
 
696
        delete[] buffer;
 
697
 
 
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] )
 
702
                        return;
 
703
 
 
704
        // sanity checks
 
705
        result = libwpd::Storage::BadOLE;
 
706
        if( !header->valid() ) return;
 
707
        if( header->threshold != 4096 ) return;
 
708
 
 
709
        // important block size
 
710
        bbat->blockSize = 1 << header->b_shift;
 
711
        sbat->blockSize = 1 << header->s_shift;
 
712
 
 
713
        // find blocks allocated to store big bat
 
714
        // the first 109 blocks are in header, the rest in meta bat
 
715
        blocks.clear();
 
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) )
 
721
        {
 
722
                unsigned char *buffer2 = new unsigned char[ bbat->blockSize ];
 
723
                unsigned k = 109;
 
724
                unsigned sector;
 
725
                for( unsigned r = 0; r < header->num_mbat; r++ )
 
726
                {
 
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 )
 
733
                        {
 
734
                                if( k >= header->num_bat ) break;
 
735
                                else  blocks[k++] = readU32( buffer2 + s );
 
736
                        }
 
737
                        /*
 
738
                        loadBigBlock( header->mbat_start+r, buffer2, bbat->blockSize );
 
739
                        for( unsigned s=0; s < bbat->blockSize; s+=4 )
 
740
                        {
 
741
                          if( k >= header->num_bat ) break;
 
742
                          else  blocks[k++] = readU32( buffer2 + s );
 
743
                        }
 
744
                        */
 
745
                }
 
746
                delete[] buffer2;
 
747
        }
 
748
 
 
749
        // load big bat
 
750
        buflen = blocks.size()*bbat->blockSize;
 
751
        if( buflen > 0 )
 
752
        {
 
753
                buffer = new unsigned char[ buflen ];
 
754
                loadBigBlocks( blocks, buffer, buflen );
 
755
                bbat->load( buffer, buflen );
 
756
                delete[] buffer;
 
757
        }
 
758
 
 
759
        // load small bat
 
760
        blocks.clear();
 
761
        blocks = bbat->follow( header->sbat_start );
 
762
        buflen = blocks.size()*bbat->blockSize;
 
763
        if( buflen > 0 )
 
764
        {
 
765
                buffer = new unsigned char[ buflen ];
 
766
                loadBigBlocks( blocks, buffer, buflen );
 
767
                sbat->load( buffer, buflen );
 
768
                delete[] buffer;
 
769
        }
 
770
 
 
771
        // load directory tree
 
772
        blocks.clear();
 
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 );
 
779
        delete[] buffer;
 
780
 
 
781
        // fetch block chain as data for small-files
 
782
        sb_blocks = bbat->follow( sb_start ); // small files
 
783
 
 
784
        // so far so good
 
785
        result = libwpd::Storage::Ok;
776
786
}
777
787
 
778
 
libwpd::StreamIO* libwpd::StorageIO::streamIO( const std::string& name )
 
788
libwpd::StreamIO *libwpd::StorageIO::streamIO( const std::string &name )
779
789
{
780
 
  load();
781
 
 
782
 
  // sanity check
783
 
  if( !name.length() ) return (libwpd::StreamIO*)0;
784
 
 
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;
789
 
 
790
 
  libwpd::StreamIO* res = new libwpd::StreamIO( this, entry );
791
 
  res->fullName = name;
792
 
  
793
 
  return res;
 
790
        load();
 
791
 
 
792
        // sanity check
 
793
        if( !name.length() ) return (libwpd::StreamIO *)0;
 
794
 
 
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;
 
799
 
 
800
        libwpd::StreamIO *res = new libwpd::StreamIO( this, entry );
 
801
        res->fullName = name;
 
802
 
 
803
        return res;
794
804
}
795
805
 
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 )
798
808
{
799
 
  // sentinel
800
 
  if( !data ) return 0;
801
 
  if( blocks.size() < 1 ) return 0;
802
 
  if( maxlen == 0 ) return 0;
803
 
 
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++ )
807
 
  {
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;
812
 
    buf.seekg( pos );
813
 
    buf.read( (char*)data + bytes, p );
814
 
    bytes += p;
815
 
  }
816
 
 
817
 
  return bytes;
 
809
        // sentinel
 
810
        if( !data ) return 0;
 
811
        if( blocks.size() < 1 ) return 0;
 
812
        if( maxlen == 0 ) return 0;
 
813
 
 
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++ )
 
817
        {
 
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;
 
822
                buf.seekg( pos );
 
823
                buf.read( (char *)data + bytes, p );
 
824
                bytes += p;
 
825
        }
 
826
 
 
827
        return bytes;
818
828
}
819
829
 
820
830
unsigned long libwpd::StorageIO::loadBigBlock( unsigned long block,
821
 
  unsigned char* data, unsigned long maxlen )
 
831
unsigned char *data, unsigned long maxlen )
822
832
{
823
 
  // sentinel
824
 
  if( !data ) return 0;
825
 
 
826
 
  // wraps call for loadBigBlocks
827
 
  std::vector<unsigned long> blocks;
828
 
  blocks.resize( 1 );
829
 
  blocks[ 0 ] = block;
830
 
  
831
 
  return loadBigBlocks( blocks, data, maxlen );
 
833
        // sentinel
 
834
        if( !data ) return 0;
 
835
 
 
836
        // wraps call for loadBigBlocks
 
837
        std::vector<unsigned long> blocks;
 
838
        blocks.resize( 1 );
 
839
        blocks[ 0 ] = block;
 
840
 
 
841
        return loadBigBlocks( blocks, data, maxlen );
832
842
}
833
843
 
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 )
837
847
{
838
 
  // sentinel
839
 
  if( !data ) return 0;
840
 
  if( blocks.size() < 1 ) return 0;
841
 
  if( maxlen == 0 ) return 0;
842
 
 
843
 
  // our own local buffer
844
 
  unsigned char* tmpBuf = new unsigned char[ bbat->blockSize ];
845
 
 
846
 
  // read small block one by one
847
 
  unsigned long bytes = 0;
848
 
  for( unsigned long i=0; ( i<blocks.size() ) & ( bytes<maxlen ); i++ )
849
 
  {
850
 
    unsigned long block = blocks[i];
851
 
 
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;
856
 
 
857
 
    loadBigBlock( sb_blocks[ bbindex ], tmpBuf, bbat->blockSize );
858
 
 
859
 
    // copy the data
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 );
864
 
    bytes += p;
865
 
  }
866
 
  
867
 
  delete[] tmpBuf;
868
 
 
869
 
  return bytes;
 
848
        // sentinel
 
849
        if( !data ) return 0;
 
850
        if( blocks.size() < 1 ) return 0;
 
851
        if( maxlen == 0 ) return 0;
 
852
 
 
853
        // our own local buffer
 
854
        unsigned char *tmpBuf = new unsigned char[ bbat->blockSize ];
 
855
 
 
856
        // read small block one by one
 
857
        unsigned long bytes = 0;
 
858
        for( unsigned long i=0; ( i<blocks.size() ) & ( bytes<maxlen ); i++ )
 
859
        {
 
860
                unsigned long block = blocks[i];
 
861
 
 
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;
 
866
 
 
867
                loadBigBlock( sb_blocks[ bbindex ], tmpBuf, bbat->blockSize );
 
868
 
 
869
                // copy the data
 
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 );
 
874
                bytes += p;
 
875
        }
 
876
 
 
877
        delete[] tmpBuf;
 
878
 
 
879
        return bytes;
870
880
}
871
881
 
872
882
unsigned long libwpd::StorageIO::loadSmallBlock( unsigned long block,
873
 
  unsigned char* data, unsigned long maxlen )
 
883
unsigned char *data, unsigned long maxlen )
874
884
{
875
 
  // sentinel
876
 
  if( !data ) return 0;
877
 
 
878
 
  // wraps call for loadSmallBlocks
879
 
  std::vector<unsigned long> blocks;
880
 
  blocks.resize( 1 );
881
 
  blocks.assign( 1, block );
882
 
 
883
 
  return loadSmallBlocks( blocks, data, maxlen );
 
885
        // sentinel
 
886
        if( !data ) return 0;
 
887
 
 
888
        // wraps call for loadSmallBlocks
 
889
        std::vector<unsigned long> blocks;
 
890
        blocks.resize( 1 );
 
891
        blocks.assign( 1, block );
 
892
 
 
893
        return loadSmallBlocks( blocks, data, maxlen );
884
894
}
885
895
 
886
896
// =========== StreamIO ==========
887
897
 
888
 
libwpd::StreamIO::StreamIO( libwpd::StorageIO* s, libwpd::DirEntry* e) :
 
898
libwpd::StreamIO::StreamIO( libwpd::StorageIO *s, libwpd::DirEntry *e) :
889
899
        io(s),
890
900
        entry(e),
891
901
        fullName(),
897
907
        cache_size(4096),
898
908
        cache_pos(0)
899
909
{
900
 
  if( entry->size >= io->header->threshold ) 
901
 
    blocks = io->bbat->follow( entry->start );
902
 
  else
903
 
    blocks = io->sbat->follow( entry->start );
 
910
        if( entry->size >= io->header->threshold )
 
911
                blocks = io->bbat->follow( entry->start );
 
912
        else
 
913
                blocks = io->sbat->follow( entry->start );
904
914
 
905
 
  // prepare cache
906
 
  cache_data = new unsigned char[cache_size];
907
 
  updateCache();
 
915
        // prepare cache
 
916
        cache_data = new unsigned char[cache_size];
 
917
        updateCache();
908
918
}
909
919
 
910
920
// FIXME tell parent we're gone
911
921
libwpd::StreamIO::~StreamIO()
912
922
{
913
 
  delete[] cache_data;  
 
923
        delete[] cache_data;
914
924
}
915
925
 
916
926
unsigned long libwpd::StreamIO::tell()
917
927
{
918
 
  return m_pos;
 
928
        return m_pos;
919
929
}
920
930
 
921
931
int libwpd::StreamIO::getch()
922
932
{
923
 
  // past end-of-file ?
924
 
  if( m_pos > entry->size ) return -1;
925
 
 
926
 
  // need to update cache ?
927
 
  if( !cache_size || ( m_pos < cache_pos ) ||
928
 
    ( m_pos >= cache_pos + cache_size ) )
929
 
      updateCache();
930
 
 
931
 
  // something bad if we don't get good cache
932
 
  if( !cache_size ) return -1;
933
 
 
934
 
  int data = cache_data[m_pos - cache_pos];
935
 
  m_pos++;
936
 
 
937
 
  return data;
938
 
}
939
 
 
940
 
unsigned long libwpd::StreamIO::read( unsigned long pos, unsigned char* data, unsigned long maxlen )
941
 
{
942
 
  // sanity checks
943
 
  if( !data ) return 0;
944
 
  if( maxlen == 0 ) return 0;
945
 
 
946
 
  unsigned long totalbytes = 0;
947
 
  
948
 
  if ( entry->size < io->header->threshold )
949
 
  {
950
 
    // small file
951
 
    unsigned long index = pos / io->sbat->blockSize;
952
 
 
953
 
    if( index >= blocks.size() ) return 0;
954
 
 
955
 
    unsigned char* buf = new unsigned char[ io->sbat->blockSize ];
956
 
    unsigned long offset = pos % io->sbat->blockSize;
957
 
    while( totalbytes < maxlen )
958
 
    {
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 );
964
 
      totalbytes += count;
965
 
      offset = 0;
966
 
      index++;
967
 
    }
968
 
    delete[] buf;
969
 
 
970
 
  }
971
 
  else
972
 
  {
973
 
    // big file
974
 
    unsigned long index = pos / io->bbat->blockSize;
975
 
    
976
 
    if( index >= blocks.size() ) return 0;
977
 
    
978
 
    unsigned char* buf = new unsigned char[ io->bbat->blockSize ];
979
 
    unsigned long offset = pos % io->bbat->blockSize;
980
 
    while( totalbytes < maxlen )
981
 
    {
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 );
987
 
      totalbytes += count;
988
 
      index++;
989
 
      offset = 0;
990
 
    }
991
 
    delete [] buf;
992
 
 
993
 
  }
994
 
 
995
 
  return totalbytes;
996
 
}
997
 
 
998
 
unsigned long libwpd::StreamIO::read( unsigned char* data, unsigned long maxlen )
999
 
{
1000
 
  unsigned long bytes = read( tell(), data, maxlen );
1001
 
  m_pos += bytes;
1002
 
  return bytes;
 
933
        // past end-of-file ?
 
934
        if( m_pos > entry->size ) return -1;
 
935
 
 
936
        // need to update cache ?
 
937
        if( !cache_size || ( m_pos < cache_pos ) ||
 
938
        ( m_pos >= cache_pos + cache_size ) )
 
939
                updateCache();
 
940
 
 
941
        // something bad if we don't get good cache
 
942
        if( !cache_size ) return -1;
 
943
 
 
944
        int data = cache_data[m_pos - cache_pos];
 
945
        m_pos++;
 
946
 
 
947
        return data;
 
948
}
 
949
 
 
950
unsigned long libwpd::StreamIO::read( unsigned long pos, unsigned char *data, unsigned long maxlen )
 
951
{
 
952
        // sanity checks
 
953
        if( !data ) return 0;
 
954
        if( maxlen == 0 ) return 0;
 
955
 
 
956
        unsigned long totalbytes = 0;
 
957
 
 
958
        if ( entry->size < io->header->threshold )
 
959
        {
 
960
                // small file
 
961
                unsigned long index = pos / io->sbat->blockSize;
 
962
 
 
963
                if( index >= blocks.size() ) return 0;
 
964
 
 
965
                unsigned char *buf = new unsigned char[ io->sbat->blockSize ];
 
966
                unsigned long offset = pos % io->sbat->blockSize;
 
967
                while( totalbytes < maxlen )
 
968
                {
 
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 );
 
974
                        totalbytes += count;
 
975
                        offset = 0;
 
976
                        index++;
 
977
                }
 
978
                delete[] buf;
 
979
 
 
980
        }
 
981
        else
 
982
        {
 
983
                // big file
 
984
                unsigned long index = pos / io->bbat->blockSize;
 
985
 
 
986
                if( index >= blocks.size() ) return 0;
 
987
 
 
988
                unsigned char *buf = new unsigned char[ io->bbat->blockSize ];
 
989
                unsigned long offset = pos % io->bbat->blockSize;
 
990
                while( totalbytes < maxlen )
 
991
                {
 
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 );
 
997
                        totalbytes += count;
 
998
                        index++;
 
999
                        offset = 0;
 
1000
                }
 
1001
                delete [] buf;
 
1002
 
 
1003
        }
 
1004
 
 
1005
        return totalbytes;
 
1006
}
 
1007
 
 
1008
unsigned long libwpd::StreamIO::read( unsigned char *data, unsigned long maxlen )
 
1009
{
 
1010
        unsigned long bytes = read( tell(), data, maxlen );
 
1011
        m_pos += bytes;
 
1012
        return bytes;
1003
1013
}
1004
1014
 
1005
1015
void libwpd::StreamIO::updateCache()
1006
1016
{
1007
 
  // sanity check
1008
 
  if( !cache_data ) return;
 
1017
        // sanity check
 
1018
        if( !cache_data ) return;
1009
1019
 
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 );
1014
1024
}
1015
1025
 
1016
1026
 
1024
1034
 
1025
1035
libwpd::Storage::~Storage()
1026
1036
{
1027
 
  delete io;
 
1037
        delete io;
1028
1038
}
1029
1039
 
1030
1040
int libwpd::Storage::result()
1031
1041
{
1032
 
  return io->result;
 
1042
        return io->result;
1033
1043
}
1034
1044
 
1035
1045
bool libwpd::Storage::isOLEStream()
1036
1046
{
1037
 
  return io->isOLEStream();
 
1047
        return io->isOLEStream();
1038
1048
}
1039
1049
 
1040
1050
// =========== Stream ==========
1041
1051
 
1042
 
libwpd::Stream::Stream( libwpd::Storage* storage, const std::string& name ) :
 
1052
libwpd::Stream::Stream( libwpd::Storage *storage, const std::string &name ) :
1043
1053
        io(storage->io->streamIO( name ))
1044
1054
{
1045
1055
}
1047
1057
// FIXME tell parent we're gone
1048
1058
libwpd::Stream::~Stream()
1049
1059
{
1050
 
  delete io;
 
1060
        delete io;
1051
1061
}
1052
1062
 
1053
1063
unsigned long libwpd::Stream::size()
1054
1064
{
1055
 
  return io ? io->entry->size : 0;
 
1065
        return io ? io->entry->size : 0;
1056
1066
}
1057
1067
 
1058
 
unsigned long libwpd::Stream::read( unsigned char* data, unsigned long maxlen )
 
1068
unsigned long libwpd::Stream::read( unsigned char *data, unsigned long maxlen )
1059
1069
{
1060
 
  return io ? io->read( data, maxlen ) : 0;
 
1070
        return io ? io->read( data, maxlen ) : 0;
1061
1071
}
 
1072
/* vim:set shiftwidth=4 softtabstop=4 noexpandtab: */