kspread/excel/sidewinder/pole.cpp
1/* POLE - Portable C++ library to access OLE Storage
2 Copyright (C) 2002-2005 Ariya Hidayat <ariya@kde.org>
3
4 Redistribution and use in source and binary forms, with or without
5 modification, are permitted provided that the following conditions
6 are met:
7 * Redistributions of source code must retain the above copyright notice,
8 this list of conditions and the following disclaimer.
9 * Redistributions in binary form must reproduce the above copyright notice,
10 this list of conditions and the following disclaimer in the documentation
11 and/or other materials provided with the distribution.
12 * Neither the name of the authors nor the names of its contributors may be
13 used to endorse or promote products derived from this software without
14 specific prior written permission.
15
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 THE POSSIBILITY OF SUCH DAMAGE.
27*/
28
29#include <fstream>
30#include <iostream>
31#include <list>
32#include <string>
33#include <vector>
34#include <string.h>
35
36#include "pole.h"
37
38// enable to activate debugging output
39// #define POLE_DEBUG
40
41namespace POLE
42{
43
44class Header
45{
46 public:
47 unsigned char id[8]; // signature, or magic identifier
48 unsigned b_shift; // bbat->blockSize = 1 << b_shift
49 unsigned s_shift; // sbat->blockSize = 1 << s_shift
50 unsigned num_bat; // blocks allocated for big bat
51 unsigned dirent_start; // starting block for directory info
52 unsigned threshold; // switch from small to big file (usually 4K)
53 unsigned sbat_start; // starting block index to store small bat
54 unsigned num_sbat; // blocks allocated for small bat
55 unsigned mbat_start; // starting block to store meta bat
56 unsigned num_mbat; // blocks allocated for meta bat
57 unsigned long bb_blocks[109];
58
59 Header();
60 bool valid();
61 void load( const unsigned char* buffer );
62 void save( unsigned char* buffer );
63 void debug();
64};
65
66class AllocTable
67{
68 public:
69 static const unsigned Eof;
70 static const unsigned Avail;
71 static const unsigned Bat;
72 static const unsigned MetaBat;
73 unsigned blockSize;
74 AllocTable();
75 void clear();
76 unsigned long count();
77 void resize( unsigned long newsize );
78 void preserve( unsigned long n );
79 void set( unsigned long index, unsigned long val );
80 unsigned unused();
81 void setChain( std::vector<unsigned long> );
82 std::vector<unsigned long> follow( unsigned long start );
83 unsigned long operator[](unsigned long index );
84 void load( const unsigned char* buffer, unsigned len );
85 void save( unsigned char* buffer );
86 unsigned size();
87 void debug();
88 private:
89 std::vector<unsigned long> data;
90 AllocTable( const AllocTable& );
91 AllocTable& operator=( const AllocTable& );
92};
93
94class DirEntry
95{
96 public:
97 bool valid; // false if invalid (should be skipped)
98 std::string name; // the name, not in unicode anymore
99 bool dir; // true if directory
100 unsigned long size; // size (not valid if directory)
101 unsigned long start; // starting block
102 unsigned prev; // previous sibling
103 unsigned next; // next sibling
104 unsigned child; // first child
105};
106
107class DirTree
108{
109 public:
110 static const unsigned End;
111 DirTree();
112 void clear();
113 unsigned entryCount();
114 DirEntry* entry( unsigned index );
115 DirEntry* entry( const std::string& name, bool create=false );
116 int indexOf( DirEntry* e );
117 int parent( unsigned index );
118 std::string fullName( unsigned index );
119 std::vector<unsigned> children( unsigned index );
120 void load( unsigned char* buffer, unsigned len );
121 void save( unsigned char* buffer );
122 unsigned size();
123 void debug();
124 private:
125 std::vector<DirEntry> entries;
126 DirTree( const DirTree& );
127 DirTree& operator=( const DirTree& );
128};
129
130class StorageIO
131{
132 public:
133 Storage* storage; // owner
134 std::string filename; // filename
135 std::fstream file; // associated with above name
136 int result; // result of operation
137 bool opened; // true if file is opened
138 unsigned long filesize; // size of the file
139
140 Header* header; // storage header
141 DirTree* dirtree; // directory tree
142 AllocTable* bbat; // allocation table for big blocks
143 AllocTable* sbat; // allocation table for small blocks
144
145 unsigned long lastBlockIndex; // last read, for simple caching
146 unsigned char* lastBlockData;
147
148 std::vector<unsigned long> sb_blocks; // blocks for "small" files
149
150 std::list<Stream*> streams;
151
152 StorageIO( Storage* storage, const char* filename );
153 ~StorageIO();
154
155 bool open();
156 void close();
157 void flush();
158 void load();
159 void create();
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& );
175
176};
177
178class StreamIO
179{
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 void seek( unsigned long pos );
191 unsigned long tell();
192 int getch();
193 unsigned long read( unsigned char* data, unsigned long maxlen );
194 unsigned long read( unsigned long pos, unsigned char* data, unsigned long maxlen );
195
196
197 private:
198 std::vector<unsigned long> blocks;
199
200 // no copy or assign
201 StreamIO( const StreamIO& );
202 StreamIO& operator=( const StreamIO& );
203
204 // pointer for read
205 unsigned long m_pos;
206
207 // simple cache system to speed-up getch()
208 unsigned char* cache_data;
209 unsigned long cache_size;
210 unsigned long cache_pos;
211 void updateCache();
212};
213
214} // namespace POLE
215
216using namespace POLE;
217
218static inline unsigned long readU16( const unsigned char* ptr )
219{
220 return ptr[0]+(ptr[1]<<8);
221}
222
223static inline unsigned long readU32( const unsigned char* ptr )
224{
225 return ptr[0]+(ptr[1]<<8)+(ptr[2]<<16)+(ptr[3]<<24);
226}
227
228static inline void writeU16( unsigned char* ptr, unsigned long data )
229{
230 ptr[0] = (unsigned char)(data & 0xff);
231 ptr[1] = (unsigned char)((data >> 8) & 0xff);
232}
233
234static inline void writeU32( unsigned char* ptr, unsigned long data )
235{
236 ptr[0] = (unsigned char)(data & 0xff);
237 ptr[1] = (unsigned char)((data >> 8) & 0xff);
238 ptr[2] = (unsigned char)((data >> 16) & 0xff);
239 ptr[3] = (unsigned char)((data >> 24) & 0xff);
240}
241
242static const unsigned char pole_magic[] =
243 { 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1 };
244
245// =========== Header ==========
246
247Header::Header()
248{
249 b_shift = 9;
250 s_shift = 6;
251 num_bat = 0;
252 dirent_start = 0;
253 threshold = 4096;
254 sbat_start = 0;
255 num_sbat = 0;
256 mbat_start = 0;
257 num_mbat = 0;
258
259 for( unsigned i = 0; i < 8; i++ )
260 id[i] = pole_magic[i];
261 for( unsigned i=0; i<109; i++ )
262 bb_blocks[i] = AllocTable::Avail;
263}
264
265bool Header::valid()
266{
267 if( threshold != 4096 ) return false;
268 if( num_bat == 0 ) return false;
269 if( (num_bat > 109) && (num_bat > (num_mbat * 127) + 109)) return false;
270 if( (num_bat < 109) && (num_mbat != 0) ) return false;
271 if( s_shift > b_shift ) return false;
272 if( b_shift <= 6 ) return false;
273 if( b_shift >=31 ) return false;
274
275 return true;
276}
277
278void Header::load( const unsigned char* buffer )
279{
280 b_shift = readU16( buffer + 0x1e );
281 s_shift = readU16( buffer + 0x20 );
282 num_bat = readU32( buffer + 0x2c );
283 dirent_start = readU32( buffer + 0x30 );
284 threshold = readU32( buffer + 0x38 );
285 sbat_start = readU32( buffer + 0x3c );
286 num_sbat = readU32( buffer + 0x40 );
287 mbat_start = readU32( buffer + 0x44 );
288 num_mbat = readU32( buffer + 0x48 );
289
290 for( unsigned i = 0; i < 8; i++ )
291 id[i] = buffer[i];
292 for( unsigned i=0; i<109; i++ )
293 bb_blocks[i] = readU32( buffer + 0x4C+i*4 );
294}
295
296void Header::save( unsigned char* buffer )
297{
298 memset( buffer, 0, 0x4c );
299 memcpy( buffer, pole_magic, 8 ); // ole signature
300 writeU32( buffer + 8, 0 ); // unknown
301 writeU32( buffer + 12, 0 ); // unknown
302 writeU32( buffer + 16, 0 ); // unknown
303 writeU16( buffer + 24, 0x003e ); // revision ?
304 writeU16( buffer + 26, 3 ); // version ?
305 writeU16( buffer + 28, 0xfffe ); // unknown
306 writeU16( buffer + 0x1e, b_shift );
307 writeU16( buffer + 0x20, s_shift );
308 writeU32( buffer + 0x2c, num_bat );
309 writeU32( buffer + 0x30, dirent_start );
310 writeU32( buffer + 0x38, threshold );
311 writeU32( buffer + 0x3c, sbat_start );
312 writeU32( buffer + 0x40, num_sbat );
313 writeU32( buffer + 0x44, mbat_start );
314 writeU32( buffer + 0x48, num_mbat );
315
316 for( unsigned i=0; i<109; i++ )
317 writeU32( buffer + 0x4C+i*4, bb_blocks[i] );
318}
319
320void Header::debug()
321{
322 std::cout << std::endl;
323 std::cout << "b_shift " << b_shift << std::endl;
324 std::cout << "s_shift " << s_shift << std::endl;
325 std::cout << "num_bat " << num_bat << std::endl;
326 std::cout << "dirent_start " << dirent_start << std::endl;
327 std::cout << "threshold " << threshold << std::endl;
328 std::cout << "sbat_start " << sbat_start << std::endl;
329 std::cout << "num_sbat " << num_sbat << std::endl;
330 std::cout << "mbat_start " << mbat_start << std::endl;
331 std::cout << "num_mbat " << num_mbat << std::endl;
332
333 unsigned s = (num_bat<=109) ? num_bat : 109;
334 std::cout << "bat blocks: ";
335 for( unsigned i = 0; i < s; i++ )
336 std::cout << bb_blocks[i] << " ";
337 std::cout << std::endl;
338}
339
340// =========== AllocTable ==========
341
342const unsigned AllocTable::Avail = 0xffffffff;
343const unsigned AllocTable::Eof = 0xfffffffe;
344const unsigned AllocTable::Bat = 0xfffffffd;
345const unsigned AllocTable::MetaBat = 0xfffffffc;
346
347AllocTable::AllocTable()
348{
349 blockSize = 4096;
350 // initial size
351 resize( 128 );
352}
353
354unsigned long AllocTable::count()
355{
356 return data.size();
357}
358
359void AllocTable::resize( unsigned long newsize )
360{
361 unsigned oldsize = data.size();
362 data.resize( newsize );
363 if( newsize > oldsize )
364 for( unsigned i = oldsize; i<newsize; i++ )
365 data[i] = Avail;
366}
367
368// make sure there're still free blocks
369void AllocTable::preserve( unsigned long n )
370{
371 std::vector<unsigned long> pre;
372 for( unsigned i=0; i < n; i++ )
373 pre.push_back( unused() );
374}
375
376unsigned long AllocTable::operator[]( unsigned long index )
377{
378 unsigned long result;
379 result = data[index];
380 return result;
381}
382
383void AllocTable::set( unsigned long index, unsigned long value )
384{
385 if( index >= count() ) resize( index + 1);
386 data[ index ] = value;
387}
388
389void AllocTable::setChain( std::vector<unsigned long> chain )
390{
391 if( chain.size() )
392 {
393 for( unsigned i=0; i<chain.size()-1; i++ )
394 set( chain[i], chain[i+1] );
395 set( chain[ chain.size()-1 ], AllocTable::Eof );
396 }
397}
398
399// follow
400std::vector<unsigned long> AllocTable::follow( unsigned long start )
401{
402 std::vector<unsigned long> chain;
403
404 if( start >= count() ) return chain;
405
406 unsigned long p = start;
407 while( p < count() )
408 {
409 if( p == (unsigned long)Eof ) break;
410 if( p == (unsigned long)Bat ) break;
411 if( p == (unsigned long)MetaBat ) break;
412 if( p >= count() ) break;
413 chain.push_back( p );
414 if( data[p] >= count() ) break;
415 p = data[ p ];
416 }
417
418 return chain;
419}
420
421unsigned AllocTable::unused()
422{
423 // find first available block
424 for( unsigned i = 0; i < data.size(); i++ )
425 if( data[i] == Avail )
426 return i;
427
428 // completely full, so enlarge the table
429 unsigned block = data.size();
430 resize( data.size()+10 );
431 return block;
432}
433
434void AllocTable::load( const unsigned char* buffer, unsigned len )
435{
436 resize( len / 4 );
437 for( unsigned i = 0; i < count(); i++ )
438 set( i, readU32( buffer + i*4 ) );
439}
440
441// return space required to save this dirtree
442unsigned AllocTable::size()
443{
444 return count() * 4;
445}
446
447void AllocTable::save( unsigned char* buffer )
448{
449 for( unsigned i = 0; i < count(); i++ )
450 writeU32( buffer + i*4, data[i] );
451}
452
453void AllocTable::debug()
454{
455 std::cout << "block size " << data.size() << std::endl;
456 for( unsigned i=0; i< data.size(); i++ )
457 {
458 if( data[i] == Avail ) continue;
459 std::cout << i << ": ";
460 if( data[i] == Eof ) std::cout << "[eof]";
461 else if( data[i] == Bat ) std::cout << "[bat]";
462 else if( data[i] == MetaBat ) std::cout << "[metabat]";
463 else std::cout << data[i];
464 std::cout << std::endl;
465 }
466}
467
468// =========== DirTree ==========
469
470const unsigned DirTree::End = 0xffffffff;
471
472DirTree::DirTree()
473{
474 clear();
475}
476
477void DirTree::clear()
478{
479 // leave only root entry
480 entries.resize( 1 );
481 entries[0].valid = true;
482 entries[0].name = "Root Entry";
483 entries[0].dir = true;
484 entries[0].size = 0;
485 entries[0].start = End;
486 entries[0].prev = End;
487 entries[0].next = End;
488 entries[0].child = End;
489}
490
491unsigned DirTree::entryCount()
492{
493 return entries.size();
494}
495
496DirEntry* DirTree::entry( unsigned index )
497{
498 if( index >= entryCount() ) return (DirEntry*) 0;
499 return &entries[ index ];
500}
501
502int DirTree::indexOf( DirEntry* e )
503{
504 for( unsigned i = 0; i < entryCount(); i++ )
505 if( entry( i ) == e ) return i;
506
507 return -1;
508}
509
510int DirTree::parent( unsigned index )
511{
512 // brute-force, basically we iterate for each entries, find its children
513 // and check if one of the children is 'index'
514 for( unsigned j=0; j<entryCount(); j++ )
515 {
516 std::vector<unsigned> chi = children( j );
517 for( unsigned i=0; i<chi.size();i++ )
518 if( chi[i] == index )
519 return j;
520 }
521
522 return -1;
523}
524
525std::string DirTree::fullName( unsigned index )
526{
527 // don't use root name ("Root Entry"), just give "/"
528 if( index == 0 ) return "/";
529
530 std::string result = entry( index )->name;
531 result.insert( 0, "/" );
532 int p = parent( index );
533 DirEntry * _entry = 0;
534 while( p > 0 )
535 {
536 _entry = entry( p );
537 if (_entry->dir && _entry->valid)
538 {
539 result.insert( 0, _entry->name);
540 result.insert( 0, "/" );
541 }
542 --p;
543 index = p;
544 if( index <= 0 ) break;
545 }
546 return result;
547}
548
549// given a fullname (e.g "/ObjectPool/_1020961869"), find the entry
550// if not found and create is false, return 0
551// if create is true, a new entry is returned
552DirEntry* DirTree::entry( const std::string& name, bool create )
553{
554 if( !name.length() ) return (DirEntry*)0;
555
556 // quick check for "/" (that's root)
557 if( name == "/" ) return entry( 0 );
558
559 // split the names, e.g "/ObjectPool/_1020961869" will become:
560 // "ObjectPool" and "_1020961869"
561 std::list<std::string> names;
562 std::string::size_type start = 0, end = 0;
563 if( name[0] == '/' ) start++;
564 while( start < name.length() )
565 {
566 end = name.find_first_of( '/', start );
567 if( end == std::string::npos ) end = name.length();
568 names.push_back( name.substr( start, end-start ) );
569 start = end+1;
570 }
571
572 // start from root
573 int index = 0 ;
574
575 // trace one by one
576 std::list<std::string>::iterator it;
577
578 for( it = names.begin(); it != names.end(); ++it )
579 {
580 // find among the children of index
581 std::vector<unsigned> chi = children( index );
582 unsigned child = 0;
583 for( unsigned i = 0; i < chi.size(); i++ )
584 {
585 DirEntry* ce = entry( chi[i] );
586 if( ce )
587 if( ce->valid && ( ce->name.length()>1 ) )
588 if( ce->name == *it )
589 child = chi[i];
590 }
591
592 // traverse to the child
593 if( child > 0 ) index = child;
594 else
595 {
596 // not found among children
597 if( !create ) return (DirEntry*)0;
598
599 // create a new entry
600 unsigned parent = index;
601 entries.push_back( DirEntry() );
602 index = entryCount()-1;
603 DirEntry* e = entry( index );
604 e->valid = true;
605 e->name = *it;
606 e->dir = false;
607 e->size = 0;
608 e->start = 0;
609 e->child = End;
610 e->prev = End;
611 e->next = entry(parent)->child;
612 entry(parent)->child = index;
613 }
614 }
615
616 return entry( index );
617}
618
619// helper function: recursively find siblings of index
620void dirtree_find_siblings( DirTree* dirtree, std::vector<unsigned>& result,
621 unsigned index )
622{
623 DirEntry* e = dirtree->entry( index );
624 if( !e ) return;
625 if( !e->valid ) return;
626
627 // prevent infinite loop
628 for( unsigned i = 0; i < result.size(); i++ )
629 if( result[i] == index ) return;
630
631 // add myself
632 result.push_back( index );
633
634 // visit previous sibling, don't go infinitely
635 unsigned prev = e->prev;
636 if( ( prev > 0 ) && ( prev < dirtree->entryCount() ) )
637 {
638 for( unsigned i = 0; i < result.size(); i++ )
639 if( result[i] == prev ) prev = 0;
640 if( prev ) dirtree_find_siblings( dirtree, result, prev );
641 }
642
643 // visit next sibling, don't go infinitely
644 unsigned next = e->next;
645 if( ( next > 0 ) && ( next < dirtree->entryCount() ) )
646 {
647 for( unsigned i = 0; i < result.size(); i++ )
648 if( result[i] == next ) next = 0;
649 if( next ) dirtree_find_siblings( dirtree, result, next );
650 }
651}
652
653std::vector<unsigned> DirTree::children( unsigned index )
654{
655 std::vector<unsigned> result;
656
657 DirEntry* e = entry( index );
658 if( e ) if( e->valid && e->child < entryCount() )
659 dirtree_find_siblings( this, result, e->child );
660
661 return result;
662}
663
664void DirTree::load( unsigned char* buffer, unsigned size )
665{
666 entries.clear();
667
668 for( unsigned i = 0; i < size/128; i++ )
669 {
670 unsigned p = i * 128;
671
672 // would be < 32 if first char in the name isn't printable
673 unsigned prefix = 32;
674
675 // parse name of this entry, which stored as Unicode 16-bit
676 std::string name;
677 int name_len = readU16( buffer + 0x40+p );
678 if( name_len > 64 ) name_len = 64;
679 for( int j=0; ( buffer[j+p]) && (j<name_len); j+= 2 )
680 name.append( 1, buffer[j+p] );
681
682 // first char isn't printable ? remove it...
683 if( buffer[p] < 32 )
684 {
685 prefix = buffer[0];
686 name.erase( 0,1 );
687 }
688
689 // 2 = file (aka stream), 1 = directory (aka storage), 5 = root
690 unsigned type = buffer[ 0x42 + p];
691
692 DirEntry e;
693 e.valid = true;
694 e.name = name;
695 e.start = readU32( buffer + 0x74+p );
696 e.size = readU32( buffer + 0x78+p );
697 e.prev = readU32( buffer + 0x44+p );
698 e.next = readU32( buffer + 0x48+p );
699 e.child = readU32( buffer + 0x4C+p );
700 e.dir = ( type!=2 );
701
702 // sanity checks
703 if( (type != 2) && (type != 1 ) && (type != 5 ) ) e.valid = false;
704 if( name_len < 1 ) e.valid = false;
705
706 entries.push_back( e );
707 }
708}
709
710// return space required to save this dirtree
711unsigned DirTree::size()
712{
713 return entryCount() * 128;
714}
715
716void DirTree::save( unsigned char* buffer )
717{
718 memset( buffer, 0, size() );
719
720 // root is fixed as "Root Entry"
721 DirEntry* root = entry( 0 );
722 std::string name = "Root Entry";
723 for( unsigned j = 0; j < name.length(); j++ )
724 buffer[ j*2 ] = name[j];
725 writeU16( buffer + 0x40, name.length()*2 + 2 );
726 writeU32( buffer + 0x74, 0xffffffff );
727 writeU32( buffer + 0x78, 0 );
728 writeU32( buffer + 0x44, 0xffffffff );
729 writeU32( buffer + 0x48, 0xffffffff );
730 writeU32( buffer + 0x4c, root->child );
731 buffer[ 0x42 ] = 5;
732 buffer[ 0x43 ] = 1;
733
734 for( unsigned i = 1; i < entryCount(); i++ )
735 {
736 DirEntry* e = entry( i );
737 if( !e ) continue;
738 if( e->dir )
739 {
740 e->start = 0xffffffff;
741 e->size = 0;
742 }
743
744 // max length for name is 32 chars
745 std::string name = e->name;
746 if( name.length() > 32 )
747 name.erase( 32, name.length() );
748
749 // write name as Unicode 16-bit
750 for( unsigned j = 0; j < name.length(); j++ )
751 buffer[ i*128 + j*2 ] = name[j];
752
753 writeU16( buffer + i*128 + 0x40, name.length()*2 + 2 );
754 writeU32( buffer + i*128 + 0x74, e->start );
755 writeU32( buffer + i*128 + 0x78, e->size );
756 writeU32( buffer + i*128 + 0x44, e->prev );
757 writeU32( buffer + i*128 + 0x48, e->next );
758 writeU32( buffer + i*128 + 0x4c, e->child );
759 buffer[ i*128 + 0x42 ] = e->dir ? 1 : 2;
760 buffer[ i*128 + 0x43 ] = 1; // always black
761 }
762}
763
764void DirTree::debug()
765{
766 for( unsigned i = 0; i < entryCount(); i++ )
767 {
768 DirEntry* e = entry( i );
769 if( !e ) continue;
770 std::cout << i << ": ";
771 if( !e->valid ) std::cout << "INVALID ";
772 std::cout << e->name << " ";
773 if( e->dir ) std::cout << "(Dir) ";
774 else std::cout << "(File) ";
775 std::cout << e->size << " ";
776 std::cout << "s:" << e->start << " ";
777 std::cout << "(";
778 if( e->child == End ) std::cout << "-"; else std::cout << e->child;
779 std::cout << " ";
780 if( e->prev == End ) std::cout << "-"; else std::cout << e->prev;
781 std::cout << ":";
782 if( e->next == End ) std::cout << "-"; else std::cout << e->next;
783 std::cout << ")";
784 std::cout << std::endl;
785 }
786}
787
788// =========== StorageIO ==========
789
790StorageIO::StorageIO( Storage* st, const char* fname )
791{
792 storage = st;
793 filename = fname;
794 result = Storage::Ok;
795 opened = false;
796
797 header = new Header();
798 dirtree = new DirTree();
799 bbat = new AllocTable();
800 sbat = new AllocTable();
801
802 lastBlockIndex = 0;
803 lastBlockData = 0;
804
805 filesize = 0;
806 bbat->blockSize = 1 << header->b_shift;
807 sbat->blockSize = 1 << header->s_shift;
808}
809
810StorageIO::~StorageIO()
811{
812 if( opened ) close();
813
814 delete [] lastBlockData;
815 delete sbat;
816 delete bbat;
817 delete dirtree;
818 delete header;
819}
820
821bool StorageIO::open()
822{
823 // already opened ? close first
824 if( opened ) close();
825
826 load();
827
828 return result == Storage::Ok;
829}
830
831void StorageIO::load()
832{
833 unsigned char* buffer = 0;
834 unsigned long buflen = 0;
835 std::vector<unsigned long> blocks;
836
837 // open the file, check for error
838 result = Storage::OpenFailed;
839 file.open( filename.c_str(), std::ios::binary | std::ios::in );
840 if( !file.good() ) return;
841
842 // find size of input file
843 file.seekg( 0, std::ios::end );
844 filesize = file.tellg();
845
846 // load header
847 buffer = new unsigned char[512];
848 file.seekg( 0 );
849 file.read( (char*)buffer, 512 );
850 header->load( buffer );
851 delete[] buffer;
852
853 // check OLE magic id
854 result = Storage::NotOLE;
855 for( unsigned i=0; i<8; i++ )
856 if( header->id[i] != pole_magic[i] )
857 return;
858
859 // sanity checks
860 result = Storage::BadOLE;
861 if( !header->valid() ) return;
862 if( header->threshold != 4096 ) return;
863
864 // important block size
865 bbat->blockSize = 1 << header->b_shift;
866 sbat->blockSize = 1 << header->s_shift;
867
868 // find blocks allocated to store big bat
869 // the first 109 blocks are in header, the rest in meta bat
870 blocks.clear();
871 blocks.resize( header->num_bat );
872 for( unsigned i = 0; i < 109; i++ )
873 if( i >= header->num_bat ) break;
874 else blocks[i] = header->bb_blocks[i];
875 if( (header->num_bat > 109) && (header->num_mbat > 0) )
876 {
877 unsigned char* buffer2 = new unsigned char[ bbat->blockSize ];
878 unsigned k = 109;
879 unsigned mblock = header->mbat_start;
880 for( unsigned r = 0; r < header->num_mbat; r++ )
881 {
882 loadBigBlock( mblock, buffer2, bbat->blockSize );
883 for( unsigned s=0; s < bbat->blockSize-4; s+=4 )
884 {
885 if( k >= header->num_bat ) break;
886 else blocks[k++] = readU32( buffer2 + s );
887 }
888 mblock = readU32( buffer2 + bbat->blockSize-4 );
889 }
890 delete[] buffer2;
891 }
892
893 // load big bat
894 buflen = blocks.size()*bbat->blockSize;
895 if( buflen > 0 )
896 {
897 buffer = new unsigned char[ buflen ];
898 loadBigBlocks( blocks, buffer, buflen );
899 bbat->load( buffer, buflen );
900 delete[] buffer;
901 }
902
903 // load small bat
904 blocks.clear();
905 blocks = bbat->follow( header->sbat_start );
906 buflen = blocks.size()*bbat->blockSize;
907 if( buflen > 0 )
908 {
909 buffer = new unsigned char[ buflen ];
910 loadBigBlocks( blocks, buffer, buflen );
911 sbat->load( buffer, buflen );
912 delete[] buffer;
913 }
914
915 // load directory tree
916 blocks.clear();
917 blocks = bbat->follow( header->dirent_start );
918 buflen = blocks.size()*bbat->blockSize;
919 buffer = new unsigned char[ buflen ];
920 loadBigBlocks( blocks, buffer, buflen );
921 dirtree->load( buffer, buflen );
922 unsigned sb_start = readU32( buffer + 0x74 );
923 delete[] buffer;
924
925 // fetch block chain as data for small-files
926 sb_blocks = bbat->follow( sb_start ); // small files
927
928 // for troubleshooting, just enable this block
929#if 0
930 header->debug();
931 sbat->debug();
932 bbat->debug();
933 dirtree->debug();
934#endif
935
936 // so far so good
937 result = Storage::Ok;
938 opened = true;
939}
940
941void StorageIO::create()
942{
943 // std::cout << "Creating " << filename << std::endl;
944
945 file.open( filename.c_str(), std::ios::out|std::ios::binary );
946 if( !file.good() )
947 {
948 std::cerr << "Can't create " << filename << std::endl;
949 result = Storage::OpenFailed;
950 return;
951 }
952
953 // so far so good
954 opened = true;
955 result = Storage::Ok;
956}
957
958void StorageIO::flush()
959{
960 /* Note on Microsoft implementation:
961 - directory entries are stored in the last block(s)
962 - BATs are as second to the last
963 - Meta BATs are third to the last
964 */
965}
966
967void StorageIO::close()
968{
969 if( !opened ) return;
970
971 file.close();
972 opened = false;
973
974 std::list<Stream*>::iterator it;
975 for( it = streams.begin(); it != streams.end(); ++it )
976 delete *it;
977}
978
979StreamIO* StorageIO::streamIO( const std::string& name )
980{
981 // sanity check
982 if( !name.length() ) return (StreamIO*)0;
983
984 // search in the entries
985 DirEntry* entry = dirtree->entry( name );
986 //if( entry) std::cout << "FOUND\n";
987 if( !entry ) return (StreamIO*)0;
988 //if( !entry->dir ) std::cout << " NOT DIR\n";
989 if( entry->dir ) return (StreamIO*)0;
990
991 StreamIO* result = new StreamIO( this, entry );
992 result->fullName = name;
993
994 return result;
995}
996
997unsigned long StorageIO::loadBigBlocks( std::vector<unsigned long> blocks,
998 unsigned char* data, unsigned long maxlen )
999{
1000 // sentinel
1001 if( !data ) return 0;
1002 if( !file.good() ) return 0;
1003 if( blocks.size() < 1 ) return 0;
1004 if( maxlen == 0 ) return 0;
1005
1006 // read block one by one, seems fast enough
1007 unsigned long bytes = 0;
1008 for( unsigned long i=0; (i < blocks.size() ) && ( bytes<maxlen ); i++ )
1009 {
1010 unsigned long block = blocks[i];
1011 unsigned long pos = bbat->blockSize * ( block+1 );
1012 unsigned long p = (bbat->blockSize < maxlen-bytes) ? bbat->blockSize : maxlen-bytes;
1013 if( pos + p > filesize ) p = filesize - pos;
1014 file.seekg( pos );
1015 file.read( (char*)data + bytes, p );
1016 bytes += p;
1017 }
1018
1019 return bytes;
1020}
1021
1022// this will avoid reading the same big block from the disk
1023#define POLE_CACHE_BLOCK
1024
1025unsigned long StorageIO::loadBigBlock( unsigned long block,
1026 unsigned char* data, unsigned long maxlen )
1027{
1028 // sentinel
1029 if( !data ) return 0;
1030 if( !file.good() ) return 0;
1031
1032#ifdef POLE_CACHE_BLOCK
1033 // just before, we also did read this block
1034 // so just reuse from cached data
1035 if( block == lastBlockIndex )
1036 if( lastBlockData) if( maxlen <= bbat->blockSize )
1037 {
1038 memcpy( data, lastBlockData, maxlen );
1039 return maxlen;
1040 }
1041#endif
1042
1043 // wraps call for loadBigBlocks
1044 std::vector<unsigned long> blocks;
1045 blocks.resize( 1 );
1046 blocks[0] = block;
1047
1048 unsigned long result = loadBigBlocks( blocks, data, maxlen );
1049
1050#ifdef POLE_CACHE_BLOCK
1051 // save cached data for future use
1052 if(maxlen == bbat->blockSize )
1053 {
1054 if( !lastBlockData )
1055 lastBlockData = new unsigned char[bbat->blockSize];
1056 memcpy(lastBlockData, data, bbat->blockSize);
1057 lastBlockIndex = block;
1058 }
1059#endif
1060
1061 return result;
1062}
1063
1064// return number of bytes which has been read
1065unsigned long StorageIO::loadSmallBlocks( std::vector<unsigned long> blocks,
1066 unsigned char* data, unsigned long maxlen )
1067{
1068 // sentinel
1069 if( !data ) return 0;
1070 if( !file.good() ) return 0;
1071 if( blocks.size() < 1 ) return 0;
1072 if( maxlen == 0 ) return 0;
1073
1074 // our own local buffer
1075 unsigned char* buf = new unsigned char[ bbat->blockSize ];
1076
1077 // read small block one by one
1078 unsigned long bytes = 0;
1079 for( unsigned long i=0; ( i<blocks.size() ) && ( bytes<maxlen ); i++ )
1080 {
1081 unsigned long block = blocks[i];
1082
1083 // find where the small-block exactly is
1084 unsigned long pos = block * sbat->blockSize;
1085 unsigned long bbindex = pos / bbat->blockSize;
1086 if( bbindex >= sb_blocks.size() ) break;
1087
1088 loadBigBlock( sb_blocks[ bbindex ], buf, bbat->blockSize );
1089
1090 // copy the data
1091 unsigned offset = pos % bbat->blockSize;
1092 unsigned long p = (maxlen-bytes < bbat->blockSize-offset ) ? maxlen-bytes : bbat->blockSize-offset;
1093 p = (sbat->blockSize<p ) ? sbat->blockSize : p;
1094 memcpy( data + bytes, buf + offset, p );
1095 bytes += p;
1096 }
1097
1098 delete[] buf;
1099
1100 return bytes;
1101}
1102
1103unsigned long StorageIO::loadSmallBlock( unsigned long block,
1104 unsigned char* data, unsigned long maxlen )
1105{
1106 // sentinel
1107 if( !data ) return 0;
1108 if( !file.good() ) return 0;
1109
1110 // wraps call for loadSmallBlocks
1111 std::vector<unsigned long> blocks;
1112 blocks.resize( 1 );
1113 blocks.assign( 1, block );
1114
1115 return loadSmallBlocks( blocks, data, maxlen );
1116}
1117
1118// =========== StreamIO ==========
1119
1120StreamIO::StreamIO( StorageIO* s, DirEntry* e)
1121{
1122 io = s;
1123 entry = e;
1124 eof = false;
1125 fail = false;
1126
1127 m_pos = 0;
1128
1129 if( entry->size >= io->header->threshold )
1130 blocks = io->bbat->follow( entry->start );
1131 else
1132 blocks = io->sbat->follow( entry->start );
1133
1134 // prepare cache
1135 cache_pos = 0;
1136 cache_size = 4096; // optimal ?
1137 cache_data = new unsigned char[cache_size];
1138 updateCache();
1139}
1140
1141// FIXME tell parent we're gone
1142StreamIO::~StreamIO()
1143{
1144 delete[] cache_data;
1145}
1146
1147void StreamIO::seek( unsigned long pos )
1148{
1149 m_pos = pos;
1150}
1151
1152unsigned long StreamIO::tell()
1153{
1154 return m_pos;
1155}
1156
1157int StreamIO::getch()
1158{
1159 // past end-of-file ?
1160 if( m_pos > entry->size ) return -1;
1161
1162 // need to update cache ?
1163 if( !cache_size || ( m_pos < cache_pos ) ||
1164 ( m_pos >= cache_pos + cache_size ) )
1165 updateCache();
1166
1167 // something bad if we don't get good cache
1168 if( !cache_size ) return -1;
1169
1170 int data = cache_data[m_pos - cache_pos];
1171 m_pos++;
1172
1173 return data;
1174}
1175
1176unsigned long StreamIO::read( unsigned long pos, unsigned char* data, unsigned long maxlen )
1177{
1178 // sanity checks
1179 if( !data ) return 0;
1180 if( maxlen == 0 ) return 0;
1181
1182 unsigned long totalbytes = 0;
1183
1184 if ( entry->size < io->header->threshold )
1185 {
1186 // small file
1187 unsigned long index = pos / io->sbat->blockSize;
1188
1189 if( index >= blocks.size() ) return 0;
1190
1191 unsigned char* buf = new unsigned char[ io->sbat->blockSize ];
1192 unsigned long offset = pos % io->sbat->blockSize;
1193 while( totalbytes < maxlen )
1194 {
1195 if( index >= blocks.size() ) break;
1196 io->loadSmallBlock( blocks[index], buf, io->bbat->blockSize );
1197 unsigned long count = io->sbat->blockSize - offset;
1198 if( count > maxlen-totalbytes ) count = maxlen-totalbytes;
1199 memcpy( data+totalbytes, buf + offset, count );
1200 totalbytes += count;
1201 offset = 0;
1202 index++;
1203 }
1204 delete[] buf;
1205
1206 }
1207 else
1208 {
1209 // big file
1210 unsigned long index = pos / io->bbat->blockSize;
1211
1212 // sanity check
1213 if( index >= blocks.size() ) return 0;
1214
1215 unsigned char* buf = new unsigned char[ io->bbat->blockSize ];
1216 unsigned long offset = pos % io->bbat->blockSize;
1217 while( totalbytes < maxlen )
1218 {
1219 if( index >= blocks.size() ) break;
1220 io->loadBigBlock( blocks[index], buf, io->bbat->blockSize );
1221 unsigned long count = io->bbat->blockSize - offset;
1222 if( count > maxlen-totalbytes ) count = maxlen-totalbytes;
1223 memcpy( data+totalbytes, buf + offset, count );
1224 totalbytes += count;
1225 index++;
1226 offset = 0;
1227 }
1228 delete [] buf;
1229
1230 }
1231
1232 return totalbytes;
1233}
1234
1235unsigned long StreamIO::read( unsigned char* data, unsigned long maxlen )
1236{
1237 unsigned long bytes = read( tell(), data, maxlen );
1238 m_pos += bytes;
1239 return bytes;
1240}
1241
1242void StreamIO::updateCache()
1243{
1244 // sanity check
1245 if( !cache_data ) return;
1246
1247 cache_pos = m_pos - ( m_pos % cache_size );
1248 unsigned long bytes = cache_size;
1249 if( cache_pos + bytes > entry->size ) bytes = entry->size - cache_pos;
1250 cache_size = read( cache_pos, cache_data, bytes );
1251}
1252
1253
1254// =========== Storage ==========
1255
1256Storage::Storage( const char* filename )
1257{
1258 io = new StorageIO( this, filename );
1259}
1260
1261Storage::~Storage()
1262{
1263 delete io;
1264}
1265
1266int Storage::result()
1267{
1268 return io->result;
1269}
1270
1271bool Storage::open()
1272{
1273 return io->open();
1274}
1275
1276void Storage::close()
1277{
1278 io->close();
1279}
1280
1281std::list<std::string> Storage::entries( const std::string& path )
1282{
1283 std::list<std::string> result;
1284 DirTree* dt = io->dirtree;
1285 DirEntry* e = dt->entry( path, false );
1286 if( e && e->dir )
1287 {
1288 unsigned parent = dt->indexOf( e );
1289 std::vector<unsigned> children = dt->children( parent );
1290 for( unsigned i = 0; i < children.size(); i++ )
1291 result.push_back( dt->entry( children[i] )->name );
1292 }
1293
1294 return result;
1295}
1296
1297bool Storage::isDirectory( const std::string& name )
1298{
1299 DirEntry* e = io->dirtree->entry( name, false );
1300 return e ? e->dir : false;
1301}
1302
1303// =========== Stream ==========
1304
1305Stream::Stream( Storage* storage, const std::string& name )
1306{
1307 io = storage->io->streamIO( name );
1308}
1309
1310// FIXME tell parent we're gone
1311Stream::~Stream()
1312{
1313 delete io;
1314}
1315
1316std::string Stream::fullName()
1317{
1318 return io ? io->fullName : std::string();
1319}
1320
1321unsigned long Stream::tell()
1322{
1323 return io ? io->tell() : 0;
1324}
1325
1326void Stream::seek( unsigned long newpos )
1327{
1328 if( io ) io->seek( newpos );
1329}
1330
1331unsigned long Stream::size()
1332{
1333 return io ? io->entry->size : 0;
1334}
1335
1336int Stream::getch()
1337{
1338 return io ? io->getch() : 0;
1339}
1340
1341unsigned long Stream::read( unsigned char* data, unsigned long maxlen )
1342{
1343 return io ? io->read( data, maxlen ) : 0;
1344}
1345
1346bool Stream::eof()
1347{
1348 return io ? io->eof : false;
1349}
1350
1351bool Stream::fail()
1352{
1353 return io ? io->fail : true;
1354}