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