00001
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <stdio.h>
00026 #include <ctype.h>
00027 #include <cstdlib>
00028 #include <stdlib.h>
00029 #include <string>
00030 #include <list>
00031
00032 #include "global.h"
00033
00034 #ifdef HAVE_LIMITS
00035 #include <limits>
00036 #endif
00037
00038
00039 #include <sys/stat.h>
00040
00041 #include <bzlib.h>
00042
00043 #include "global.h"
00044 #include "basestrm.h"
00045
00046 #ifdef _DOS_
00047 #include "dos/fileio.h"
00048 #else
00049 #ifdef _WIN32_
00050 #include "win32/fileio.h"
00051 #else
00052 #ifdef _UNIX_
00053 #include "unix/fileio.h"
00054 #endif
00055 #endif
00056 #endif
00057
00058
00059 #include <SDL_endian.h>
00060
00061
00062 #include "util/messaginghub.h"
00063
00064
00065 const int maxSearchDirNum = 30;
00066 int searchDirNum = 0;
00067 char* ascDirectory[maxSearchDirNum] = { NULL, NULL, NULL, NULL, NULL,
00068 NULL, NULL, NULL, NULL, NULL };
00069
00070
00071
00072
00073 #pragma pack(1)
00074 struct trleheader {
00075 unsigned short int id;
00076 unsigned short int size;
00077 char rle;
00078 unsigned short int x;
00079 unsigned short int y;
00080 };
00081
00082 #pragma pack()
00083
00084 #define bzip_xor_byte 'M'
00085
00086 const char* containermagic = "NCBM";
00087
00088 const char* LZ_SIGNATURE = "MBLZW16";
00089 const char* RLE_SIGNATURE = "MBRLE1";
00090 const char* BZIP_SIGNATURE = "MBZLB2X!";
00091
00092
00093
00094
00095
00099
00100 CharBuf :: CharBuf ( void )
00101 {
00102 size = 0;
00103 buf = NULL;
00104 }
00105
00106 CharBuf :: CharBuf ( int _size )
00107
00108 {
00109 size = _size;
00110 buf = new char[ size ];
00111 }
00112
00113 void CharBuf :: resize ( int newsize )
00114 {
00115 char* nb = new char[newsize];
00116 for ( int i = 0; i < size; i++ )
00117 nb[i] = buf[i];
00118
00119 delete[] buf;
00120 buf = nb;
00121 }
00122
00123 CharBuf :: ~CharBuf()
00124 {
00125 if ( buf )
00126 delete[] buf;
00127 buf = NULL;
00128 }
00129
00133
00134
00135
00136 OutOfMemoryError::OutOfMemoryError ( int m )
00137 {
00138 required = m;
00139 }
00140
00141 tfileerror::tfileerror ( const ASCString& fileName )
00142 {
00143 _filename = fileName ;
00144 }
00145
00146
00147 tinvalidmode :: tinvalidmode ( const ASCString& _fileName, tnstream::IOMode org_mode, tnstream::IOMode requested_mode )
00148 : tfileerror ( _fileName )
00149 {
00150 orgmode = org_mode;
00151 requestmode = requested_mode;
00152 }
00153
00154
00155
00156 treadafterend :: treadafterend ( const ASCString& _fileName )
00157 : tfileerror ( _fileName )
00158 {
00159
00160 }
00161
00162
00163 tinternalerror::tinternalerror ( const char* filename, int l )
00164 {
00165 linenum = l;
00166 sourcefilename = filename;
00167 }
00168
00169
00170
00171 tinvalidversion :: tinvalidversion ( const ASCString& _fileName, int ex, int fnd )
00172 : tfileerror ( _fileName ), expected ( ex ), found ( fnd )
00173 {
00174 }
00175
00176 ASCString tinvalidversion :: getMessage() const
00177 {
00178 ASCString s;
00179 if ( expected < found )
00180 s.format( "File/module %s has invalid version.\nExpected file version %d\nFound file version %d\nThe file/module is newer than your application\nPlease install the latest version of ASC from www.asc-hq.org", getFileName().c_str(), expected, found );
00181 else
00182 s.format ( "File/module %s has invalid version.\nExpected file version %d\nFound file version %d\nThis is a bug, please report it!", getFileName().c_str(), expected, found );
00183
00184 return s;
00185 }
00186
00187
00188
00192
00193
00194 tnstream :: tnstream ( void )
00195 : devicename ( "-abstract tnstream-" ) {}
00196
00197 void tnstream::seek ( int pos )
00198 {
00199 throw tfileerror ( "Seeking not supported for stream " + getDeviceName() );
00200 }
00201
00202 void tnstream::readrlepict( void** pnter, bool allocated, int* size)
00203 {
00204 trleheader hd;
00205 int w;
00206 char* q;
00207
00208 hd.id = readWord();
00209 hd.size = readWord();
00210 hd.rle = readChar();
00211 hd.x = readWord();
00212 hd.y = readWord();
00213
00214 if (hd.id == 16973) {
00215 if (!allocated)
00216 *pnter = new char [ hd.size + sizeof(hd) ];
00217 memcpy( *pnter, &hd, sizeof(hd));
00218 q = (char*) (*pnter) + sizeof(hd);
00219
00220 readdata( q, hd.size);
00221 *size = hd.size + sizeof(hd);
00222 }
00223 else {
00224 w = (hd.id + 1) * (hd.size + 1) + 4 ;
00225 if (!allocated)
00226 *pnter = new char [ w ];
00227 memcpy ( *pnter, &hd, sizeof ( hd ));
00228 q = (char*) (*pnter) + sizeof(hd);
00229 readdata ( q, w - sizeof(hd) );
00230 *size = w;
00231 }
00232 }
00233
00234
00235
00236 void tnstream :: writerlepict ( const void* buf )
00237 {
00238 writeImage( buf, true );
00239 }
00240
00241 void tnstream :: writeImage ( const void* buf, bool compress )
00242 {
00243 if ( compress ) {
00244 char* tempbuf = new char [ 0xffff ];
00245 if ( tempbuf ) {
00246 int size = compressrle ( buf, tempbuf );
00247 trleheader* hd = (trleheader*) tempbuf;
00248 writeWord( hd->id );
00249 writeWord( hd->size );
00250 writeChar( hd->rle );
00251 writeWord( hd->x );
00252 writeWord( hd->y );
00253
00254 writedata ( hd+1, size - sizeof(*hd) );
00255 delete[] tempbuf;
00256 } else
00257 compress = false;
00258 }
00259
00260 if ( !compress ) {
00261 Uint16* pw = (Uint16*) buf;
00262 writeWord(pw[0] );
00263 writeWord(pw[1] );
00264 writedata ( pw+2, ( pw[0] + 1 ) * ( pw[1] + 1 ) );
00265 }
00266 }
00267
00268
00269 ASCString tnstream::getDeviceName()
00270 {
00271 return devicename;
00272 }
00273
00274 ASCString tnstream::getLocation()
00275 {
00276 return devicename;
00277 }
00278
00279 ASCString tnstream::getArchive()
00280 {
00281 return "";
00282 }
00283
00284 int tnstream::readInt ( void )
00285 {
00286 int i;
00287 readdata2 ( i );
00288 return SDL_SwapLE32( i );
00289 }
00290
00291 int tnstream::readWord ( void )
00292 {
00293 Uint16 w;
00294 readdata2 ( w );
00295 return SDL_SwapLE16( w );
00296 }
00297
00298 char tnstream::readChar ( void )
00299 {
00300 char c;
00301 readdata2 ( c );
00302 return c;
00303 }
00304
00305 float SwapFloat( float f )
00306 {
00307 union
00308 {
00309 float f;
00310 unsigned char b[4];
00311 } dat1, dat2;
00312
00313 dat1.f = f;
00314 dat2.b[0] = dat1.b[3];
00315 dat2.b[1] = dat1.b[2];
00316 dat2.b[2] = dat1.b[1];
00317 dat2.b[3] = dat1.b[0];
00318 return dat2.f;
00319 }
00320
00321 float tnstream::readFloat ( void )
00322 {
00323 float c;
00324 readdata2 ( c );
00325 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
00326 c = SwapFloat(c);
00327 #endif
00328 return c;
00329 }
00330
00331 #if SIZE_T_not_identical_to_INT
00332
00333 void tnstream::writeInt ( size_t i )
00334 {
00335 #ifdef HAVE_LIMITS
00336
00337 #endif
00338 writeInt( int(i) );
00339 }
00340
00341 #endif
00342
00343 void tnstream::writeInt ( unsigned int i )
00344 {
00345 i = SDL_SwapLE32(i);
00346 writedata2 ( i );
00347 }
00348
00349 void tnstream::writeInt ( bool b )
00350 {
00351 int i = b;
00352 i = SDL_SwapLE32(i);
00353 writedata2 ( i );
00354 }
00355
00356 void tnstream::writeInt ( int i )
00357 {
00358 i = SDL_SwapLE32(i);
00359 writedata2 ( i );
00360 }
00361
00362 void tnstream::writeWord ( int w )
00363 {
00364 Uint16 w2 = SDL_SwapLE16( Uint16(w) );
00365 writedata2 ( w2 );
00366 }
00367
00368 void tnstream::writeChar ( char c )
00369 {
00370 writedata2 ( c );
00371 }
00372
00373 void tnstream::writeFloat ( float f )
00374 {
00375 writedata2 ( f );
00376 }
00377
00378 void tnstream::readpchar(char** pc, int maxlength )
00379 {
00380 int actpos2 = 0;
00381
00382 int maxav = 100000;
00383
00384 if ( maxlength )
00385 if ( maxav > maxlength )
00386 maxav = maxlength;
00387
00388 CharBuf charbuf ( maxav );
00389
00390 maxav--;
00391
00392
00393 char* pch2 = charbuf.buf;
00394
00395 int loop = 0;
00396
00397 do {
00398 actpos2++;
00399 if ( loop )
00400 pch2++;
00401
00402 loop++;
00403
00404 readdata( pch2, 1 );
00405
00406 } while (*pch2 != 0 && actpos2 < maxav );
00407
00408 if ( actpos2 >= maxav ) {
00409 pch2[1] = 0;
00410 actpos2++;
00411
00412 if ( pch2[0] ) {
00413 char temp;
00414 do {
00415 readdata( &temp, 1 );
00416 } while ( temp );
00417 }
00418 }
00419
00420 pch2 = new char [ actpos2 ];
00421
00422 memcpy ( pch2, charbuf.buf, actpos2 );
00423
00424 *pc = pch2;
00425 }
00426
00427
00428 void tnstream::readpnchar(char** pc, int maxlength )
00429 {
00430 int actpos2 = 0;
00431
00432 int maxav = 10000;
00433
00434 if ( maxlength )
00435 if ( maxav > maxlength )
00436 maxav = maxlength;
00437
00438
00439 CharBuf charbuf ( maxav );
00440
00441 maxav--;
00442
00443
00444 char* pch2 = charbuf.buf;
00445
00446 int ende = 0;
00447
00448 do {
00449 char bt;
00450
00451 int red = readdata( &bt, 1, 0 );
00452
00453 if ( red < 1 ) {
00454 ende = 2;
00455 *pch2 = 0;
00456 } else
00457 if ( bt == '\n' || bt == 0 ) {
00458 *pch2 = 0;
00459 ende = 1;
00460 } else
00461 if ( bt != '\r' ) {
00462 *pch2 = bt;
00463 pch2++;
00464 actpos2++;
00465 }
00466
00467 } while ( !ende && actpos2 < maxav );
00468
00469
00470 if ( !ende ) {
00471 if ( actpos2 >= maxav ) {
00472 *pch2 = 0;
00473
00474 if ( pch2[0] ) {
00475 char temp;
00476 do {
00477
00478 int red = readdata( &temp, 1, 0 );
00479 if ( red < 1 ) {
00480 temp = 0;
00481 } else
00482 if ( temp == '\n' )
00483 temp = 0;
00484
00485 } while ( temp );
00486 }
00487 }
00488 }
00489 if ( ende == 2 ) {
00490 if ( !actpos2 )
00491 *pc = NULL;
00492 else
00493 *pc = strdup ( charbuf.buf );
00494 } else
00495 *pc = strdup ( charbuf.buf );
00496 }
00497
00498
00499 bool tnstream::readTextString ( ASCString& s, bool includeCR )
00500 {
00501 s = "";
00502 char c;
00503 int red;
00504 int end = 0;
00505 do {
00506 red = readdata( &c, 1, 0 );
00507 if ( red < 1 ) {
00508 end = 2;
00509 } else
00510 if ( (c == '\n' && !includeCR) || c == 0 ) {
00511 end = 1;
00512 } else
00513 if ( c != '\r' )
00514 s += c;
00515 } while ( red && !end );
00516 if ( end == 2)
00517 return false;
00518 else
00519 return true;
00520 }
00521
00522
00523 ASCString tnstream::readString ( bool includeCR )
00524 {
00525 ASCString s;
00526 bool data = readTextString ( s, includeCR );
00527 if ( !data && s.empty() )
00528 throw treadafterend ( getLocation() );
00529 return s;
00530 }
00531
00532
00533 void tnstream::writeString(const string& pc, bool binary )
00534 {
00535 if ( binary )
00536 writepchar ( pc.c_str() );
00537 else
00538 writedata ( pc.data(), pc.length() );
00539 }
00540
00541
00542 void tnstream::writepchar(const char* pc)
00543 {
00544 if ( pc ) {
00545 const char *pch1 = pc;
00546 int loop = 0;
00547
00548 do {
00549 if ( loop )
00550 pch1++;
00551 writedata( pch1, 1 );
00552 loop++;
00553 } while ( *pch1 > 0 );
00554 } else {
00555 char pch1 = 0;
00556 writedata ( &pch1, 1 );
00557 }
00558
00559 }
00560
00562
00563
00564
00565
00566 MemoryStreamCopy :: MemoryStreamCopy ( tnstream* stream )
00567 {
00568 buf = NULL;
00569 int bufused = 0;
00570 int memreserved = 0;
00571 int blocksize = 500000;
00572 int red;
00573 do {
00574 if ( bufused + blocksize > memreserved ) {
00575 int newsize = memreserved + blocksize;
00576 void* newbuf = malloc (newsize);
00577 if ( buf ) {
00578 memcpy ( newbuf, buf, bufused );
00579 free ( buf );
00580 }
00581 buf = newbuf;
00582 memreserved = newsize;
00583 }
00584 char* cp = (char*) buf;
00585 red = stream->readdata ( cp + bufused, blocksize, 0 );
00586 bufused += red;
00587
00588 } while ( red == blocksize );
00589 size = bufused;
00590 pos = 0;
00591
00592 devicename = stream->getDeviceName();
00593 }
00594
00595 ASCString MemoryStreamCopy::getLocation()
00596 {
00597 return devicename + " (memory buffered)";
00598 }
00599
00600 MemoryStreamCopy :: ~MemoryStreamCopy ( )
00601 {
00602 if ( buf )
00603 free ( buf );
00604 }
00605
00606
00607 void MemoryStreamCopy :: writedata ( const void* buf, int size )
00608 {
00609 throw tinvalidmode ( getDeviceName(), reading, writing );
00610 }
00611
00612 int MemoryStreamCopy :: readdata ( void* buffer, int _size, bool excpt )
00613 {
00614 char* cp = (char*) buf;
00615 if ( pos + _size > size ) {
00616 if ( excpt )
00617 throw treadafterend ( getDeviceName() );
00618 else {
00619 int tr = size-pos;
00620 memcpy ( buffer, cp+pos, tr );
00621 pos += tr;
00622 return tr;
00623 }
00624
00625 } else {
00626 memcpy ( buffer, cp+pos, _size );
00627 pos += _size;
00628 return _size;
00629 }
00630 }
00631
00632 void MemoryStreamCopy :: seek ( int newpos )
00633 {
00634 if ( newpos > size || newpos < 0 )
00635 throw treadafterend ( getDeviceName() );
00636
00637 pos = newpos;
00638 }
00639
00640
00642
00643
00644 static int stream_seek( struct SDL_RWops *context, int offset, int whence)
00645 {
00646 MemoryStreamCopy* stream = (MemoryStreamCopy*) context->hidden.unknown.data1;
00647 if ( whence == SEEK_SET )
00648 stream->seek ( offset );
00649 else
00650 if ( whence == SEEK_CUR )
00651 stream->seek ( offset + stream->getPosition() );
00652 else
00653 if ( whence == SEEK_END )
00654 stream->seek ( offset + stream->getSize() );
00655 return stream->getPosition();
00656 }
00657
00658
00659 static int stream_read(SDL_RWops *context, void *ptr, int size, int maxnum)
00660
00661 {
00662 MemoryStreamCopy* stream = (MemoryStreamCopy*) context->hidden.unknown.data1;
00663 size_t nread = stream->readdata ( ptr, size * maxnum, 0 );
00664
00665 return(nread / size);
00666 }
00667
00668 static int stream_close(SDL_RWops *context)
00669 {
00670 if ( context ) {
00671 if ( context->hidden.unknown.data1 ) {
00672 MemoryStreamCopy* stream = (MemoryStreamCopy*) context->hidden.unknown.data1;
00673 delete stream;
00674 }
00675 SDL_FreeRW(context);
00676 }
00677 return(0);
00678 }
00679
00680
00681 SDL_RWops *SDL_RWFromStream( tnstream* stream )
00682 {
00683 MemoryStreamCopy* msb = new MemoryStreamCopy ( stream );
00684
00685 SDL_RWops *rwops;
00686
00687 rwops = SDL_AllocRW();
00688 if ( rwops != NULL ) {
00689 rwops->seek = stream_seek;
00690 rwops->read = stream_read;
00691 rwops->write = NULL;
00692 rwops->close = stream_close;
00693 rwops->hidden.unknown.data1 = msb;
00694 }
00695 return(rwops);
00696 }
00697
00699
00700
00701
00702
00703 tncontainerstream :: tncontainerstream ( const char* containerfilename, ContainerIndexer* indexer, int dirLevel )
00704 : tn_file_buf_stream ( containerfilename, reading ), index(NULL)
00705 {
00706 num = 0;
00707 char magic[4];
00708 readdata ( &magic, 4 );
00709 if ( strncmp ( magic, containermagic, 4 ) == 0) {
00710 int pos = readInt();
00711 seek ( pos );
00712 num = readInt();
00713 index = new tcontainerindex[num];
00714 for ( int i = 0; i < num; i++ ) {
00715
00716 bool __loadName = readInt();
00717 index[i].start = readInt();
00718 index[i].end = readInt();
00719 if ( __loadName ) {
00720 readpchar ( &index[i].name );
00721
00722 #if CASE_SENSITIVE_FILE_NAMES == 1
00723
00724 char *c = index[i].name;
00725 while ( *c ) {
00726 *c = tolower( *c );
00727 c++;
00728 }
00729 #endif
00730
00731 indexer->addfile ( index[i].name, this, dirLevel );
00732 } else
00733 index[i].name = NULL;
00734 }
00735 }
00736 actfile = NULL;
00737 containerfilepos = 0;
00738 }
00739
00740
00741 int tncontainerstream :: getcontainerfilesize ( const char* name )
00742 {
00743 int i = 0;
00744 while ( i < num && stricmp ( index[i].name, name ) )
00745 i++;
00746
00747 if ( i >= num )
00748 return -1;
00749 else
00750 return index[i].end - index[i].start + 1;
00751
00752 }
00753
00754
00755 void tncontainerstream :: opencontainerfile ( const char* name )
00756 {
00757 if ( actfile ) {
00758 ASCString err = ASCString("two files simultaneously: ") + actfile->name + " and " + name;
00759 throw tfileerror ( err );
00760 }
00761
00762 containerfilepos = 0;
00763 int i = 0;
00764 while ( i < num && stricmp ( index[i].name, name ) )
00765 i++;
00766
00767 if ( i >= num )
00768 throw tfileerror ( name );
00769
00770 displayLogMessage( 9, ASCString("opencontainerfile ") + name );
00771 containerfilepos = 0;
00772 seek ( index[i].start );
00773 actfile = &index[i];
00774 }
00775
00776 int tncontainerstream :: readcontainerdata ( void* buf, int size, bool excpt )
00777 {
00778 if ( actfile->start + containerfilepos + size > actfile->end+1 ) {
00779 if ( excpt )
00780 throw treadafterend ( actfile->name );
00781 else {
00782 int got = readdata ( buf, (actfile->end+1 - actfile->start) - containerfilepos , excpt );
00783 containerfilepos+=got;
00784 return got;
00785
00786 }
00787 }
00788
00789 readdata ( buf, size );
00790 containerfilepos+=size;
00791 return size;
00792 }
00793
00794 void tncontainerstream :: closecontainerfile ( void )
00795 {
00796 actfile = NULL;
00797 }
00798
00799 char* tncontainerstream :: getfirstname ( void )
00800 {
00801 actname = 0;
00802 return getnextname();
00803 }
00804
00805 char* tncontainerstream :: getnextname ( void )
00806 {
00807 if ( actname < num )
00808 return index[actname++].name;
00809 else
00810 return NULL;
00811
00812 }
00813
00814
00815
00816 tncontainerstream :: ~tncontainerstream ()
00817 {
00818 for ( int i = 0; i < num; i++ )
00819 if ( index[i].name )
00820 delete[] index[i].name;
00821 delete[] index;
00822 }
00823
00824
00825
00826
00828
00829 class ContainerCollector : public ContainerIndexer {
00830 public:
00831 struct FileIndex {
00832 ASCString name;
00833 pncontainerstream container;
00834 int directoryLevel;
00835 };
00836 protected:
00837
00838 dynamic_array<FileIndex> index[256];
00839
00840 dynamic_array<pncontainerstream> container;
00841 int containernum;
00842 struct {
00843 int alpha;
00844 int index;
00845 } namesearch;
00846 public:
00847 ContainerCollector ( void );
00848 void init ( const char* wildcard );
00849 void addfile ( const char* filename, const pncontainerstream stream, int directoryLevel );
00850
00851 FileIndex* getfile ( const ASCString& filename );
00852 FileIndex* getfirstname ( void );
00853 FileIndex* getnextname ( void );
00854 ASCString listContainer();
00855 virtual ~ContainerCollector();
00856 };
00857
00858
00859 ContainerCollector containercollector;
00860
00861 char* constructFileName( char* buf, int directoryLevel, const char* path, const char* filename )
00862 {
00863 if ( buf ) {
00864
00865 const char* filename2 = filename;
00866 buf[0] = 0;
00867
00868
00869 if ( ! (filename && (filename[0] == pathdelimitter || (filename[0]=='~' && filename[1] == pathdelimitter)) )) {
00870 if ( path )
00871 strcpy ( buf, path);
00872 else
00873 if ( directoryLevel >= 0 && ascDirectory[ directoryLevel ] )
00874 strcpy ( buf, ascDirectory[ directoryLevel ]);
00875 }
00876
00877 appendbackslash ( buf );
00878
00879 if ( filename && strchr ( filename, pathdelimitter )) {
00880
00881 char name2[ maxFileStringSize ];
00882
00883 strcpy ( name2, filename );
00884 int i = strlen ( name2 )-1;
00885 while ( name2[i] != pathdelimitter )
00886 i--;
00887
00888 name2[i+1] = 0;
00889
00890 filename2 = &filename[i+1];
00891
00892
00893
00894
00895 if ( buf[0] && name2[0]==pathdelimitter )
00896 strcpy ( buf, name2+1);
00897 else
00898 strcpy ( buf, name2);
00899 }
00900
00901 if ( buf[0] == '~' && buf[1] == pathdelimitter ) {
00902 char* home = getenv ( "HOME" );
00903 if ( home ) {
00904 char temp[ maxFileStringSize ];
00905 strcpy ( temp, buf );
00906 strcpy ( buf, home );
00907 appendbackslash ( buf );
00908 strcat ( buf, &temp[2]);
00909 }
00910 }
00911
00912
00913 appendbackslash ( buf );
00914
00915 if ( filename2 )
00916 strcat ( buf, filename2 );
00917 }
00918
00919 return buf;
00920 }
00921
00922 bool isPathRelative( const ASCString& path )
00923 {
00924 if ( path.length() < 2 )
00925 return true;
00926
00927 if ( path[0] == '~' && path[1] == pathdelimitter )
00928 return false;
00929
00930 #ifdef WIN32
00931 if ( path[1] == ':' && path[2] == pathdelimitter )
00932 return false;
00933
00934 #endif
00935
00936 if ( path[0] == pathdelimitter )
00937 return false;
00938
00939 return true;
00940 }
00941
00942 ASCString constructFileName( int directoryLevel, const ASCString& path, ASCString filename )
00943 {
00944 ASCString result;
00945
00946
00947 if ( isPathRelative( filename )) {
00948 if ( !path.empty() )
00949 result += path;
00950 else
00951 if ( directoryLevel >= 0 && ascDirectory[ directoryLevel ] )
00952 result += ascDirectory[ directoryLevel ];
00953 }
00954
00955 appendbackslash ( result );
00956
00957 if ( !filename.empty() && filename.find( pathdelimitter )!= ASCString::npos ) {
00958 ASCString dir = filename;
00959
00960 dir.erase( dir.rfind( pathdelimitter ) + 1);
00961
00962 filename.erase( 0, filename.find( pathdelimitter ) + 1 );
00963
00964 if ( dir.find( pathdelimitter ) == 0 )
00965 dir.erase( 0, 1 );
00966
00967 result = dir;
00968 }
00969
00970 if ( result.length() > 2 && result[0] == '~' && result[1] == pathdelimitter ) {
00971 char* home = getenv ( "HOME" );
00972 if ( home ) {
00973 ASCString temp = result;
00974 result = home;
00975 appendbackslash ( result );
00976 result += temp.substr( 2 );
00977 }
00978 }
00979
00980
00981 appendbackslash ( result );
00982
00983 result += filename;
00984
00985 return result;
00986 }
00987
00988
00989
00990 struct FileLocation {
00991 int directoryLevel;
00992 pncontainerstream container;
00993 int found;
00994 };
00995
00996 void locateFile ( const ASCString& filename, FileLocation* loc )
00997 {
00998 loc->found = 0;
00999 ContainerCollector::FileIndex* idx = containercollector.getfile ( filename );
01000 int maxnum;
01001 if ( idx ) {
01002 maxnum = idx->directoryLevel+1;
01003 loc->directoryLevel = idx->directoryLevel;
01004 loc->found = 1;
01005 loc->container = idx->container;
01006 } else {
01007 maxnum = searchDirNum;
01008 loc->container = NULL;
01009 loc->directoryLevel = -1;
01010 }
01011
01012 if ( maxnum ) {
01013 int localfound = 0;
01014 for ( int i = 0; i < maxnum && !localfound; i++ ) {
01015 char buf[2000];
01016 FILE* fp = fopen ( constructFileName ( buf, i, NULL, filename.c_str()), "r" );
01017 if ( fp ) {
01018 localfound = loc->found = 1;
01019 fclose ( fp );
01020 loc->container = NULL;
01021 loc->directoryLevel = i;
01022 }
01023 }
01024 } else {
01025 char buf[2000];
01026 FILE* fp = fopen ( constructFileName ( buf, -1, ".", filename.c_str()), "r" );
01027 if ( fp ) {
01028 loc->found = 1;
01029 fclose ( fp );
01030 loc->container = NULL;
01031 loc->directoryLevel = -2;
01032 }
01033 }
01034 }
01035
01037
01038
01039
01040 ASCString listContainer()
01041 {
01042 return containercollector.listContainer();
01043 }
01044
01045
01046 ContainerCollector :: ContainerCollector ( void )
01047 {
01048 containernum = 0;
01049 }
01050
01051 void ContainerCollector :: init ( const char* wildcard )
01052 {
01053 for ( int i = 0; i < searchDirNum; i++ ) {
01054 DIR *dirp;
01055 struct ASC_direct *direntp;
01056
01057 char buf[ maxFileStringSize ];
01058 char buf2[ maxFileStringSize ];
01059 char buf3 [ maxFileStringSize ];
01060 dirp = opendir( extractPath ( buf2, constructFileName ( buf, i, NULL, wildcard )));
01061 extractFileName ( buf3, buf );
01062 if( dirp != NULL ) {
01063 for(;;) {
01064 direntp = readdir( dirp );
01065 if ( direntp == NULL ) {
01066 break;
01067 }
01068 if ( patimat ( buf3, direntp->d_name )) {
01069 container[containernum++] = new tncontainerstream( constructFileName ( buf, i, buf2, direntp->d_name), this, i);
01070 if ( MessagingHub::Instance().getVerbosity() >= 2 )
01071 printf("container %s mounted\n", buf );
01072 }
01073 }
01074 closedir( dirp );
01075 }
01076 }
01077 }
01078
01079 void ContainerCollector :: addfile ( const char* filename, const pncontainerstream stream, int directoryLevel )
01080 {
01081 int found = 0;
01082 FileIndex* cci = NULL;
01083
01084 int i1 = toupper ( filename[0] );
01085 for ( int i = 0; i <= index[i1].getlength(); i++ )
01086 if ( index[i1][i].name.compare_ci ( filename ) == 0 ) {
01087 if ( index[i1][i].directoryLevel <= directoryLevel )
01088 return;
01089 else {
01090 cci = &(index[i1][i]);
01091 found = 1;
01092 }
01093 }
01094
01095 if ( !found )
01096 cci = &( index[i1][ index[i1].getlength()+1 ] );
01097
01098 cci->name = filename;
01099 cci->container = stream;
01100 cci->directoryLevel = directoryLevel;
01101 }
01102
01103 ContainerCollector::FileIndex* ContainerCollector :: getfile ( const ASCString& filename )
01104 {
01105 int i1 = toupper ( filename[0] );
01106 for ( int i = 0; i <= index[i1].getlength(); i++ )
01107 if ( index[i1][i].name.compare_ci ( filename) == 0 )
01108 return &index[i1][i];
01109
01110 return NULL;
01111 }
01112
01113
01114 ContainerCollector::FileIndex* ContainerCollector :: getfirstname ( void )
01115 {
01116 namesearch.alpha = 0;
01117 namesearch.index = 0;
01118 return getnextname();
01119 }
01120
01121 ContainerCollector::FileIndex* ContainerCollector :: getnextname ( void )
01122 {
01123 while ( index[namesearch.alpha].getlength() < namesearch.index) {
01124 if ( namesearch.alpha == 255 )
01125 return NULL;
01126 namesearch.alpha++;
01127 namesearch.index = 0;
01128 }
01129 return &index[namesearch.alpha][namesearch.index++];
01130 }
01131
01132 ASCString ContainerCollector :: listContainer()
01133 {
01134 ASCString s;
01135 for ( int i = 0; i < containernum; i++ )
01136 s += container[i]->getLocation() + "\n";
01137
01138 return s;
01139
01140 }
01141
01142
01143
01144 ContainerCollector :: ~ContainerCollector()
01145 {
01146 int i;
01147 for (i = 0; i < containernum; i++ )
01148 delete container[i];
01149 containernum = 0;
01150 }
01151
01152
01153
01155
01156 CompressionStreamAdapter::CompressionStreamAdapter( tnstream* compressedStream )
01157 : stream ( compressedStream )
01158 {
01159 }
01160 void CompressionStreamAdapter::writecmpdata ( const void* buf, int size )
01161 {
01162 stream->writedata( buf, size );
01163 }
01164
01165 int CompressionStreamAdapter::readcmpdata ( void* buf, int size, bool excpt )
01166 {
01167 return stream->readdata( buf, size, excpt );
01168 }
01169
01170
01171 class PrivateCompressionData {
01172 public:
01173 bz_stream bzs;
01174 static const int outputbufsize = 100000;
01175 char outputbuf[outputbufsize];
01176
01177 PrivateCompressionData() {
01178 bzs.bzalloc = NULL;
01179 bzs.bzfree = NULL;
01180 bzs.opaque = NULL;
01181 };
01182
01183 ~PrivateCompressionData() {
01184 BZ2_bzCompressEnd ( &bzs );
01185 }
01186 };
01187
01188 libbzip_compression :: libbzip_compression ( CompressionStreamInterface* strm )
01189 {
01190 data = new PrivateCompressionData();
01191 BZ2_bzCompressInit ( &data->bzs, 5, 0, 0 );
01192
01193 stream = strm;
01194 }
01195
01196
01197 void libbzip_compression :: writedata ( const void* buf, int size )
01198 {
01199 char* cbuf = (char*) buf;
01200
01201 data->bzs.next_in = cbuf ;
01202 data->bzs.avail_in = size ;
01203 data->bzs.total_in_lo32 = 0 ;
01204 data->bzs.total_in_hi32 = 0 ;
01205
01206 while ( data->bzs.total_in_lo32 < size ) {
01207
01208 data->bzs.next_out = data->outputbuf;
01209 data->bzs.avail_out = data->outputbufsize;
01210 data->bzs.total_out_lo32 = 0;
01211 data->bzs.total_out_hi32 = 0;
01212
01213 int res = BZ2_bzCompress ( &data->bzs, BZ_RUN );
01214 if ( res < 0 )
01215 throw StreamCompressionError ( "MBZLB2 compression :: writedata", res );
01216
01217 for ( int i = 0; i < data->bzs.total_out_lo32; i++ )
01218 data->outputbuf[i] ^= bzip_xor_byte;
01219
01220 if ( data->bzs.total_out_lo32 > 0 )
01221 stream->writecmpdata ( data->outputbuf, data->bzs.total_out_lo32 );
01222 }
01223 }
01224
01225
01226 void libbzip_compression :: close_compression ( void )
01227 {
01228 int res;
01229 do {
01230 data->bzs.next_in = data->outputbuf;
01231 data->bzs.avail_in = 0;
01232
01233 data->bzs.next_out = data->outputbuf;
01234 data->bzs.avail_out = data->outputbufsize;
01235 data->bzs.total_out_lo32 = 0;
01236 data->bzs.total_out_hi32 = 0;
01237
01238 res = BZ2_bzCompress ( &data->bzs, BZ_FINISH );
01239 if ( res < 0 )
01240 throw StreamCompressionError ( "MBZLB2 compression :: closecompression", res );
01241
01242 for ( int i = 0; i < data->bzs.total_out_lo32; i++ )
01243 data->outputbuf[i] ^= bzip_xor_byte;
01244 stream->writecmpdata ( data->outputbuf, data->bzs.total_out_lo32 );
01245
01246 } while ( res != BZ_STREAM_END );
01247
01248
01249 BZ2_bzCompressEnd ( &data->bzs );
01250 }
01251
01252 libbzip_compression :: ~libbzip_compression ( )
01253 {
01254 delete data;
01255 }
01256
01257
01258
01259 class PrivateDecompressionData {
01260 public:
01261 bz_stream bzs;
01262 static const int inputbufsize = 100000;
01263 char inputbuf[inputbufsize];
01264 int inputbufused;
01265 int inputbufread;
01266
01267 PrivateDecompressionData() {
01268 bzs.bzalloc = NULL;
01269 bzs.bzfree = NULL;
01270 bzs.opaque = NULL;
01271
01272 inputbufused = 0;
01273 inputbufread = 0;
01274
01275 }
01276
01277 ~PrivateDecompressionData() {
01278 BZ2_bzDecompressEnd ( &bzs );
01279 }
01280
01281 };
01282
01283 libbzip_decompression :: libbzip_decompression ( CompressionStreamInterface* strm )
01284 {
01285 data = new PrivateDecompressionData();
01286 BZ2_bzDecompressInit ( &data->bzs, 0, 0 );
01287 stream = strm;
01288 }
01289
01290
01291 int libbzip_decompression :: readdata ( void* buf, int size, bool excpt )
01292 {
01293 int decompressed = 0;
01294 char* cbuf = (char*) buf;
01295
01296 data->bzs.next_in = cbuf ;
01297 data->bzs.avail_in = size ;
01298 data->bzs.total_in_lo32 = 0 ;
01299 data->bzs.total_in_hi32 = 0 ;
01300
01301 int abrt = 0;
01302
01303 while ( decompressed < size && !abrt ) {
01304 if ( data->inputbufread >= data->inputbufused ) {
01305 data->inputbufused = stream->readcmpdata ( data->inputbuf, data->inputbufsize, 0 );
01306
01307 if ( !data->inputbufused && excpt )
01308 throw StreamCompressionError ( "Decompressor :: out of data", 0 );
01309
01310
01311 for ( int i = 0; i < data->inputbufused; i++ )
01312 data->inputbuf[i] ^= bzip_xor_byte;
01313
01314 data->inputbufread = 0;
01315 }
01316 data->bzs.next_in = data->inputbuf + data->inputbufread;
01317 data->bzs.avail_in = data->inputbufused - data->inputbufread;
01318 data->bzs.total_in_lo32 = 0;
01319 data->bzs.total_in_hi32 = 0;
01320
01321 data->bzs.next_out = cbuf + decompressed;
01322 data->bzs.avail_out = size - decompressed;
01323 data->bzs.total_out_lo32 = 0;
01324 data->bzs.total_out_hi32 = 0;
01325
01326 int res = BZ2_bzDecompress ( &data->bzs );
01327 decompressed += data->bzs.total_out_lo32;
01328 data->inputbufread += data->bzs.total_in_lo32;
01329
01330 if ( decompressed < size ) {
01331 if ( res == BZ_STREAM_END ) {
01332 if ( excpt )
01333 throw treadafterend ( "BZ_decompress_stream" );
01334 abrt = 1;
01335 } else {
01336 if ( res != BZ_OK ) {
01337 if ( excpt ) {
01338 if ( res == BZ_MEM_ERROR )
01339 throw OutOfMemoryError ( -1 );
01340 else
01341 throw StreamCompressionError ( "MBZLB2 decompression :: readdata", res );
01342 }
01343 abrt = 1;
01344 }
01345 }
01346 }
01347 }
01348 return decompressed;
01349 }
01350
01351
01352 libbzip_decompression :: ~libbzip_decompression ( )
01353 {
01354 delete data;
01355 }
01356
01357
01358
01360
01361
01362
01363
01364
01365
01366
01367
01368
01369
01370
01371
01372
01373
01374
01375
01376
01377
01378
01379
01380
01381
01382
01383
01384
01385
01386
01387
01388
01389
01390
01391
01392
01393
01394
01395
01396
01397
01398
01399
01400
01401
01402
01403
01404 tanycompression :: tanycompression ( int md )
01405 {
01406 mmd = md;
01407 bzip_compress = NULL;
01408 bzip_decompress = NULL;
01409 }
01410
01411 void tanycompression :: init ( void )
01412 {
01413 if ( mmd == 1 ) {
01414 char buf[10];
01415
01416 int maxlen = strlen ( BZIP_SIGNATURE ) + 1;
01417 int bufdatanum = readcmpdata ( buf, maxlen, 0 );
01418 int siglen = 0;
01419
01420 if ( bufdatanum == maxlen ) {
01421
01422 if ( strncmp ( &buf[1], LZ_SIGNATURE, 9 ) == 0 && !buf[0]) {
01423 status = 110;
01424 siglen = 0;
01425 } else
01426 if ( strncmp ( &buf[1], RLE_SIGNATURE, 9 ) == 0 && !buf[0]) {
01427 status = 111;
01428 siglen = 0;
01429 } else
01430 if ( strncmp ( buf, BZIP_SIGNATURE, 9 ) == 0 ) {
01431 status = 112;
01432 siglen = strlen ( BZIP_SIGNATURE ) + 1;
01433 bzip_decompress = new libbzip_decompression ( this );
01434 } else
01435 status= 109;
01436
01437 } else
01438 status = 109;
01439
01440 for ( int i = siglen; i < bufdatanum; i++ )
01441 _queue.push ( buf[i] );
01442
01443
01444 } else {
01445 status = 201;
01446 bzip_compress = new libbzip_compression ( this );
01447 writecmpdata ( BZIP_SIGNATURE, strlen ( BZIP_SIGNATURE ) + 1 );
01448 }
01449 }
01450
01451
01452 int tanycompression :: readdata ( void* rbuf, int size, bool excpt )
01453 {
01454 int red = 0;
01455 if ( size ) {
01456 switch ( status ) {
01457 case 109: red += readlzwdata ( rbuf, size, excpt );
01458 break;
01459 case 110:
01460 case 111: red += tlzwstreamcompression :: readdata ( rbuf, size, excpt );
01461 break;
01462 case 112: red += bzip_decompress -> readdata ( rbuf, size, excpt );
01463 break;
01464 }
01465 }
01466 return red;
01467 }
01468
01469
01470
01471 void tanycompression :: writedata ( const void* buf, int size )
01472 {
01473 bzip_compress -> writedata ( buf, size );
01474
01475 }
01476
01477
01478 int tanycompression :: readlzwdata ( void* buf, int size, bool excpt )
01479 {
01480 if ( _queue.size() ) {
01481 int got = 0;
01482
01483 char* pc = (char*) buf;
01484
01485 while ( size && _queue.size() ) {
01486 *pc = _queue.front();
01487 _queue.pop();
01488 pc++;
01489 size--;
01490 got++;
01491 }
01492
01493 if ( size )
01494 got += readcmpdata ( pc, size, excpt );
01495
01496 return got;
01497 } else
01498 return readcmpdata ( buf, size, excpt );
01499 }
01500
01501 void tanycompression :: writelzwdata ( const void* buf, int size )
01502 {
01503 writecmpdata ( buf, size );
01504 }
01505
01506
01507 void tanycompression :: close_compression ( void )
01508 {
01509 if ( bzip_compress ) {
01510 bzip_compress->close_compression ( );
01511 delete bzip_compress;
01512 bzip_compress = NULL;
01513 }
01514 }
01515
01516
01517 tanycompression :: ~tanycompression ( )
01518 {
01519 if ( bzip_decompress ) {
01520 delete bzip_decompress;
01521 bzip_decompress = NULL;
01522 }
01523
01524 }
01525
01526
01528
01529
01530
01531
01532
01533
01534
01535
01536
01537
01538
01539
01540
01541
01542
01543
01544
01545
01546
01547
01548
01549
01550
01551
01552
01553
01554
01555
01556
01557
01559
01560 void tn_lzw_file_buf_stream :: writedata ( const void* buf, int size )
01561 {
01562 tanycompression :: writedata ( buf, size );
01563 }
01564
01565 int tn_lzw_file_buf_stream :: readdata ( void* buf, int size, bool excpt )
01566 {
01567 return tanycompression :: readdata ( buf, size, excpt );
01568 }
01569
01570 int tn_lzw_file_buf_stream:: readcmpdata ( void* buf, int size, bool excpt )
01571 {
01572 return tn_file_buf_stream :: readdata ( buf, size, excpt );
01573 }
01574
01575 void tn_lzw_file_buf_stream :: writecmpdata ( const void* buf, int size )
01576 {
01577 tn_file_buf_stream :: writedata ( buf, size );
01578 }
01579
01580 tn_lzw_file_buf_stream :: ~tn_lzw_file_buf_stream()
01581 {
01582 close_compression ();
01583 tn_file_buf_stream :: close();
01584 }
01585
01586
01588
01589
01590 tn_c_lzw_filestream :: tn_c_lzw_filestream ( const ASCString& name, IOMode mode ) : tanycompression ( mode )
01591 {
01592 #ifdef logfiles
01593 FILE* fp = fopen ( "files.lst", "at" );
01594 fprintf ( fp, "%s\n", name );
01595 fclose ( fp );
01596 #endif
01597
01598 strm = NULL;
01599 inp = 0;
01600 containerstream = NULL;
01601
01602 FileLocation fl;
01603 if ( mode == tnstream::reading ) {
01604 locateFile ( name, &fl );
01605
01606 if ( !fl.found )
01607 throw tfileerror ( name );
01608
01609 } else {
01610 fl.directoryLevel = 0;
01611 fl.container = NULL;
01612 }
01613
01614
01615 if ( fl.container == NULL ) {
01616 char string[2000];
01617
01618 ASCString fileNameComplete = constructFileName ( string, fl.directoryLevel, NULL, name.c_str());
01619 strm = new tn_file_buf_stream ( fileNameComplete, mode );
01620 inp = 1;
01621 devicename = fileNameComplete;
01622 location = fileNameComplete;
01623
01624 } else {
01625 containerstream = fl.container;
01626 if ( containerstream ) {
01627 inp = 2;
01628 containerstream->opencontainerfile ( name.c_str() );
01629 devicename = name;
01630 location = name + " located inside " + containerstream->getDeviceName();
01631 } else
01632 throw tfileerror ( name );
01633 }
01634 fname = name;
01635
01636 tanycompression :: init ( );
01637 }
01638
01639 ASCString tn_c_lzw_filestream::getArchive()
01640 {
01641 if ( containerstream )
01642 return containerstream->getDeviceName();
01643 else
01644 return "";
01645 }
01646
01647
01648 ASCString tn_c_lzw_filestream::getLocation()
01649 {
01650 return location;
01651 }
01652
01653 int tn_c_lzw_filestream :: getSize ( void )
01654 {
01655 if ( inp == 2 )
01656 return containerstream->getSize();
01657 else
01658 return strm->getSize();
01659 }
01660
01661 void tn_c_lzw_filestream :: writecmpdata ( const void* buf, int size )
01662 {
01663 if ( inp == 2 )
01664 throw tinvalidmode ( fname, tnstream::reading, tnstream::writing );
01665 else
01666 strm->writedata ( buf, size );
01667 }
01668
01669 int tn_c_lzw_filestream :: readcmpdata ( void* buf, int size, bool excpt )
01670 {
01671 if ( inp == 2 )
01672 return containerstream->readcontainerdata ( buf, size, excpt );
01673 else
01674 return strm->readdata ( buf, size, excpt );
01675 };
01676
01677
01678 void tn_c_lzw_filestream :: writedata ( const void* buf, int size )
01679 {
01680 tanycompression :: writedata ( buf, size );
01681 }
01682
01683 int tn_c_lzw_filestream :: readdata ( void* buf, int size, bool excpt )
01684 {
01685 if ( tanycompression :: mode == readingdirect && !tempbuf.size() )
01686 if ( inp == 2 )
01687 return containerstream->readcontainerdata ( buf, size, excpt );
01688 else
01689 return strm->readdata ( buf, size, excpt );
01690 else
01691 return tanycompression :: readdata ( buf, size, excpt );
01692 };
01693
01694
01695 time_t tn_c_lzw_filestream :: get_time ( void )
01696 {
01697 if ( inp == 2 )
01698 return containerstream->get_time();
01699 else
01700 return strm->get_time();
01701 }
01702
01703 tn_c_lzw_filestream :: ~tn_c_lzw_filestream()
01704 {
01705 try {
01706 displayLogMessage( 9, "~tn_c_lzw_filestream " + getLocation() );
01707
01708 close_compression ();
01709 close();
01710 if ( inp == 1 ) {
01711 delete strm;
01712 strm = NULL;
01713 } else {
01714 displayLogMessage( 9, ASCString("~tn_c_lzw_filestream -> closecontainerfile ") );
01715 containerstream->closecontainerfile();
01716 }
01717 } catch ( ... ) {
01718 displayLogMessage( 9, ASCString("~tn_c_lzw_filestream : caught exception") );
01719 throw;
01720 }
01721 }
01722
01723
01724
01726
01727 static const char asciiCodingTable[64] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
01728 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
01729 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
01730 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
01731 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
01732 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
01733 'w', 'x', 'y', 'z', '0', '1', '2', '3',
01734 '4', '5', '6', '7', '8', '9', '+', '/' };
01735
01736
01737 ASCIIEncodingStream::ASCIIEncodingStream() : shift(0), buf(0) {};
01738
01739 void ASCIIEncodingStream::writedata ( const void* buf, int size ) {
01740 const char* c = (const char*)buf;
01741 for ( int i = 0; i < size; ++i )
01742 put ( c[i] );
01743 }
01744 int ASCIIEncodingStream::readdata ( void* buf, int size, bool excpt ) {
01745 throw tinvalidmode ( "Base64SerializingStream", reading, writing );
01746 }
01747
01748 void ASCIIEncodingStream::put( char c )
01749 {
01750 if ( shift == 0 ) {
01751 buf = c >> 6;
01752 shift = 2;
01753 result += asciiCodingTable[c & 63];
01754 } else if ( shift == 2 ) {
01755 buf |= ( c << 2) & 63;
01756 result += asciiCodingTable[buf];
01757 buf = c >> 4;
01758 shift = 4;
01759 } else if ( shift==4 ) {
01760 buf |= (c << 4) & 63;
01761 result += asciiCodingTable[buf];
01762 shift = 0;
01763 result += asciiCodingTable[int((c>>2) & 63)];
01764 }
01765 }
01766 void ASCIIEncodingStream::flush() {
01767 if ( shift )
01768 result += asciiCodingTable[buf & 63];
01769 result += "#";
01770 }
01771
01772 ASCString ASCIIEncodingStream::getResult()
01773 {
01774 flush();
01775 return result;
01776 }
01777
01778 void ASCIIDecodingStream :: generateTable()
01779 {
01780 for ( int i = 0; i< 256; ++i )
01781 reverse[i] = -1;
01782 for ( int i = 0; i < sizeof(asciiCodingTable); ++i )
01783 reverse[ int(asciiCodingTable[i])] = i;
01784 }
01785
01786 int ASCIIDecodingStream :: get()
01787 {
01788 if ( length < data.length() ) {
01789 int c = data.at(length);
01790 if ( c == '#' )
01791 throw treadafterend("ASCIIDecodingStream");
01792 ++length;
01793
01794 if ( reverse[c] == -1 )
01795 throw ASCmsgException("Invalid ASCII data to decode");
01796
01797 return reverse[c];
01798 } else
01799 throw treadafterend("ASCIIDecodingStream");
01800 }
01801
01802 ASCIIDecodingStream :: ASCIIDecodingStream( const ASCString& data) : shift(0), buf(0), length(0)
01803 {
01804 this->data = data;
01805 generateTable();
01806 }
01807
01808 void ASCIIDecodingStream :: writedata ( const void* buf, int size )
01809 {
01810 throw tinvalidmode ( "ASCIIDecodingStream", writing, reading );
01811 }
01812
01813 int ASCIIDecodingStream :: readdata ( void* buffer, int size, bool excpt )
01814 {
01815 int i = 0;
01816 try {
01817 char* cbuf = (char*) buffer;
01818 for ( i = 0; i < size; ++i ) {
01819 if ( shift == 0 ) {
01820 char c = get();
01821 char c2 = get();
01822 cbuf[i] = c | ((c2 << 6) & 0xff);
01823 shift = 2;
01824 buf = c2 >> 2;
01825 } else if ( shift == 2 ) {
01826 char c = get();
01827 cbuf[i] = buf | ((c << 4) & 0xff );
01828 buf = c >> 4;
01829 shift = 4;
01830 } else if ( shift == 4 ) {
01831 char c = get();
01832 cbuf[i] = buf | (c << 2 );
01833 shift = 0;
01834 }
01835 }
01836 }
01837 catch ( treadafterend trae ) {
01838 if ( excpt )
01839 throw trae;
01840 }
01841 return i;
01842 }
01843
01844
01845 StreamCompressionFilter :: StreamCompressionFilter( tnstream* outputstream )
01846 : adapter( outputstream), compressor( &adapter ), closed(false) {
01847
01848 }
01849
01850 void StreamCompressionFilter :: writedata ( const void* buf, int size )
01851 {
01852 compressor.writedata(buf,size);
01853 }
01854
01855 int StreamCompressionFilter :: readdata ( void* buf, int size, bool excpt )
01856 {
01857 throw tinvalidmode ( "StreamCompressionFilter", reading, writing );
01858 }
01859
01860 void StreamCompressionFilter :: close()
01861 {
01862 if ( closed )
01863 return;
01864
01865 compressor.close_compression();
01866 closed = true;
01867 }
01868
01869 StreamCompressionFilter ::~StreamCompressionFilter()
01870 {
01871 close();
01872 }
01873
01874
01875 StreamDecompressionFilter :: StreamDecompressionFilter( tnstream* inputstream ) : adapter( inputstream), decompressor( &adapter ) {
01876
01877 }
01878
01879 void StreamDecompressionFilter :: writedata ( const void* buf, int size )
01880 {
01881 throw tinvalidmode ( "StreamCompressionFilter", writing, reading );
01882 }
01883
01884 int StreamDecompressionFilter :: readdata ( void* buf, int size, bool excpt )
01885 {
01886 return decompressor.readdata(buf,size,excpt);
01887 }
01888
01890 int compressrle ( const void* p, void* q)
01891 {
01892 trleheader* sourcehead = (trleheader*) p;
01893 if ( sourcehead->id == 16973 ) {
01894 memcpy ( q, p, sourcehead->size + sizeof ( trleheader ) );
01895 return sourcehead->size + sizeof ( trleheader );
01896 }
01897
01898
01899 char* s = (char*) p;
01900 char* d = (char*) q;
01901
01902 trleheader* header = (trleheader*) q;
01903
01904 Uint16 x,y;
01905 int size;
01906 {
01907 Uint16* pw = (Uint16*) s;
01908 x = pw[0];
01909 y = pw[1];
01910
01911 header->x = x;
01912 header->y = y;
01913
01914 x++;
01915 y++;
01916
01917 size = x * y;
01918
01919 header->id = 16973;
01920 }
01921
01922 {
01923 int bts[256];
01924 memset ( bts, 0, sizeof ( bts ));
01925 for ( int i = 0; i < size ;i++ )
01926 bts[int(s[i+4])]++;
01927
01928 int min = 70000;
01929 for ( int i = 0; i < 256; i++ )
01930 if ( bts[i] < min ) {
01931 min = bts[i];
01932 header->rle = i;
01933 }
01934
01935 }
01936
01937 s+=4;
01938 d+=sizeof ( trleheader );
01939
01940 {
01941 char* startpos = d;
01942 int xp;
01943
01944 for (int j = 0; j < y ; j++ ) {
01945 xp = 0;
01946 unsigned char num;
01947 unsigned char actbyte ;
01948
01949 do {
01950 num = 1;
01951 actbyte = *s;
01952
01953 while ( xp+num < x && num < 255 && s[num] == actbyte )
01954 num++;
01955
01956 if ( num > 2 || actbyte == header->rle ) {
01957 *(d++) = header->rle;
01958 *(d++) = num;
01959 *(d++) = actbyte;
01960 } else {
01961 *(d++) = actbyte;
01962 if ( num > 1 )
01963 *(d++) = actbyte;
01964 }
01965
01966 s += num;
01967 xp += num;
01968 } while ( xp < x );
01969
01970
01971 }
01972
01973 header->size = d - startpos;
01974 }
01975 return header->size + sizeof ( trleheader );
01976 }
01977
01979
01980
01981
01982
01983 bool patimat (const char *pat, const char *str, bool forceCaseInsensitivity )
01984 {
01985 switch (*pat)
01986 {
01987 case '\0':
01988 return !*str;
01989
01990 case '*' :
01991 return patimat(pat+1, str, forceCaseInsensitivity) || (*str && patimat(pat, str+1, forceCaseInsensitivity));
01992
01993 case '?' :
01994 return *str && patimat(pat+1, str+1, forceCaseInsensitivity);
01995
01996 default :
01997 if ( forceCaseInsensitivity ||
01998 #if CASE_SENSITIVE_FILE_NAMES == 0
01999 true
02000 #else
02001 false
02002 #endif
02003 )
02004 return (toupper(*pat) == toupper(*str)) && patimat(pat+1, str+1, forceCaseInsensitivity);
02005 else
02006 return (*pat == *str) && patimat(pat+1, str+1, forceCaseInsensitivity );
02007 }
02008 }
02009
02010 bool patimat (const ASCString& pat, const ASCString& str, bool forceCaseInsensitivity)
02011 {
02012 return patimat( pat.c_str(), str.c_str(), forceCaseInsensitivity );
02013 }
02014
02015
02016 tfindfile :: tfindfile ( ASCString name, SearchPosition searchPosition, SearchTypes searchTypes )
02017 {
02018 convertPathDelimitters ( name );
02019
02020 if ( searchPosition == DefaultDir )
02021 searchPosition = AllDirs;
02022
02023
02024 if ( searchDirNum == 0 )
02025 searchPosition = CurrentDir;
02026
02027 found = 0;
02028 act = 0;
02029 if ( name.empty() )
02030 return;
02031
02032 ASCString directory[maxSearchDirNum];
02033 int dirNum;
02034 ASCString wildcard;
02035
02036 int ppos = name.rfind ( pathdelimitterstring );
02037 if ( ppos != name.npos ) {
02038
02039
02040
02041
02042 bool absolute = false;
02043 if ( name[0] == pathdelimitter )
02044 absolute = true;
02045
02046 if ( has_drive_letters && name.length() > 3 && name.find ( ":\\", 1 ) != name.npos )
02047 absolute = true;
02048
02049 if ( absolute || searchPosition == CurrentDir ) {
02050 directory[0].assign ( name, 0, ppos );
02051 dirNum = 1;
02052 } else {
02053 ASCString strippedPath;
02054 strippedPath.assign ( name, 0, ppos );
02055 if ( strippedPath.find ( ASCString(".") + pathdelimitterstring ) == 0 )
02056 strippedPath.erase( 0, 2);
02057
02058 int upDir = 0;
02059 while ( strippedPath.find ( ASCString("..") + pathdelimitterstring ) == 0 ) {
02060 upDir++;
02061 strippedPath.erase ( 0, 3 );
02062 }
02063
02064 int dirsToProcess;
02065 if ( searchPosition == AllDirs ) {
02066 dirsToProcess = searchDirNum;
02067 } else
02068 dirsToProcess = 1;
02069
02070 dirNum = 0;
02071 for ( int i = 0; i < dirsToProcess; i++ ) {
02072 ASCString dir = ascDirectory[i];
02073
02074
02075 dir.erase ( dir.length() -1 );
02076
02077 for ( int j = 0; j < upDir; j++ ) {
02078 int pos = dir.rfind ( pathdelimitterstring );
02079 if ( pos > 0 && pos == dir.npos )
02080 dir.erase ( pos );
02081 }
02082
02083
02084 dir += pathdelimitterstring;
02085
02086 directory[dirNum++] = dir + strippedPath;
02087 }
02088
02089 if ( !dirNum ) {
02090 directory[0] = ".";
02091 dirNum = 1;
02092 }
02093
02094 }
02095
02096 wildcard.assign ( name, ppos+1, name.npos );
02097
02098 } else {
02099 if ( searchDirNum ) {
02100 for (int i = 0; i < searchDirNum; i++ )
02101 directory[i] = ascDirectory[i];
02102 dirNum = searchDirNum;
02103 } else {
02104 directory[0] = ".";
02105 dirNum = 1;
02106 }
02107 wildcard = name;
02108 }
02109
02110 if ( searchTypes == All || searchTypes == OutsideContainer )
02111 for ( int i = 0; i < dirNum; i++ ) {
02112 DIR *dirp;
02113 struct ASC_direct *direntp;
02114
02115 dirp = opendir( directory[i].c_str() );
02116 if( dirp != NULL ) {
02117 for(;;) {
02118 direntp = readdir( dirp );
02119 if ( direntp == NULL )
02120 break;
02121
02122 if ( patimat ( wildcard.c_str(), direntp->d_name )) {
02123 int localfound = 0;
02124 for ( int j = 0; j < found; j++ )
02125 if ( strcmpi ( fileInfo[j].name.c_str(), direntp->d_name ) == 0 )
02126 localfound++;
02127
02128 if ( !localfound ) {
02129 FileInfo fi;
02130 fi.name = direntp->d_name;
02131 fi.directoryLevel = i ;
02132 fi.isInContainer = false ;
02133 fi.location = directory[i];
02134
02135 char buf[1000];
02136 ASCString fullName = constructFileName( buf, i, NULL, direntp->d_name );
02137
02138 struct stat statbuf;
02139 stat( fullName.c_str(), &statbuf);
02140
02141 fi.size = statbuf.st_size ;
02142 fi.date = statbuf.st_mtime;
02143
02144 fileInfo.push_back ( fi );
02145
02146 found++;
02147 }
02148 }
02149 }
02150 closedir( dirp );
02151 }
02152 }
02153
02154
02155
02156 if ( searchTypes == All || searchTypes == InsideContainer ) {
02157 const ContainerCollector::FileIndex* c = containercollector.getfirstname();
02158 while ( c ) {
02159 if ( patimat ( name.c_str(), c->name ) ) {
02160 int f = 0;
02161 for ( int i = 0; i < found; i++ )
02162 if ( stricmp ( c->name.c_str(), fileInfo[i].name.c_str() ) == 0 ) {
02163 if ( fileInfo[i].directoryLevel <= c->directoryLevel )
02164 f = 1;
02165 else {
02166 FileInfo& fi = fileInfo[i];
02167 fi.name = c->name ;
02168 fi.isInContainer = true;
02169 fi.directoryLevel = c->directoryLevel;
02170 fi.location = c->container->getDeviceName();
02171
02172 fi.size = c->container->getstreamsize();
02173 fi.date = c->container->get_time();
02174 f = 1;
02175 }
02176 }
02177
02178 if ( !f ) {
02179 FileInfo fi;
02180 fi.name = c->name ;
02181 fi.directoryLevel = c->directoryLevel ;
02182 fi.isInContainer = true ;
02183 fi.location = c->container->getDeviceName() ;
02184
02185 fi.size = c->container->getstreamsize() ;
02186 fi.date = c->container->get_time() ;
02187 fileInfo.push_back ( fi );
02188 found++;
02189 }
02190 }
02191 c = containercollector.getnextname();
02192 }
02193 }
02194 }
02195
02196
02197 ASCString tfindfile :: getnextname ( int* loc, bool* inContainer, ASCString* location )
02198 {
02199 if ( act < found ) {
02200 if ( loc )
02201 *loc = fileInfo[act].directoryLevel;
02202
02203 if ( inContainer )
02204 *inContainer = fileInfo[act].isInContainer;
02205
02206 if ( location )
02207 *location = fileInfo[act].location;
02208
02209
02210
02211
02212
02213
02214
02215
02216 return fileInfo[act++].name;
02217 } else {
02218 if ( loc )
02219 *loc = -1;
02220
02221 return "";
02222 }
02223 }
02224
02225 bool tfindfile :: getnextname ( FileInfo& fi )
02226 {
02227 if ( act < found ) {
02228 fi = fileInfo[act++];
02229 return true;
02230 } else
02231 return false;
02232 }
02233
02234
02236
02237
02238
02239
02240
02241 int checkforvaliddirectory ( char* dir )
02242 {
02243 int stat = 0;
02244
02245 DIR *dirp;
02246 struct ASC_direct *direntp;
02247
02248
02249
02250
02251
02252
02253
02254
02255 dirp = opendir( dir );
02256 if( dirp != NULL ) {
02257 for(;;) {
02258 direntp = readdir( dirp );
02259 if ( direntp == NULL )
02260 break;
02261
02262 if ( strcmp ( direntp -> d_name, ".") == 0 )
02263 stat = 1;
02264 }
02265 closedir( dirp );
02266 }
02267
02268 return stat;
02269 }
02270
02272
02273 MemoryStreamStorage :: MemoryStreamStorage ( void )
02274 {
02275 used = 0;
02276 allocated = 0;
02277 buf = 0;
02278 memset ( dummy, 0, sizeof ( dummy ));
02279 }
02280
02281 MemoryStreamStorage :: ~MemoryStreamStorage ( void )
02282 {
02283 if ( buf ) {
02284 delete[] buf;
02285 buf = NULL;
02286 }
02287 }
02288
02289 void MemoryStreamStorage :: writetostream ( tnstream* stream )
02290 {
02291 if ( stream ) {
02292 stream->writeInt ( 0 );
02293 stream->writeInt ( used );
02294 stream->writeInt ( allocated );
02295 for ( int i = 0; i < 10; i++ )
02296 stream->writeInt ( dummy[i] );
02297 if ( used > 0 )
02298 stream->writedata ( buf, used );
02299 }
02300 }
02301
02302 void MemoryStreamStorage :: readfromstream ( tnstream* stream )
02303 {
02304 if ( stream ) {
02305 stream->readInt();
02306 used = stream->readInt();
02307 allocated = stream->readInt();
02308 for ( int i = 0; i< 10; i++ )
02309 dummy[i] = stream->readInt();
02310
02311 if ( buf ) {
02312 delete[] buf;
02313 buf = NULL;
02314 }
02315 if ( used > 0 || allocated > 0 ) {
02316 allocated = max(allocated,used);
02317 buf = new char[allocated];
02318 stream->readdata ( buf, used );
02319 }
02320 }
02321 }
02322
02323
02324 MemoryStream :: MemoryStream ( MemoryStreamStorage* lbuf, IOMode lmode )
02325 {
02326
02327 blocksize = 1024;
02328 buf = lbuf;
02329 _mode = lmode;
02330
02331 if ( !buf )
02332 throw tfileerror ( "memorystream" );
02333
02334
02335 if ( _mode == reading ) {
02336 pointer = buf->buf;
02337 actmempos = 0;
02338 } else
02339 if ( _mode == writing ) {
02340 if ( buf->buf ) {
02341 delete[] buf->buf;
02342 buf->buf = NULL;
02343 }
02344 buf->buf = new char[blocksize];
02345 buf->allocated = blocksize;
02346 buf->used = 0;
02347 pointer = buf->buf;
02348 actmempos = 0;
02349 }
02350 if ( _mode == appending ) {
02351 pointer = buf->buf;
02352 actmempos = buf->used;
02353 _mode = writing;
02354 }
02355 }
02356
02357 void MemoryStream :: writedata ( const void* nbuf, int size )
02358 {
02359 if ( _mode != writing )
02360 throw tinvalidmode ( "memorystream", _mode, writing );
02361
02362 if ( buf->used + size > buf->allocated ) {
02363 int newsize = ((buf->used + size + blocksize - 1) / blocksize);
02364 newsize *= blocksize;
02365 char* tmp = new char[newsize];
02366 memcpy ( tmp, buf->buf, buf->used );
02367 delete[] buf->buf;
02368 buf->buf = tmp;
02369 buf->allocated = newsize;
02370 }
02371
02372 memcpy ( &buf->buf[buf->used], nbuf, size );
02373 buf->used += size;
02374 }
02375
02376
02377 int MemoryStream :: readdata ( void* nbuf, int size, bool excpt )
02378 {
02379 if (_mode != reading )
02380 throw tinvalidmode ( "memorystream", _mode, reading );
02381
02382 if ( actmempos + size > buf->used ) {
02383 if ( excpt )
02384 throw treadafterend ( "memory stream" );
02385 else
02386 size = buf->used-actmempos;
02387 }
02388
02389 memcpy ( nbuf, &buf->buf[actmempos], size );
02390 actmempos += size;
02391 return size;
02392 }
02393
02394 int MemoryStream :: dataavail ( void )
02395 {
02396 if ( _mode == writing )
02397 return 1;
02398 else
02399 return actmempos < buf->used;
02400 }
02401
02402
02403
02404 ASCString getnextfilenumname ( const ASCString& first, const ASCString& suffix, int num )
02405 {
02406 ASCString name;
02407
02408 if ( num < 0 )
02409 num = 0;
02410
02411 do {
02412 name = first;
02413 while ( name.length() - first.length() + ASCString::toString(num).length() < 3 )
02414 name += "0";
02415
02416 name += ASCString::toString(num) + "." + suffix;
02417
02418 tfindfile ff ( name );
02419 ASCString c = ff.getnextname();
02420 if ( c.empty() )
02421 return name;
02422
02423 num++;
02424 } while ( true );
02425
02426 return "";
02427 }
02428
02429
02430 bool exist ( const ASCString& s )
02431 {
02432 tfindfile ff ( s );
02433 return !ff.getnextname().empty();
02434 }
02435
02436
02437
02438 #include "oldlzw.cpp"
02439
02440 void tnbufstream :: writebuffer( void ) {
02441 }
02442
02443 void opencontainer ( const char* wildcard )
02444 {
02445 if ( !searchDirNum )
02446 addSearchPath(".");
02447
02448 containercollector.init ( wildcard );
02449 }
02450
02451
02452
02453
02454 time_t get_filetime ( const char* fileName )
02455 {
02456 FileLocation fl;
02457 locateFile ( fileName, &fl );
02458
02459 if ( fl.found ) {
02460 if ( fl.container )
02461 return fl.container->get_time();
02462 else {
02463 struct stat stbuf;
02464 char buf[ maxFileStringSize ];
02465 if ( !stat ( constructFileName ( buf, fl.directoryLevel, NULL, fileName), &stbuf) )
02466 return ( stbuf.st_mtime);
02467 else
02468 return -1;
02469 }
02470 } else
02471 return -1;
02472 }
02473
02474
02475 int filesize( const char *name)
02476 {
02477 struct stat buf;
02478
02479 if ( !stat (name, &buf))
02480 return (buf.st_size);
02481 else
02482 return -1;
02483 }
02484
02485
02486 bool directoryExist ( const ASCString& path )
02487 {
02488 bool existence = false;
02489
02490 DIR *dirp = opendir( path.c_str() );
02491
02492 if( dirp ) {
02493 if ( readdir( dirp ) )
02494 existence = true;
02495 else
02496 existence = false;
02497
02498 closedir( dirp );
02499 }
02500 return existence;
02501 }
02502
02503 void addSearchPath ( const ASCString& path )
02504 {
02505 if ( !path.empty() ) {
02506 ASCString s = constructFileName ( -3, path, "" );
02507
02508 if ( directoryExist( s.c_str() )) {
02509 bool found = false;
02510 for ( int i = 0; i < searchDirNum; i++ )
02511 if ( s == ascDirectory[i] )
02512 found = true;
02513
02514 if ( !found )
02515 ascDirectory[ searchDirNum++ ] = strdup ( s.c_str() );
02516 }
02517 }
02518 }
02519
02520 int getSearchPathNum()
02521 {
02522 return searchDirNum;
02523 }
02524
02525 ASCString getSearchPath ( int i )
02526 {
02527 if ( i < searchDirNum )
02528 return ascDirectory[i];
02529 else
02530 return "";
02531 }
02532
02533
02534 char* extractPath ( char* buf, const char* filename )
02535 {
02536 if ( buf && filename ) {
02537 if ( strchr ( filename, pathdelimitter )) {
02538 strcpy ( buf, filename );
02539 int i = strlen ( buf )-1;
02540 while ( buf[i] != pathdelimitter )
02541 i--;
02542
02543 buf[i+1] = 0;
02544 } else
02545 strcpy ( buf, "./" );
02546 }
02547 return buf;
02548 }
02549
02550 char* extractFileName ( char* buf, const char* filename )
02551 {
02552 if ( buf && filename ) {
02553 if ( strchr ( filename, pathdelimitter )) {
02554 int i = strlen ( filename )-1;
02555 while ( filename[i] != pathdelimitter )
02556 i--;
02557
02558 strcpy ( buf, filename +i+1);
02559 } else
02560 strcpy ( buf, filename );
02561 }
02562 return buf;
02563 }
02564
02565 ASCString extractFileName ( const ASCString& filename )
02566 {
02567 char buf[10000];
02568 return extractFileName( buf, filename.c_str() );
02569 }
02570
02571 ASCString extractFileName_withoutSuffix ( const ASCString& filename )
02572 {
02573 char buf[10000];
02574 extractFileName( buf, filename.c_str() );
02575 char* c = strchr ( buf, '.' );
02576 if ( c )
02577 *c = 0;
02578 return ASCString(buf);
02579 }
02580
02581
02582 void appendbackslash ( char* string )
02583 {
02584 if ( strlen ( string ) && string[strlen ( string ) -1] != pathdelimitter )
02585 strcat ( string, pathdelimitterstring );
02586 }
02587
02588 void appendbackslash ( ASCString& string )
02589 {
02590 if ( !string.empty() && string[ string.length() -1] != pathdelimitter )
02591 string += pathdelimitterstring ;
02592 }
02593
02594
02595 int createDirectory ( const char* name )
02596 {
02597 #ifdef _UNIX_
02598 char *nname;
02599 int i;
02600
02601 if (name == NULL || (nname=strdup(name)) == NULL)
02602 return -1;
02603 i = strlen(nname);
02604
02605 while (i>1 && nname[i-1] == '/')
02606 nname[--i] = '\0';
02607 i = mkdir ( nname, 0700 );
02608 free(nname);
02609
02610 return i;
02611 #else
02612 return mkdir ( name );
02613 #endif
02614 }
02615
02616
02617 ASCString FileName::suffix ( )
02618 {
02619 size_type slash = find_last_of ( pathdelimitterstring );
02620 size_type point = find_last_of ( "." );
02621 if ( point == npos )
02622 return "";
02623 else
02624 if ( slash == npos || slash < point )
02625 return substr(point+1);
02626 else
02627 return "";
02628 }
02629
02630
02631
02632 void convertPathDelimitters ( ASCString& path )
02633 {
02634 int pos;
02635 while ( (pos = path.find ( foreignPathDelimitterString )) != path.npos )
02636 path.replace ( pos, 1, pathdelimitterstring );
02637 }