5128eecc9f 2011-02-23 kinaba: 5128eecc9f 2011-02-23 kinaba: #include "stdafx.h" 5128eecc9f 2011-02-23 kinaba: #include "LzhTool.h" 5128eecc9f 2011-02-23 kinaba: #include "LzhDecoder2.h" 5128eecc9f 2011-02-23 kinaba: #include "kiutil.h" 5128eecc9f 2011-02-23 kinaba: #include "kilib/kilib.h" 5128eecc9f 2011-02-23 kinaba: 5128eecc9f 2011-02-23 kinaba: bool CLzhTool::crcinit; 5128eecc9f 2011-02-23 kinaba: unsigned short CLzhTool::crctable[256]; 5128eecc9f 2011-02-23 kinaba: 5128eecc9f 2011-02-23 kinaba: bool CLzhTool::Extract( const char* aname, const char* dll, kiPath& dll_rel_path ) 5128eecc9f 2011-02-23 kinaba: { 5128eecc9f 2011-02-23 kinaba: // 先頭の方を読み込み 5128eecc9f 2011-02-23 kinaba: FILE* fp = fopen( aname,"rb" ); 5128eecc9f 2011-02-23 kinaba: if( !fp ) 5128eecc9f 2011-02-23 kinaba: return false; 5128eecc9f 2011-02-23 kinaba: unsigned char* buff = new unsigned char[65536]; 5128eecc9f 2011-02-23 kinaba: DWORD siz = fread( buff, 1, 65536, fp ); 5128eecc9f 2011-02-23 kinaba: fclose( fp ); 5128eecc9f 2011-02-23 kinaba: // ヘッダを探す 5128eecc9f 2011-02-23 kinaba: int ps = FindHeader( aname,buff,siz ); 5128eecc9f 2011-02-23 kinaba: // 書庫を開く 5128eecc9f 2011-02-23 kinaba: if( ps==-1 || !(lzh = fopen( aname,"rb" )) ) 5128eecc9f 2011-02-23 kinaba: { 5128eecc9f 2011-02-23 kinaba: delete [] buff; 5128eecc9f 2011-02-23 kinaba: return false; 5128eecc9f 2011-02-23 kinaba: } 5128eecc9f 2011-02-23 kinaba: 5128eecc9f 2011-02-23 kinaba: fseek( lzh,ps,SEEK_SET ); 5128eecc9f 2011-02-23 kinaba: 5128eecc9f 2011-02-23 kinaba: // 格納ファイル毎に処理 5128eecc9f 2011-02-23 kinaba: while( ReadHeader( buff ) ) 5128eecc9f 2011-02-23 kinaba: { 5128eecc9f 2011-02-23 kinaba: long base = ftell( lzh ); 5128eecc9f 2011-02-23 kinaba: char* name; 5128eecc9f 2011-02-23 kinaba: 5128eecc9f 2011-02-23 kinaba: if( h_FileName[0]!='!' && h_FileName[0]!='$' && h_FileName[0]!='%' ) 5128eecc9f 2011-02-23 kinaba: if( out=fopen( name=kiutil::pathMake(h_FileName),"wb" ) ) 5128eecc9f 2011-02-23 kinaba: { 5128eecc9f 2011-02-23 kinaba: if( 0==strcmpi( kiPath::name(name), dll ) ) // DLLの位置を記憶 5128eecc9f 2011-02-23 kinaba: dll_rel_path = name; 5128eecc9f 2011-02-23 kinaba: 5128eecc9f 2011-02-23 kinaba: // デコード 5128eecc9f 2011-02-23 kinaba: CLzhDecoder2 dec; 5128eecc9f 2011-02-23 kinaba: lzh_method mhd = UNKNOWN; 5128eecc9f 2011-02-23 kinaba: if( 0==strcmp(h_Method,"-lh0-") )mhd=LH0; 5128eecc9f 2011-02-23 kinaba: else if( 0==strcmp(h_Method,"-lh5-") )mhd=LH5; 5128eecc9f 2011-02-23 kinaba: else if( 0==strcmp(h_Method,"-lh6-") )mhd=LH6; 5128eecc9f 2011-02-23 kinaba: else if( 0==strcmp(h_Method,"-lh7-") )mhd=LH7; 5128eecc9f 2011-02-23 kinaba: dec.Decode( mhd, lzh, h_CompSize, out, h_OrigSize ); 5128eecc9f 2011-02-23 kinaba: 5128eecc9f 2011-02-23 kinaba: // 属性など設定 5128eecc9f 2011-02-23 kinaba: fclose( out ); 5128eecc9f 2011-02-23 kinaba: 5128eecc9f 2011-02-23 kinaba: SetFileAttributes( name,h_Attrib ); 5128eecc9f 2011-02-23 kinaba: if( h_Level<2 ) 5128eecc9f 2011-02-23 kinaba: kiutil::timeSet( name, (WORD)(h_Update>>16),(WORD)h_Update ); 5128eecc9f 2011-02-23 kinaba: else 5128eecc9f 2011-02-23 kinaba: kiutil::timeSet( name, h_Update ); 5128eecc9f 2011-02-23 kinaba: } 5128eecc9f 2011-02-23 kinaba: 5128eecc9f 2011-02-23 kinaba: fseek( lzh, base+h_CompSize, SEEK_SET ); 5128eecc9f 2011-02-23 kinaba: } 5128eecc9f 2011-02-23 kinaba: 5128eecc9f 2011-02-23 kinaba: delete [] buff; 5128eecc9f 2011-02-23 kinaba: fclose( lzh ); 5128eecc9f 2011-02-23 kinaba: return true; 5128eecc9f 2011-02-23 kinaba: } 5128eecc9f 2011-02-23 kinaba: 5128eecc9f 2011-02-23 kinaba: int CLzhTool::FindHeader( const char* fname, const BYTE* hdr, DWORD siz ) 5128eecc9f 2011-02-23 kinaba: { 5128eecc9f 2011-02-23 kinaba: bool bopen = false; 5128eecc9f 2011-02-23 kinaba: BYTE* temp; 5128eecc9f 2011-02-23 kinaba: int ans=-1; 5128eecc9f 2011-02-23 kinaba: 5128eecc9f 2011-02-23 kinaba: for( DWORD i=0; i<siz-20; i++ ) 5128eecc9f 2011-02-23 kinaba: { 5128eecc9f 2011-02-23 kinaba: if( hdr[i+2]=='-' && hdr[i+3]=='l' && 5128eecc9f 2011-02-23 kinaba: (hdr[i+4]=='h' || hdr[i+4]=='z') ) 5128eecc9f 2011-02-23 kinaba: { 5128eecc9f 2011-02-23 kinaba: if( !bopen ) 5128eecc9f 2011-02-23 kinaba: if( !(lzh=fopen( fname,"rb" )) ) 5128eecc9f 2011-02-23 kinaba: return -1; 5128eecc9f 2011-02-23 kinaba: else 5128eecc9f 2011-02-23 kinaba: bopen=true, temp = new BYTE[65536]; 5128eecc9f 2011-02-23 kinaba: 5128eecc9f 2011-02-23 kinaba: fseek( lzh,i,SEEK_SET ); 5128eecc9f 2011-02-23 kinaba: if( ReadHeader(temp) ) 5128eecc9f 2011-02-23 kinaba: {ans=(signed)i;break;} 5128eecc9f 2011-02-23 kinaba: } 5128eecc9f 2011-02-23 kinaba: } 5128eecc9f 2011-02-23 kinaba: 5128eecc9f 2011-02-23 kinaba: if( bopen ) 5128eecc9f 2011-02-23 kinaba: {delete [] temp;fclose( lzh );} 5128eecc9f 2011-02-23 kinaba: return ans; 5128eecc9f 2011-02-23 kinaba: } 5128eecc9f 2011-02-23 kinaba: 5128eecc9f 2011-02-23 kinaba: bool CLzhTool::ReadHeader( unsigned char* buf ) 5128eecc9f 2011-02-23 kinaba: { 5128eecc9f 2011-02-23 kinaba: // 初期化 5128eecc9f 2011-02-23 kinaba: *h_FileName=0; 5128eecc9f 2011-02-23 kinaba: sum=0,crc=0; 5128eecc9f 2011-02-23 kinaba: 5128eecc9f 2011-02-23 kinaba: // だいたい共通な部分 5128eecc9f 2011-02-23 kinaba: // 5128eecc9f 2011-02-23 kinaba: // 0- 1: [0]=header_size [1]=check_sum (h0) 5128eecc9f 2011-02-23 kinaba: // [0]=bas_hdr_siz [1]=check_sum (h1) 5128eecc9f 2011-02-23 kinaba: // [WORD] = all_header_size (h2) 5128eecc9f 2011-02-23 kinaba: // 5128eecc9f 2011-02-23 kinaba: // 2- 6: method 5128eecc9f 2011-02-23 kinaba: // 5128eecc9f 2011-02-23 kinaba: // 7-10: [DWORD]=compressed_size (h0/h2) 5128eecc9f 2011-02-23 kinaba: // [DWORD]=offset_to_next_hdr (h1) 5128eecc9f 2011-02-23 kinaba: // 5128eecc9f 2011-02-23 kinaba: // 11-14: [DWORD]=original_size 5128eecc9f 2011-02-23 kinaba: // 5128eecc9f 2011-02-23 kinaba: // 15-18: [ftime]=update_date_time 5128eecc9f 2011-02-23 kinaba: // 5128eecc9f 2011-02-23 kinaba: // 19: attribute (h0) 5128eecc9f 2011-02-23 kinaba: // 0x20 (h1/h2) 5128eecc9f 2011-02-23 kinaba: // 5128eecc9f 2011-02-23 kinaba: // 20: header_level 5128eecc9f 2011-02-23 kinaba: // 5128eecc9f 2011-02-23 kinaba: if( 21!=fread_crc(buf,21) ) 5128eecc9f 2011-02-23 kinaba: return false; 5128eecc9f 2011-02-23 kinaba: sum-=(buf[0]+buf[1]); 5128eecc9f 2011-02-23 kinaba: 5128eecc9f 2011-02-23 kinaba: if( (h_Level=buf[20])>2 ) // LV3以上未対応 5128eecc9f 2011-02-23 kinaba: return false; 5128eecc9f 2011-02-23 kinaba: 5128eecc9f 2011-02-23 kinaba: BYTE bshdr = (h_Level==2)?26:buf[0]+2; 5128eecc9f 2011-02-23 kinaba: if( bshdr<21 || buf[0]==0 ) 5128eecc9f 2011-02-23 kinaba: return false; 5128eecc9f 2011-02-23 kinaba: BYTE hdrsum= buf[1]; 5128eecc9f 2011-02-23 kinaba: for( int i=0; i!=5; i++ ) 5128eecc9f 2011-02-23 kinaba: h_Method[i]=(char)buf[2+i];h_Method[5]=0; 5128eecc9f 2011-02-23 kinaba: h_CompSize = (buf[ 7])+(buf[ 8]<<8)+(buf[ 9]<<16)+(buf[10]<<24); 5128eecc9f 2011-02-23 kinaba: h_OrigSize = (buf[11])+(buf[12]<<8)+(buf[13]<<16)+(buf[14]<<24); 5128eecc9f 2011-02-23 kinaba: h_Update = (buf[15])+(buf[16]<<8)+(buf[17]<<16)+(buf[18]<<24); 5128eecc9f 2011-02-23 kinaba: h_Attrib = buf[19]; 5128eecc9f 2011-02-23 kinaba: if( h_Method[0]!='-' || h_Method[1]!='l' ) 5128eecc9f 2011-02-23 kinaba: return false; 5128eecc9f 2011-02-23 kinaba: 5128eecc9f 2011-02-23 kinaba: // レベル共通じゃない基本ヘッダ部分 5128eecc9f 2011-02-23 kinaba: // <h0> 5128eecc9f 2011-02-23 kinaba: // 21: file_name_length 5128eecc9f 2011-02-23 kinaba: // 22- n: file_name ( with path info ) 5128eecc9f 2011-02-23 kinaba: // WORD: crc16_of_file 5128eecc9f 2011-02-23 kinaba: // : and some extension part 5128eecc9f 2011-02-23 kinaba: // 5128eecc9f 2011-02-23 kinaba: // <h1> 5128eecc9f 2011-02-23 kinaba: // 21: file_name_length 5128eecc9f 2011-02-23 kinaba: // 22- n: file_name ( with no path info ) 5128eecc9f 2011-02-23 kinaba: // WORD: crc16_of_file 5128eecc9f 2011-02-23 kinaba: // BYTE: os_flag 5128eecc9f 2011-02-23 kinaba: // : and some extension part 5128eecc9f 2011-02-23 kinaba: // 5128eecc9f 2011-02-23 kinaba: // <h2> 5128eecc9f 2011-02-23 kinaba: // WORD: crc16_of_file 5128eecc9f 2011-02-23 kinaba: // BYTE: os_flag 5128eecc9f 2011-02-23 kinaba: // 5128eecc9f 2011-02-23 kinaba: // 5128eecc9f 2011-02-23 kinaba: if( (bshdr-21)!=fread_crc(buf+21,(bshdr-21)) ) 5128eecc9f 2011-02-23 kinaba: return false; 5128eecc9f 2011-02-23 kinaba: if( h_Level!=2 ) 5128eecc9f 2011-02-23 kinaba: { 5128eecc9f 2011-02-23 kinaba: if( sum!=hdrsum || 21+1+buf[21]+2>bshdr ) 5128eecc9f 2011-02-23 kinaba: return false; 5128eecc9f 2011-02-23 kinaba: memcpy( h_FileName,buf+22,buf[21] ); 5128eecc9f 2011-02-23 kinaba: h_FileName[buf[21]]=0; 5128eecc9f 2011-02-23 kinaba: } 5128eecc9f 2011-02-23 kinaba: 5128eecc9f 2011-02-23 kinaba: // 拡張ヘッダ( h1/h2 ) 5128eecc9f 2011-02-23 kinaba: // repeating of such blocks. 5128eecc9f 2011-02-23 kinaba: //------------------------------------------------------ 5128eecc9f 2011-02-23 kinaba: // WORD: size_of_this_block ( if 0 then end_of_header ) 5128eecc9f 2011-02-23 kinaba: // BYTE: type_flag 5128eecc9f 2011-02-23 kinaba: // : data ( (blocksize-3) bytes ) 5128eecc9f 2011-02-23 kinaba: //------------------------------------------------------ 5128eecc9f 2011-02-23 kinaba: 5128eecc9f 2011-02-23 kinaba: char PathName[MAX_PATH*2]={0}; 5128eecc9f 2011-02-23 kinaba: if( h_Level!=0 ) 5128eecc9f 2011-02-23 kinaba: { 5128eecc9f 2011-02-23 kinaba: DWORD hdrcrc=0xffffffff; 5128eecc9f 2011-02-23 kinaba: WORD tmpcrc; 5128eecc9f 2011-02-23 kinaba: 5128eecc9f 2011-02-23 kinaba: // ここでループって拡張ヘッダ読み込み 5128eecc9f 2011-02-23 kinaba: WORD ehs; 5128eecc9f 2011-02-23 kinaba: ehs = ((buf[bshdr-2])|(buf[bshdr-1]<<8)); 5128eecc9f 2011-02-23 kinaba: 5128eecc9f 2011-02-23 kinaba: while( ehs>2 ) 5128eecc9f 2011-02-23 kinaba: { 5128eecc9f 2011-02-23 kinaba: tmpcrc=crc;//CRC自身を読み込んだときに直すため 5128eecc9f 2011-02-23 kinaba: if( ehs!=fread_crc(buf,ehs) ) 5128eecc9f 2011-02-23 kinaba: return false; 5128eecc9f 2011-02-23 kinaba: if( h_Level==1 ) 5128eecc9f 2011-02-23 kinaba: h_CompSize-=ehs; 5128eecc9f 2011-02-23 kinaba: 5128eecc9f 2011-02-23 kinaba: switch( *buf ) 5128eecc9f 2011-02-23 kinaba: { 5128eecc9f 2011-02-23 kinaba: case 0x00://共通 5128eecc9f 2011-02-23 kinaba: if( ehs>=5 && hdrcrc==0xffffffff ) 5128eecc9f 2011-02-23 kinaba: { 5128eecc9f 2011-02-23 kinaba: hdrcrc=((buf[1])|(buf[2]<<8)); 5128eecc9f 2011-02-23 kinaba: 5128eecc9f 2011-02-23 kinaba: crc=tmpcrc; 5128eecc9f 2011-02-23 kinaba: buf[1]=buf[2]=0; 5128eecc9f 2011-02-23 kinaba: UpdateCRC(buf,ehs); 5128eecc9f 2011-02-23 kinaba: } 5128eecc9f 2011-02-23 kinaba: break; 5128eecc9f 2011-02-23 kinaba: case 0x01://ファイル名 5128eecc9f 2011-02-23 kinaba: memcpy(h_FileName,buf+1,ehs-3>MAX_PATH?MAX_PATH:ehs-3); 5128eecc9f 2011-02-23 kinaba: h_FileName[ehs-3>MAX_PATH?MAX_PATH:ehs-3]=0; 5128eecc9f 2011-02-23 kinaba: break; 5128eecc9f 2011-02-23 kinaba: case 0x02://パス名 5128eecc9f 2011-02-23 kinaba: memcpy(PathName,buf+1,ehs-3>MAX_PATH?MAX_PATH:ehs-3); 5128eecc9f 2011-02-23 kinaba: PathName[ehs-3>MAX_PATH?MAX_PATH:ehs-3]=0; 5128eecc9f 2011-02-23 kinaba: break; 5128eecc9f 2011-02-23 kinaba: case 0xff://新属性 5128eecc9f 2011-02-23 kinaba: break; 5128eecc9f 2011-02-23 kinaba: case 0x40://属性(DOS依存) 5128eecc9f 2011-02-23 kinaba: if( ehs>=5 ) 5128eecc9f 2011-02-23 kinaba: h_Attrib=((buf[1])|(buf[2]<<8)); 5128eecc9f 2011-02-23 kinaba: break; 5128eecc9f 2011-02-23 kinaba: case 0x41://タイムスタンプ(UNLHA32.DLL) 5128eecc9f 2011-02-23 kinaba: //は、なんだかうまくいかないので無視する。 5128eecc9f 2011-02-23 kinaba: break; 5128eecc9f 2011-02-23 kinaba: } 5128eecc9f 2011-02-23 kinaba: 5128eecc9f 2011-02-23 kinaba: ehs = ((buf[ehs-2])|(buf[ehs-1]<<8)); 5128eecc9f 2011-02-23 kinaba: } 5128eecc9f 2011-02-23 kinaba: 5128eecc9f 2011-02-23 kinaba: if( hdrcrc!=0xffffffff && crc!=hdrcrc ) 5128eecc9f 2011-02-23 kinaba: return false; 5128eecc9f 2011-02-23 kinaba: } 5128eecc9f 2011-02-23 kinaba: 5128eecc9f 2011-02-23 kinaba: // ff -> \\ 変換 5128eecc9f 2011-02-23 kinaba: char* x; 5128eecc9f 2011-02-23 kinaba: for( x=h_FileName; *x!=0; x=CharNext(x) ) 5128eecc9f 2011-02-23 kinaba: if( (BYTE)*x==0xff ) 5128eecc9f 2011-02-23 kinaba: *x='\\'; 5128eecc9f 2011-02-23 kinaba: for( x=PathName; *x!=0; x=CharNext(x) ) 5128eecc9f 2011-02-23 kinaba: if( (BYTE)*x==0xff ) 5128eecc9f 2011-02-23 kinaba: *x='\\'; 5128eecc9f 2011-02-23 kinaba: strcat( PathName,h_FileName ); 5128eecc9f 2011-02-23 kinaba: strcpy( h_FileName,PathName ); 5128eecc9f 2011-02-23 kinaba: return true; 5128eecc9f 2011-02-23 kinaba: 5128eecc9f 2011-02-23 kinaba: // lha header MEMO 5128eecc9f 2011-02-23 kinaba: // (h0/h1) 5128eecc9f 2011-02-23 kinaba: // 1 byte 目は、「1byte目自身を除いた基本ヘッダのサイズ」 5128eecc9f 2011-02-23 kinaba: // チェックサムは、「1,2byte目自身を除いた基本ヘッダの合計」 5128eecc9f 2011-02-23 kinaba: // (h1) 5128eecc9f 2011-02-23 kinaba: // offset_to_next_hdr は、基本ヘッダ末端から次のヘッダへの距離 5128eecc9f 2011-02-23 kinaba: // (h1/h2) 5128eecc9f 2011-02-23 kinaba: // crcは自分自身は0000として他全部から算出 5128eecc9f 2011-02-23 kinaba: }