39 std::vector<Entry*> children;
43 Entry(
const Entry& );
44 Entry& operator=(
const Entry& );
61 void resize(
unsigned long newsize );
63 void set(
unsigned long index,
unsigned long val );
65 std::vector<unsigned long> follow(
unsigned long start );
67 unsigned long operator[](
unsigned long index );
71 std::vector<unsigned long> data;
73 AllocTable(
const AllocTable& );
75 AllocTable& operator=(
const AllocTable& );
98 unsigned long filesize;
101 unsigned char header[512];
104 unsigned char magic[8];
125 std::vector<unsigned long> sb_blocks;
131 unsigned dirent_start;
140 StorageIO( Storage* storage,
const char* fileName,
int mode );
147 unsigned long loadBigBlocks( std::vector<unsigned long> blocks,
unsigned char* buffer,
unsigned long maxlen );
149 unsigned long loadBigBlock(
unsigned long block,
unsigned char* buffer,
unsigned long maxlen );
151 unsigned long loadSmallBlocks( std::vector<unsigned long> blocks,
unsigned char* buffer,
unsigned long maxlen );
153 unsigned long loadSmallBlock(
unsigned long block,
unsigned char* buffer,
unsigned long maxlen );
156 Entry* buildTree( Entry* parent,
int index,
const unsigned char* dirent );
158 std::string fullName( Entry* e );
161 Entry* entry(
const std::string& name );
171 StorageIO(
const StorageIO& );
172 StorageIO& operator=(
const StorageIO& );
180 StreamIO( StorageIO* io, Entry* entry );
184 unsigned long size();
186 void seek(
unsigned long pos );
188 unsigned long tell();
192 unsigned long read(
unsigned char* data,
unsigned long maxlen );
194 unsigned long read(
unsigned long pos,
unsigned char* data,
unsigned long maxlen );
203 std::vector<unsigned long> blocks;
206 StreamIO(
const StreamIO& );
207 StreamIO& operator=(
const StreamIO& );
213 unsigned char* cache_data;
214 unsigned long cache_size;
215 unsigned long cache_pos;
224static inline unsigned long readU16(
const unsigned char* ptr )
226 return ptr[0]+(ptr[1]<<8);
229static inline unsigned long readU32(
const unsigned char* ptr )
231 return ptr[0]+(ptr[1]<<8)+(ptr[2]<<16)+(ptr[3]<<24);
234static inline void writeU16(
unsigned char* ptr,
unsigned long data )
236 ptr[0] = data & 0xff;
237 ptr[1] = (data >> 8) & 0xff;
240static inline void writeU32(
unsigned char* ptr,
unsigned long data )
242 ptr[0] = data & 0xff;
243 ptr[1] = (data >> 8) & 0xff;
244 ptr[2] = (data >> 16) & 0xff;
245 ptr[3] = (data >> 24) & 0xff;
248static const unsigned char pole_magic[] =
249 { 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1 };
260 for(
unsigned i=0; i<children.size(); i++ )
262 Entry* entry = children[ i ];
267AllocTable::AllocTable()
272AllocTable::~AllocTable()
276unsigned long AllocTable::size()
281void AllocTable::resize(
unsigned long newsize )
283 data.resize( newsize );
286unsigned long AllocTable::operator[](
unsigned long index )
288 unsigned long result;
289 result = data[index];
293void AllocTable::set(
unsigned long index,
unsigned long value )
295 if( index >= size() ) resize( index + 1);
296 data[ index ] = value;
299std::vector<unsigned long> AllocTable::follow(
unsigned long start )
301 std::vector<unsigned long> chain;
303 if( start >= size() )
return chain;
305 unsigned long p = start;
308 if( p >= (
unsigned long)0xfffe )
break;
309 if( p >= size() )
break;
310 chain.push_back( p );
311 if( data[p] >= size() )
break;
320StorageIO::StorageIO( Storage* storage,
const char* fname,
int m ):
321 doc( storage ), filename( fname), mode( m )
324 result = Storage::Ok;
326 current_dir = (Entry*) 0L;
332 int om = std::ios::in;
333 if( mode == Storage::WriteOnly ) om = std::ios::out;
334 if( mode == Storage::ReadWrite) om = std::ios::app;
335 om |= std::ios::binary;
337 file.open( filename.c_str(), std::ios::binary | std::ios::in );
342 std::cerr <<
"Can't open " << filename <<
"\n\n";
343 result = Storage::OpenFailed;
348 result = Storage::Ok;
350 if( mode == Storage::WriteOnly ) create();
355StorageIO::~StorageIO()
357 filename = std::string();
362void StorageIO::load()
371 file.seekg( 0, std::ios::end );
372 filesize = file.tellg();
376 file.read( (
char*)header,
sizeof( header ) );
377 if( file.gcount() !=
sizeof( header ) )
379 result = Storage::NotOLE;
384 for(
unsigned i=0; i<8; i++ )
386 magic[i] = header[i];
387 if( magic[i] != pole_magic[i] )
389 result = Storage::NotOLE;
395 bb_shift = readU16( header + 0x1e );
396 sb_shift = readU16( header + 0x20 );
397 num_bat = readU32( header + 0x2c );
398 dirent_start = readU32( header + 0x30 );
399 threshold = readU32( header + 0x38 );
400 sbat_start = readU32( header + 0x3c );
401 num_sbat = readU32( header + 0x40 );
402 mbat_start = readU32( header + 0x44 );
403 num_mbat = readU32( header + 0x48 );
406 if( ( threshold != 4096 ) || ( num_bat == 0 ) ||
407 ( sb_shift > bb_shift ) || ( bb_shift <= 6 ) || ( bb_shift >=31 ) )
409 result = Storage::BadOLE;
414 bb_size = 1 << bb_shift;
415 sb_size = 1 << sb_shift;
417 std::vector<unsigned long> chain;
418 unsigned char buffer[bb_size];
421 std::vector<unsigned long> metabat( num_mbat * bb_size / 4 );
423 for(
unsigned r=0; r<num_mbat; r++ )
425 unsigned char metabuf[ bb_size ];
426 loadBigBlock( mbat_start+r, metabuf,
sizeof( metabuf ) );
427 for(
unsigned s=0; s< bb_size/4; s++ )
428 metabat[q++] = readU32( metabuf + s*4 );
433 bb.resize( num_bat * bb_size / 4 );
434 for(
unsigned long i=0; i< num_bat; i++ )
438 unsigned long block = (i<109) ? readU32( header + 0x4C+i*4 ) : metabat[i-109];
440 loadBigBlock( block, buffer, bb_size );
442 for(
unsigned m=0; m<bb_size/4; m++)
443 bb.set( i*bb_size/4 + m, readU32( buffer + m*4 ) );
448 chain = bb.follow( sbat_start );
450 for(
unsigned long i=0; i < chain.size(); i++ )
452 unsigned long block = chain[i];
453 loadBigBlock( block, buffer, bb_size );
454 for(
unsigned m=0; m<bb_size/4; m++ )
455 sb.set( i*bb_size/4 + m, readU32( buffer + m*4 ) );
459 unsigned char* dirent;
460 chain = bb.follow( dirent_start );
461 unsigned bufsize = chain.size() * bb_size;
462 dirent =
new unsigned char[bufsize];
463 loadBigBlocks( chain, dirent, bufsize );
464 root = buildTree( (Entry*)0L, 0, dirent );
467 sb_blocks = bb.follow( readU32( dirent + 0x74 ) );
475 result = Storage::Ok;
479void StorageIO::create()
481 unsigned bb_shift = 9;
482 unsigned sb_shift = 6;
483 bb_size = 1 << bb_shift;
484 sb_size = 1 << sb_shift;
489 for(
int i=0; i<8; i++ ) header[i] = pole_magic[i];
490 writeU32( header + 8, 0 );
491 writeU32( header + 12, 0 );
492 writeU32( header + 16, 0 );
493 writeU16( header + 24, 0x3B00 );
494 writeU16( header + 26, 3 );
495 writeU16( header + 28, 0xfffe );
496 writeU16( header + 30, bb_shift );
497 writeU16( header + 32, sb_shift );
498 writeU16( header + 34, 0 );
499 writeU32( header + 36, 0 );
500 writeU32( header + 40, 0 );
501 writeU32( header + 52, 0 );
502 for(
int j=0x4C; j<512; j++ ) header[j] = 0xff;
505 result = Storage::Ok;
508void StorageIO::flush()
510 if( mode == Storage::ReadOnly )
return;
513 writeU32( header + 0x30, dirent_start );
514 writeU32( header + 0x38, threshold );
515 writeU32( header + 0x3c, sbat_start );
516 writeU32( header + 0x44, mbat_start );
525unsigned long StorageIO::loadBigBlocks( std::vector<unsigned long> blocks,
526 unsigned char* data,
unsigned long maxlen )
529 if( !data )
return 0;
530 if( !file.good() )
return 0;
531 if( blocks.size() < 1 )
return 0;
532 if( maxlen == 0 )
return 0;
535 unsigned long bytes = 0;
536 for(
unsigned long i=0; (i < blocks.size() ) & ( bytes<maxlen ); i++ )
538 unsigned long block = blocks[i];
539 if( block < 0 )
continue;
540 unsigned long pos = bb_size * ( block+1 );
541 unsigned long p = (bb_size < maxlen-bytes) ? bb_size : maxlen-bytes;
542 if( pos + p > filesize ) p = filesize - pos;
544 file.read( (
char*)data + bytes, p );
551unsigned long StorageIO::loadBigBlock(
unsigned long block,
552 unsigned char* data,
unsigned long maxlen )
555 if( !data )
return 0;
556 if( !file.good() )
return 0;
557 if( block < 0 )
return 0;
560 std::vector<unsigned long> blocks;
564 return loadBigBlocks( blocks, data, maxlen );
568unsigned long StorageIO::loadSmallBlocks( std::vector<unsigned long> blocks,
569 unsigned char* data,
unsigned long maxlen )
572 if( !data )
return 0;
573 if( !file.good() )
return 0;
574 if( blocks.size() < 1 )
return 0;
575 if( maxlen == 0 )
return 0;
578 unsigned char buf[ bb_size ];
581 unsigned long bytes = 0;
582 for(
unsigned long i=0; ( i<blocks.size() ) & ( bytes<maxlen ); i++ )
584 unsigned long block = blocks[i];
585 if( block < 0 )
continue;
588 unsigned long pos = block * sb_size;
589 unsigned long bbindex = pos / bb_size;
590 if( bbindex >= sb_blocks.size() )
break;
592 loadBigBlock( sb_blocks[ bbindex ], buf, bb_size );
595 unsigned offset = pos % bb_size;
596 unsigned long p = (maxlen-bytes < bb_size-offset ) ? maxlen-bytes : bb_size-offset;
597 p = (sb_size<p ) ? sb_size : p;
598 memcpy( data + bytes, buf + offset, p );
605unsigned long StorageIO::loadSmallBlock(
unsigned long block,
606 unsigned char* data,
unsigned long maxlen )
609 if( !data )
return 0;
610 if( !file.good() )
return 0;
611 if( block < 0 )
return 0;
614 std::vector<unsigned long> blocks;
616 blocks.assign( 1, block );
618 return loadSmallBlocks( blocks, data, maxlen );
622Entry* StorageIO::buildTree( Entry* parent,
int index,
const unsigned char* dirent )
624 Entry* entry = (Entry*) 0L;
627 unsigned p = index * 128;
630 unsigned prefix = 32;
634 int name_len = readU16( dirent + 64+p );
635 for(
int j=0; ( dirent[j+p]) && (j<name_len); j+= 2 )
636 name.append( 1, dirent[j+p] );
639 if( !name.length() )
return entry;
642 if( dirent[p] < 32 ){ prefix = dirent[0]; name.erase( 0,1 ); }
646 unsigned type = dirent[ 0x42 + p];
647 if( ( type == 2 ) || ( type == 1 ) || ( type == 5 ) ) entry =
new Entry();
648 if( entry ) entry->dir = ( ( type = 1 ) || ( type == 5 ) );
651 if( !entry )
return entry;
655 entry->start = readU32( dirent + 0x74+p );
656 entry->size = readU32( dirent + 0x78+p );
659 entry->parent = parent;
660 if( parent ) parent->children.push_back( entry );
663 int prev = readU32( dirent + 0x44+p );
664 if( prev >= 0 ) buildTree( parent, prev, dirent );
667 int dir = readU32( dirent + 0x4C+p );
668 if( entry->dir && (dir > 0 ))
669 buildTree( entry, dir, dirent );
672 int next = readU32( dirent + 0x48+p );
673 if( next >= 0 ) buildTree( parent, next, dirent );
678std::string StorageIO::fullName( Entry* e )
680 if( !e )
return (
const char*) 0L;
686 result.insert( 0, e->name );
687 result.insert( 0,
"/" );
692 if( !result.length() ) result =
"/";
698Entry* StorageIO::entry(
const std::string& name )
700 Entry* entry = (Entry*) 0L;
703 if( !root )
return (Entry*) 0L;
704 if( !name.length() )
return (Entry*) 0L;
708 entry = (name[0] ==
'/' ) ? root : current_dir;
712 std::list<std::string> names;
713 std::string::size_type start = 0, end = 0;
714 while( start < name.length() )
716 end = name.find_first_of(
'/', start );
717 if( end == std::string::npos ) end = name.length();
718 names.push_back( name.substr( start, end-start ) );
722 std::list<std::string>::iterator it;
723 for( it = names.begin(); it != names.end(); ++it )
725 std::string entryname = *it;
726 Entry *child = (Entry*) 0L;
728 for(
unsigned j=0; j < entry->children.size(); j++ )
729 if( entry->children[j]->name == entryname )
730 child = entry->children[j];
731 if( !child )
return (Entry*) 0L;
740StreamIO::StreamIO( StorageIO* _io, Entry* _entry ):
741 io( _io ), entry( _entry ), m_pos( 0 ),
742 cache_data( 0 ), cache_size( 0 ), cache_pos( 0 )
744 blocks = ( entry->size >= io->threshold ) ? io->bb.follow( entry->start ) :
745 io->sb.follow( entry->start );
749 cache_data =
new unsigned char[cache_size];
759void StreamIO::seek(
unsigned long pos )
764unsigned long StreamIO::tell()
772 if( m_pos > entry->size )
return -1;
775 if( !cache_size || ( m_pos < cache_pos ) ||
776 ( m_pos >= cache_pos + cache_size ) )
780 if( !cache_size )
return -1;
782 int data = cache_data[m_pos - cache_pos];
788unsigned long StreamIO::read(
unsigned long pos,
unsigned char* data,
unsigned long maxlen )
791 if( !data )
return 0;
792 if( maxlen == 0 )
return 0;
794 unsigned long totalbytes = 0;
796 if ( entry->size < io->threshold )
799 unsigned long index = pos / io->sb_size;
801 if( index >= blocks.size() )
return 0;
803 unsigned char buf[ io->sb_size ];
804 unsigned long offset = pos % io->sb_size;
805 while( totalbytes < maxlen )
807 if( index >= blocks.size() )
break;
808 io->loadSmallBlock( blocks[index], buf, io->bb_size );
809 unsigned long count = io->sb_size - offset;
810 if( count > maxlen-totalbytes ) count = maxlen-totalbytes;
811 memcpy( data+totalbytes, buf + offset, count );
821 unsigned long index = pos / io->bb_size;
823 if( index >= blocks.size() )
return 0;
825 unsigned char buf[ io->bb_size ];
826 unsigned long offset = pos % io->bb_size;
827 while( totalbytes < maxlen )
829 if( index >= blocks.size() )
break;
830 io->loadBigBlock( blocks[index], buf, io->bb_size );
831 unsigned long count = io->bb_size - offset;
832 if( count > maxlen-totalbytes ) count = maxlen-totalbytes;
833 memcpy( data+totalbytes, buf + offset, count );
844unsigned long StreamIO::read(
unsigned char* data,
unsigned long maxlen )
846 unsigned long bytes = read( tell(), data, maxlen );
851void StreamIO::updateCache()
854 if( !cache_data )
return;
856 cache_pos = m_pos - ( m_pos % cache_size );
857 unsigned long bytes = cache_size;
858 if( cache_pos + bytes > entry->size ) bytes = entry->size - cache_pos;
859 cache_size = read( cache_pos, cache_data, bytes );
867 io = (StorageIO*) 0L;
868 result = Storage::Ok;
877bool Storage::open(
const char* fileName,
int m )
880 if( ( m != ReadOnly ) && ( m != WriteOnly ) && ( m != ReadWrite ) )
882 result = UnknownError;
886 io =
new StorageIO(
this, fileName, m );
890 return result == Storage::Ok;
895 if( io ) io->flush();
904std::list<std::string> Storage::listDirectory()
906 std::list<std::string> entries;
909 if( !io )
return entries;
910 if( !io->current_dir )
return entries;
913 if( !io->current_dir->dir )
return entries;
916 for(
unsigned i = 0; i<io->current_dir->children.size(); i++ )
918 Entry* e = io->current_dir->children[i];
919 if( e ) entries.push_back( e->name );
926bool Storage::enterDirectory(
const std::string& directory )
929 if( !io )
return false;
930 if( !io->current_dir )
return false;
933 for(
unsigned i = 0; i<io->current_dir->children.size(); i++ )
935 Entry* e = io->current_dir->children[i];
936 if( e )
if( e->name == directory )
948void Storage::leaveDirectory()
952 if( !io->current_dir )
return;
954 Entry* parent = io->current_dir->parent;
955 if( parent )
if( parent->dir )
956 io->current_dir = parent;
960std::string Storage::path()
963 if( !io )
return std::string();
964 if( !io->current_dir )
return std::string();
966 return io->fullName( io->current_dir );
969Stream* Storage::stream(
const std::string& name )
972 if( !name.length() )
return (Stream*) 0L;
973 if( !io )
return (Stream*) 0L;
976 std::string fullName = name;
977 if( name[0] !=
'/' ) fullName.insert( 0, path() +
"/" );
980 Entry* entry = io->entry( name );
981 if( !entry )
return (Stream*) 0L;
983 StreamIO* sio =
new StreamIO( io, entry );
984 Stream* s =
new Stream( sio );
991Stream::Stream( StreamIO* _io ):
1002unsigned long Stream::tell()
1004 return io ? io->tell() : 0;
1007void Stream::seek(
unsigned long newpos )
1009 if( io ) io->seek( newpos );
1012unsigned long Stream::size()
1014 return io ? io->entry->size : 0;
1019 return io ? io->getch() : -1;
1022unsigned long Stream::read(
unsigned char* data,
unsigned long maxlen )
1024 return io ? io->read( data, maxlen ) : 0;