Diff

Not logged in

Differences From Artifact [9075347c70b2342c]:

To Artifact [3b6f189d5603825c]:


> 1 private import win32.windows; 1 private import std.string; | 2 private import std.string; 2 private import std.file; 3 private import std.file; 3 private import std.c.stdio; 4 private import std.c.stdio; > 5 private import std.string; 4 private import etc.c.zlib; 6 private import etc.c.zlib; 5 private import win32.ansi.windows; < 6 private import libbz2.bzlib; 7 private import libbz2.bzlib; 7 private import util; 8 private import util; 8 9 9 //---------------------------------------------------------------- 10 //---------------------------------------------------------------- 10 // Bga書庫のファイルヘッダ形式 11 // Bga書庫のファイルヘッダ形式 11 //---------------------------------------------------------------- 12 //---------------------------------------------------------------- 12 13 ................................................................................................................................................................................ 23 ubyte header_type; // ヘッダの種類( 現在は常に 0 ) 24 ubyte header_type; // ヘッダの種類( 現在は常に 0 ) 24 ushort arc_type; // アーカイブタイプ 25 ushort arc_type; // アーカイブタイプ 25 // 0:(ext==↓?非圧縮:圧縮) 1:圧縮 2:非圧縮 26 // 0:(ext==↓?非圧縮:圧縮) 1:圧縮 2:非圧縮 26 // .ARC, .ARJ, .BZ2, .BZA, .CAB, .GZ, .GZA, 27 // .ARC, .ARJ, .BZ2, .BZA, .CAB, .GZ, .GZA, 27 // .LZS, .PAK, .RAR, .TAZ, .TBZ, .TGZ, .Z, 28 // .LZS, .PAK, .RAR, .TAZ, .TBZ, .TGZ, .Z, 28 ushort dir_name_len; // ディレクトリ名の長さ 29 ushort dir_name_len; // ディレクトリ名の長さ 29 ushort file_name_len; // ファイル名の長さ 30 ushort file_name_len; // ファイル名の長さ 30 char[] fname; // dir_name_len + file_name_len ( no '\0' ) | 31 string fname; // dir_name_len + file_name_len ( no '\0' ) 31 } 32 } 32 33 33 //---------------------------------------------------------------- 34 //---------------------------------------------------------------- 34 // エラー発生時に投げる例外 35 // エラー発生時に投げる例外 35 //---------------------------------------------------------------- 36 //---------------------------------------------------------------- 36 37 37 class BgaMelterError : Error 38 class BgaMelterError : Error ................................................................................................................................................................................ 90 } 91 } 91 92 92 class Filep 93 class Filep 93 { 94 { 94 private FILE* fp; 95 private FILE* fp; 95 private this( FILE* p ) { fp = p; } 96 private this( FILE* p ) { fp = p; } 96 97 97 static Filep open( char[] filename, bool read ) | 98 static Filep open( string filename, bool read ) 98 { 99 { 99 FILE* fp = fopen( toStringz(filename), read?"rb":"wb" ); 100 FILE* fp = fopen( toStringz(filename), read?"rb":"wb" ); 100 return (fp ? new Filep(fp) : null); 101 return (fp ? new Filep(fp) : null); 101 } 102 } 102 103 103 int dup_han() 104 int dup_han() 104 { 105 { ................................................................................................................................................................................ 106 lseek( fd, cur(), 0 ); 107 lseek( fd, cur(), 0 ); 107 return fd; 108 return fd; 108 } 109 } 109 110 110 void[] read( int siz ) 111 void[] read( int siz ) 111 { 112 { 112 char[] buf; buf.length = siz; 113 char[] buf; buf.length = siz; 113 int rsiz = fread( buf, 1, siz, fp ); | 114 int rsiz = fread( buf.ptr, 1, siz, fp ); 114 if( rsiz < 0 ) 115 if( rsiz < 0 ) 115 throw new BgaMelterError(ERROR_FILE_OPEN); 116 throw new BgaMelterError(ERROR_FILE_OPEN); 116 buf.length = rsiz; 117 buf.length = rsiz; 117 return buf; 118 return buf; 118 } 119 } 119 120 120 void write( void[] buf ) 121 void write( void[] buf ) 121 { 122 { 122 while( buf.length > 0 ) 123 while( buf.length > 0 ) 123 { 124 { 124 int rsiz = fwrite( buf, 1, buf.length, fp ); | 125 int rsiz = fwrite( buf.ptr, 1, buf.length, fp ); 125 if( rsiz < 0 ) return; 126 if( rsiz < 0 ) return; 126 buf = buf[rsiz .. length]; | 127 buf = buf[rsiz .. $]; 127 } 128 } 128 } 129 } 129 130 130 int cur() 131 int cur() 131 { 132 { 132 return ftell(fp); 133 return ftell(fp); 133 } 134 } ................................................................................................................................................................................ 151 152 152 //---------------------------------------------------------------- 153 //---------------------------------------------------------------- 153 // メインクラス 154 // メインクラス 154 //---------------------------------------------------------------- 155 //---------------------------------------------------------------- 155 156 156 class BgaMelter 157 class BgaMelter 157 { 158 { 158 alias BgaAnswer delegate(inout BgaHeader) FileHandler; | 159 alias BgaAnswer delegate(ref BgaHeader) FileHandler; 159 alias BgaAnswer delegate(int, int) ProgressHandler; 160 alias BgaAnswer delegate(int, int) ProgressHandler; 160 161 161 private Filep fp = null; 162 private Filep fp = null; 162 163 163 this( char[] arc_name ) | 164 this( string arc_name ) 164 { 165 { 165 fp = Filep.open( arc_name, true ); 166 fp = Filep.open( arc_name, true ); 166 if( fp is null ) 167 if( fp is null ) 167 throw new BgaMelterError(ERROR_FILE_OPEN); 168 throw new BgaMelterError(ERROR_FILE_OPEN); 168 } 169 } 169 170 170 void close() 171 void close() ................................................................................................................................................................................ 212 bContinue = GzDec( hdr.compresse 213 bContinue = GzDec( hdr.compresse 213 else if( hdr.method == "BZ2\0" ) 214 else if( hdr.method == "BZ2\0" ) 214 bContinue = BzDec( hdr.original_ 215 bContinue = BzDec( hdr.original_ 215 216 216 // 閉じて属性設定 217 // 閉じて属性設定 217 outf.close(); 218 outf.close(); 218 dosSetFTime( hdr.fname, hdr.date, hdr.ti 219 dosSetFTime( hdr.fname, hdr.date, hdr.ti 219 SetFileAttributes( hdr.fname, hdr.attrib | 220 SetFileAttributesA( toStringz(hdr.fname) 220 if( !bContinue ) 221 if( !bContinue ) 221 return; 222 return; 222 } 223 } 223 finally { fp.seek_to(nextpos); } 224 finally { fp.seek_to(nextpos); } 224 } 225 } 225 } 226 } 226 finally { close(); } 227 finally { close(); } ................................................................................................................................................................................ 230 { 231 { 231 int cn = c; 232 int cn = c; 232 return (cn>=0x80 ? cn|0xffffff00 : cn); 233 return (cn>=0x80 ? cn|0xffffff00 : cn); 233 } 234 } 234 235 235 private int find_header() 236 private int find_header() 236 { 237 { 237 char[] dat = cast(char[]) fp.read(0x10000); | 238 string dat = cast(string) fp.read(0x10000); 238 239 239 for( int i=0; i<dat.length-28; ++i ) 240 for( int i=0; i<dat.length-28; ++i ) 240 { 241 { 241 if( dat[i+4]!='G' && dat[i+4]!='B' ) continue; 242 if( dat[i+4]!='G' && dat[i+4]!='B' ) continue; 242 if( dat[i+5]!='Z' ) continue; 243 if( dat[i+5]!='Z' ) continue; 243 if( dat[i+6]!='I' && dat[i+6]!='2' ) continue; 244 if( dat[i+6]!='I' && dat[i+6]!='2' ) continue; 244 if( dat[i+7]!='P' && dat[i+7]!='\0') continue; 245 if( dat[i+7]!='P' && dat[i+7]!='\0') continue; ................................................................................................................................................................................ 256 257 257 return -1; 258 return -1; 258 } 259 } 259 260 260 private bool read_header( out BgaHeader hdr ) 261 private bool read_header( out BgaHeader hdr ) 261 { 262 { 262 // リトルエンディアンを仮定。ヘッダ読み込み 263 // リトルエンディアンを仮定。ヘッダ読み込み 263 char[] buf = cast(char[]) fp.read(28); | 264 string buf = cast(string) fp.read(28); 264 if( buf.length < 28 ) return false; 265 if( buf.length < 28 ) return false; 265 buf.length = BgaHeader.sizeof; 266 buf.length = BgaHeader.sizeof; 266 hdr = (cast(BgaHeader[]) buf)[0]; 267 hdr = (cast(BgaHeader[]) buf)[0]; 267 hdr.fname = ""; 268 hdr.fname = ""; 268 269 269 // ファイル名 270 // ファイル名 270 hdr.fname = cast(char[]) fp.read(hdr.dir_name_len + hdr.file_nam | 271 hdr.fname = cast(string) fp.read(hdr.dir_name_len + hdr.file_nam 271 if( hdr.fname.length < hdr.dir_name_len + hdr.file_name_len ) re 272 if( hdr.fname.length < hdr.dir_name_len + hdr.file_name_len ) re 272 273 273 // チェックサム 274 // チェックサム 274 int sum = 0; 275 int sum = 0; 275 for( int i=4; i!=28; ++i ) sum += signed_char(buf[i]); 276 for( int i=4; i!=28; ++i ) sum += signed_char(buf[i]); 276 foreach( char c ; hdr.fname ) sum += signed_char(c); 277 foreach( char c ; hdr.fname ) sum += signed_char(c); 277 return (sum == hdr.checksum); 278 return (sum == hdr.checksum); 278 } 279 } 279 280 280 private bool is_compressed( inout BgaHeader hdr ) // inout=just for opti | 281 private bool is_compressed( ref BgaHeader hdr ) // ref=just for optimiza 281 { 282 { 282 // ヘッダから、ファイルが圧縮格納されているかどうかを判定 283 // ヘッダから、ファイルが圧縮格納されているかどうかを判定 283 if( hdr.arc_type==2 ) 284 if( hdr.arc_type==2 ) 284 return false; 285 return false; 285 if( hdr.arc_type==0 && hdr.compressed_size==hdr.original_size ) 286 if( hdr.arc_type==0 && hdr.compressed_size==hdr.original_size ) 286 { 287 { 287 int x = rfind( hdr.fname, '.' ); | 288 int x = hdr.fname.lastIndexOf('.'); 288 if( x == -1 ) 289 if( x == -1 ) 289 return true; 290 return true; 290 char[] ext = tolower(hdr.fname[x+1 .. length]); | 291 string ext = toLower(hdr.fname[x+1 .. $]); 291 if( ext=="arc" || ext=="arj" || ext=="bz2" || ext=="bza" 292 if( ext=="arc" || ext=="arj" || ext=="bz2" || ext=="bza" 292 || ext=="cab" || ext=="gz" || ext=="gza" || ext=="lzh" 293 || ext=="cab" || ext=="gz" || ext=="gza" || ext=="lzh" 293 || ext=="lzs" || ext=="pak" || ext=="rar" || ext=="taz" 294 || ext=="lzs" || ext=="pak" || ext=="rar" || ext=="taz" 294 || ext=="tbz" || ext=="tgz" || ext=="z" || ext=="zip" 295 || ext=="tbz" || ext=="tgz" || ext=="z" || ext=="zip" 295 || ext=="zoo" ) 296 || ext=="zoo" ) 296 return false; 297 return false; 297 } 298 } 298 return true; 299 return true; 299 } 300 } 300 301 301 static char[] pathMake( char[] path ) | 302 static string pathMake( string path ) 302 { 303 { 303 char* ps = toStringz(path); | 304 char* ps = cast(char*)toStringz(path); 304 for(char* p=ps;;) 305 for(char* p=ps;;) 305 { 306 { 306 for(; *p!=0&&*p!='\\'&&*p!='/'; p=CharNext(p)) {} | 307 for(; *p!=0&&*p!='\\'&&*p!='/'; p=CharNextA(p)) {} 307 if( *p==0 ) 308 if( *p==0 ) 308 break; 309 break; 309 CreateDirectory( toStringz(ps[0..(p-ps)]), null ); | 310 CreateDirectoryA( toStringz(ps[0..(p-ps)]), null ); 310 ++p; 311 ++p; 311 } 312 } 312 return path; 313 return path; 313 } 314 } 314 315 315 enum { BUFSIZ = 65536 } 316 enum { BUFSIZ = 65536 } 316 317 ................................................................................................................................................................................ 317 private bool NcDec( uint usiz, Filep outf, ProgressHandler ph ) 318 private bool NcDec( uint usiz, Filep outf, ProgressHandler ph ) 318 { 319 { 319 uint init_usiz = usiz; 320 uint init_usiz = usiz; 320 321 321 // 非圧縮。コピーするだけ 322 // 非圧縮。コピーするだけ 322 while( usiz ) 323 while( usiz ) 323 { 324 { 324 char[] r = cast(char[]) fp.read( BUFSIZ<usiz?BUFSIZ:usiz | 325 string r = cast(string) fp.read( BUFSIZ<usiz?BUFSIZ:usiz 325 usiz -= r.length; 326 usiz -= r.length; 326 outf.write(r); | 327 outf.write(cast(char[])r); 327 328 328 // dlg 329 // dlg 329 if( BgaAnswer.Abort==ph(init_usiz-usiz,usiz) ) return fa 330 if( BgaAnswer.Abort==ph(init_usiz-usiz,usiz) ) return fa 330 } 331 } 331 332 332 // dlg 333 // dlg 333 if( BgaAnswer.Abort==ph(init_usiz-usiz,usiz) ) return false; 334 if( BgaAnswer.Abort==ph(init_usiz-usiz,usiz) ) return false; ................................................................................................................................................................................ 346 347 347 // zlib準備 348 // zlib準備 348 z_stream zs; 349 z_stream zs; 349 zs.zalloc = null; 350 zs.zalloc = null; 350 zs.zfree = null; 351 zs.zfree = null; 351 352 352 // 出力バッファ 353 // 出力バッファ 353 zs.next_out = outbuf; | 354 zs.next_out = outbuf.ptr; 354 zs.avail_out = outbuf.length; 355 zs.avail_out = outbuf.length; 355 356 356 // 入力バッファ 357 // 入力バッファ 357 inbuf = cast(ubyte[]) fp.read( csiz<65536 ? csiz : 65536 ); 358 inbuf = cast(ubyte[]) fp.read( csiz<65536 ? csiz : 65536 ); 358 csiz -= inbuf.length; 359 csiz -= inbuf.length; 359 zs.next_in = inbuf; | 360 zs.next_in = inbuf.ptr; 360 zs.avail_in = inbuf.length; 361 zs.avail_in = inbuf.length; 361 362 362 // スタート 363 // スタート 363 inflateInit2( &zs, -15 ); 364 inflateInit2( &zs, -15 ); 364 try { 365 try { 365 366 366 // 書庫から入力し終わるまでループ 367 // 書庫から入力し終わるまでループ ................................................................................................................................................................................ 375 if( !csiz ) 376 if( !csiz ) 376 break; 377 break; 377 378 378 if( zs.avail_in<=0 ) 379 if( zs.avail_in<=0 ) 379 { 380 { 380 inbuf = cast(ubyte[]) fp.read( csiz<6553 381 inbuf = cast(ubyte[]) fp.read( csiz<6553 381 csiz -= inbuf.length; 382 csiz -= inbuf.length; 382 zs.next_in = inbuf; | 383 zs.next_in = inbuf.ptr; 383 zs.avail_in = inbuf.length; 384 zs.avail_in = inbuf.length; 384 385 385 if( inbuf.length==0 ) 386 if( inbuf.length==0 ) 386 { 387 { 387 err = Z_STREAM_END; 388 err = Z_STREAM_END; 388 csiz = 0; 389 csiz = 0; 389 break; 390 break; ................................................................................................................................................................................ 391 } 392 } 392 } 393 } 393 394 394 int written = outbuf.length - zs.avail_out; 395 int written = outbuf.length - zs.avail_out; 395 if( usiz < written ) written = usiz; 396 if( usiz < written ) written = usiz; 396 usiz -= written; 397 usiz -= written; 397 outf.write( outbuf[0..written] ); 398 outf.write( outbuf[0..written] ); 398 zs.next_out = outbuf; | 399 zs.next_out = outbuf.ptr; 399 zs.avail_out = outbuf.length; 400 zs.avail_out = outbuf.length; 400 401 401 // dlg 402 // dlg 402 if( BgaAnswer.Abort==ph(init_usiz-usiz,usiz) ) return fa 403 if( BgaAnswer.Abort==ph(init_usiz-usiz,usiz) ) return fa 403 } 404 } 404 405 405 // 出力残しを無くす。 406 // 出力残しを無くす。 ................................................................................................................................................................................ 409 if( err!=Z_STREAM_END && err!=Z_OK ) 410 if( err!=Z_STREAM_END && err!=Z_OK ) 410 break; 411 break; 411 412 412 int written = outbuf.length - zs.avail_out; 413 int written = outbuf.length - zs.avail_out; 413 if( usiz < written ) written = usiz; 414 if( usiz < written ) written = usiz; 414 usiz -= written; 415 usiz -= written; 415 outf.write( outbuf[0..written] ); 416 outf.write( outbuf[0..written] ); 416 zs.next_out = outbuf; | 417 zs.next_out = outbuf.ptr; 417 zs.avail_out = outbuf.length; 418 zs.avail_out = outbuf.length; 418 419 419 // dlg 420 // dlg 420 if( BgaAnswer.Abort==ph(init_usiz-usiz,usiz) ) return fa 421 if( BgaAnswer.Abort==ph(init_usiz-usiz,usiz) ) return fa 421 } 422 } 422 423 423 // 終了 424 // 終了 ................................................................................................................................................................................ 430 431 431 private bool BzDec( uint usiz, Filep outf, ProgressHandler ph ) 432 private bool BzDec( uint usiz, Filep outf, ProgressHandler ph ) 432 { 433 { 433 uint init_usiz = usiz; 434 uint init_usiz = usiz; 434 435 435 // libbz2で展開 436 // libbz2で展開 436 int err; 437 int err; 437 BZFILE* b = BZ2_bzReadOpen( &err, fp.get_fp(), 0, 0, NULL, 0 ); | 438 BZFILE* b = BZ2_bzReadOpen( &err, fp.get_fp(), 0, 0, null, 0 ); 438 if( err!=BZ_OK || b is null ) 439 if( err!=BZ_OK || b is null ) 439 return true; 440 return true; 440 441 441 try 442 try 442 { 443 { 443 char[] buf; buf.length = BUFSIZ; 444 char[] buf; buf.length = BUFSIZ; 444 int len; 445 int len; 445 while( 0<(len=BZ2_bzRead( &err, b, buf, BUFSIZ<usiz?BUFS | 446 while( 0<(len=BZ2_bzRead( &err, b, buf.ptr, BUFSIZ<usiz? 446 { 447 { 447 outf.write( buf[0..len] ); 448 outf.write( buf[0..len] ); 448 usiz -= len; 449 usiz -= len; 449 if( err != BZ_OK ) 450 if( err != BZ_OK ) 450 break; 451 break; 451 452 452 // dlg 453 // dlg