Artifact Content

Not logged in

Artifact de96d041f43cbd6fed6047e0da21dd4c86bbaf7b


     1  
     2  #include "stdafx.h"
     3  #include "ArcCpt.h"
     4  #include "NoahApp.h"
     5  
     6  //--- CArchiver --------------------------------------------------
     7  
     8  bool CArcCpt::v_check( const kiPath& aname )
     9  {
    10  	bool ans = ( cpt.open( aname ) && read_main_hdr() && check_index_crc() );
    11  	cpt.close();
    12  	return ans;
    13  }
    14  
    15  bool CArcCpt::v_list( const arcname& aname, aflArray& files )
    16  {
    17  	::SetCurrentDirectory( aname.basedir );
    18  
    19  	bool ans = ( cpt.open( aname.lname ) && read_main_hdr() && operation_for_each( true, &files ) );
    20  	cpt.close();
    21  	return ans;
    22  }
    23  
    24  int CArcCpt::v_melt( const arcname& aname, const kiPath& ddir, const aflArray* files )
    25  {
    26  	::SetCurrentDirectory( aname.basedir );
    27  	if( !cpt.open( aname.lname ) )
    28  		return 0xffff;
    29  
    30  	::SetCurrentDirectory( ddir );
    31  	bool ans = ( read_main_hdr() && operation_for_each( false, const_cast<aflArray*>(files) ) );
    32  	cpt.close();
    33  	return ans ? 0 : 0x8020;
    34  }
    35  
    36  int CArcCpt::v_contents( const kiPath& aname, kiPath& dname )
    37  {
    38  	int ans=aUnknown;
    39  	if( cpt.open( aname ) && read_main_hdr() )
    40  	{
    41  		if( cpt.read( tmp, 7 ) )
    42  		{
    43  			WORD EntryNum = (tmp[4]<<8)  + tmp[5];
    44  			if( EntryNum == 1 )
    45  				ans = aSingleFile;
    46  			else
    47  			{
    48  				cpt.read( tmp, tmp[6] );
    49  				tmp[0] = cpt.getc();
    50  				if( tmp[0] & 0x80 ) // Folder
    51  				{
    52  					unsigned long size = (tmp[0]&0x3f) + 2;
    53  					if( size == cpt.read( tmp+1, size ) )
    54  						if( EntryNum == 1 + (tmp[size-1]<<8) + tmp[size] )
    55  						{
    56  							dname = "";
    57  							tmp[ 1+tmp[0] ] = '\0';
    58  							for( char* pp=(char*)tmp+1; *pp; pp=kiStr::next(pp) )
    59  							{
    60  								if( kiStr::isLeadByte(*pp) )
    61  									dname += *pp, dname += *(pp+1);
    62  								else if( *pp<' ' || *pp>'~' )
    63  									dname += '_';
    64  								else switch( *pp )
    65  								{
    66  									case '\\': case '/': case ':': case '*': 
    67  									case '?': case '\"': case '<': case '>': case '|':
    68  										dname += '_';
    69  									default:
    70  										dname += *pp;
    71  								}
    72  							}
    73  
    74  							ans = aSingleDir;
    75  						}
    76  				}
    77  			}
    78  		}
    79  	}
    80  	cpt.close();
    81  	return ans;
    82  }
    83  
    84  //--- CRC ----------------------------------------------------------
    85  
    86  static unsigned long crctbl[256] = { 1 };
    87  
    88  static void init_crc_table()
    89  {
    90  	if( crctbl[0]==1 ) // uninitialized
    91  		for( unsigned long c,n=0; n!=256; n++ )
    92  		{
    93  			c = n;
    94  			for( unsigned long k=8; k; k-- )
    95  				c = (c&1) ? ((0xedb88320L)^(c>>1)) : (c>>1);
    96  			crctbl[n] = c;
    97  		}
    98  }
    99  
   100  static unsigned long crc( unsigned long c, unsigned char* cp,int cnt )
   101  {
   102  	while( cnt-- )
   103  		c = (c>>8)^crctbl[(c&0xff)^*cp++];
   104  	return c;
   105  }
   106  
   107  //--- cpt ----------------------------------------------------------
   108  
   109  bool CArcCpt::read_main_hdr()
   110  {
   111  	//-- 先頭のバイトは MagicNumber : 0x01 なはず。
   112  	m_nMacBinOffset = 0;
   113  	if( 8 != cpt.read( tmp, 8 ) )
   114  		return false;
   115  	if( tmp[0] != 1 )
   116  	{
   117  		if(  0  != tmp[0]
   118  		 || 120 != cpt.read( tmp, 120 )
   119  		 ||  8  != cpt.read( tmp,  8  )
   120  		 || tmp[0] != 1 ) // MacBinスキップ
   121  			return false;
   122  		m_nMacBinOffset = 128;
   123  	}
   124  
   125  	//-- indexまで跳ぶ
   126  	cpt.seek( (tmp[4]<<24) + (tmp[5]<<16) + (tmp[6]<<8) + (tmp[7]) - 8 );
   127  	return true;
   128  }
   129  
   130  bool CArcCpt::check_index_crc()
   131  {
   132  	bool folder;
   133  	unsigned int size;
   134  
   135  	//-- CRC(DWORD), EntryNum(WORD), CommentLen(BYTE)
   136  	if( !cpt.read( tmp, 7 ) )
   137  		return false;
   138  
   139  	init_crc_table();
   140  
   141  	DWORD     CRC = (tmp[0]<<24) + (tmp[1]<<16) + (tmp[2]<<8) + tmp[3];
   142  	WORD EntryNum = (tmp[4]<<8)  + tmp[5];
   143  	if( tmp[6] != cpt.read( tmp+7, tmp[6] ) )
   144  		return false;
   145  	DWORD chk_crc = crc( 0xffffffff, tmp+4, 3+tmp[6] );
   146  
   147  	//-- 全ヘッダを走査してCRC計算
   148  	for( WORD i=0; i!=EntryNum; i++ )
   149  	{
   150  		tmp[0] = cpt.getc();
   151  
   152  		if( tmp[0] & 0x80 )	folder = true,  size = (tmp[0]&0x3f) + 2;
   153  		else				folder = false, size = (tmp[0]) + 45;
   154  		if( size != cpt.read( tmp+1, size ) ) return false;
   155  
   156  		chk_crc = crc( chk_crc, tmp, 1+size );
   157      }
   158  
   159  	return CRC == chk_crc;
   160  }
   161  
   162  bool CArcCpt::operation_for_each( bool o_list, aflArray* files )
   163  {
   164  	//-- Entry数を得る
   165  	if( !cpt.read( tmp, 7 ) )
   166  		return false;
   167  	WORD EntryNum = (tmp[4]<<8)  + tmp[5];
   168  	cpt.read( tmp, tmp[6] );
   169  
   170  	//-- ダイアログ準備
   171  	pdlg = files ? NULL : new CArcProgressDlg( EntryNum );
   172  
   173  	//-- 操作
   174  	kiPath path;
   175  	m_nIndexPos = cpt.tell();
   176  	bool ans = recurse( o_list, files, path, 0, EntryNum );
   177  	delete pdlg;
   178  	return ans;
   179  }
   180  
   181  bool CArcCpt::recurse( bool o_list, aflArray* files, kiPath& path, int base, int num )
   182  {
   183  	bool folder;
   184  	unsigned int size;
   185  	kiPath pthtmp;
   186  
   187  	for( int i=0; i<num; i++ )
   188  	{
   189  		cpt.seekTo( m_nIndexPos );
   190  
   191  	//-- tmpへindex読み込み
   192  
   193  		tmp[0] = cpt.getc();
   194  		if( tmp[0] & 0x80 )	folder = true,  size = (tmp[0]&0x3f) + 2;
   195  		else				folder = false, size = (tmp[0]) + 45;
   196  		if( size != cpt.read( tmp+1, size ) ) return false;
   197  		m_nIndexPos = cpt.tell(); // 次のIndexの位置を記憶
   198  
   199  	//-- ヘッダ解析
   200  
   201  		//   0: filename_len (BYTE)
   202  		// 1-n: filename     (with no '\0')
   203  		char filename[MAX_PATH];
   204  		ki_memcpy( filename, tmp+1, tmp[0] );
   205  		filename[ *tmp ] = '\0';
   206  		for( char* pp=filename; *pp; pp=kiStr::next(pp) )
   207  		{
   208  			if( kiStr::isLeadByte(*pp) )
   209  				continue;
   210  			if( *pp<' ' || *pp>'~' )
   211  				*pp = '_';
   212  			else switch( *pp )
   213  			{
   214  				case '\\': case '/': case ':': case '*': 
   215  				case '?': case '\"': case '<': case '>': case '|':
   216  					*pp = '_';
   217  			}
   218  		}
   219  		// filenameが2個以上の.のみからなっていたら_に書き換え
   220  		{
   221  			int dots = 0;
   222  			char* pp;
   223  			for( pp=filename; *pp; pp=kiStr::next(pp) )
   224  				if( *pp == '.' ) { ++dots; }
   225  				else { dots=-1; break; }
   226  			if( dots >= 2 )
   227  				for( pp=filename; *pp; ++pp )
   228  					*pp = '_';
   229  		}
   230  
   231  	//-- ダイアログ処理
   232  
   233  		pthtmp = path, pthtmp += filename;
   234  
   235  		if( pdlg )
   236  		{
   237  			pdlg->change( pthtmp, base+i+1 );
   238  			if( !pdlg->msgloop() )
   239  				return false;
   240  		}
   241  
   242  	//-- フォルダ処理
   243  
   244  		if( folder )
   245  		{
   246  			unsigned long fldlen = (tmp[size-1]<<8) + tmp[size];
   247  			pthtmp += '\\';
   248  
   249  			if( o_list )
   250  			{
   251  				files->forcelen( base+i+1 );
   252  				ki_strcpy( (*files)[base+i].inf.szFileName, pthtmp );
   253  				(*files)[base+i].isfile = false;
   254  			}
   255  
   256  			if( !recurse( o_list, files, pthtmp, base+i+1, fldlen ) )
   257  				return false;
   258  			i += fldlen;
   259  		}
   260  
   261  	//-- ファイル処理
   262  
   263  		else
   264  		{
   265  			const unsigned char* hdr = tmp + (size+1) - 80;
   266  
   267  			unsigned long rsrcSkip; bool lzhFlag;
   268  			if( (hdr[68]<<24) + (hdr[69]<<16) + (hdr[70]<<8) + hdr[71] != 0 )
   269  			{
   270  				// もし dataForkが存在するならば
   271  				dataULen = (hdr[68]<<24) + (hdr[69]<<16) + (hdr[70]<<8) + hdr[71];
   272  				dataCLen = (hdr[76]<<24) + (hdr[77]<<16) + (hdr[78]<<8) + hdr[79];
   273  				rsrcSkip = (hdr[72]<<24) + (hdr[73]<<16) + (hdr[74]<<8) + hdr[75];
   274  				lzhFlag  = (hdr[63]&4) !=0;
   275  			}
   276  			else
   277  			{
   278  				// dataForkが存在しないならば
   279  				dataULen = (hdr[64]<<24) + (hdr[65]<<16) + (hdr[66]<<8) + hdr[67];
   280  				dataCLen = (hdr[72]<<24) + (hdr[73]<<16) + (hdr[74]<<8) + hdr[75];
   281  				rsrcSkip = 0;
   282  				lzhFlag  = (hdr[63]&2) !=0;
   283  			}
   284  
   285  			if( o_list ) // リストへ加える
   286  			{
   287  				files->forcelen( base+i+1 );
   288  				ki_strcpy( (*files)[base+i].inf.szFileName, pthtmp );
   289  				ki_strcpy( (*files)[base+i].inf.szMode, lzhFlag ? "rle+lzh" : "rle" );
   290  				(*files)[base+i].inf.dwCompressedSize = dataCLen;
   291  				(*files)[base+i].inf.dwOriginalSize = dataULen;
   292  				(*files)[base+i].isfile = true;
   293  			}
   294  			else if( !files || (*files)[base+i].selected )
   295  			{
   296  				if( !(hdr[63] & 1) )
   297  				{
   298  					pthtmp.mkdir();
   299  					cpt.seekTo( (hdr[36]<<24) + (hdr[37]<<16) + (hdr[38]<<8) + hdr[39] +
   300  								rsrcSkip + m_nMacBinOffset ); // filepos + rsrcCLen + (0 | 128)
   301  					if( out.open( pthtmp, false ) )
   302  					{
   303  						cptmelt( lzhFlag );
   304  						out.close();
   305  					}
   306  				}
   307  			}
   308  		}
   309      }
   310  
   311  	return true;
   312  }
   313  
   314  //-- 解凍処理 ------------------------------------------------
   315  
   316  #define	ESC1		0x81
   317  #define	ESC2		0x82
   318  #define NONESEEN	0
   319  #define ESC1SEEN	1
   320  #define ESC2SEEN	2
   321  
   322  void CArcCpt::cptmelt( bool isRL )
   323  {
   324  	cpt_outstat = NONESEEN;
   325  	cpt_LZptr = 0;
   326  	cpt_blocksize = 0x1fff0;
   327  
   328  	if( isRL )
   329  		cpt_rle_lzh();
   330  	else
   331  		while( dataCLen-- )
   332  			cpt_outch( cpt.getc() );
   333  }
   334  
   335  void CArcCpt::cpt_outch(unsigned char ch)
   336  {
   337  	cpt_LZbuff[ cpt_LZptr++ & (CIRCSIZE-1) ] = ch;
   338  
   339  	switch( cpt_outstat )
   340  	{
   341  	case NONESEEN:
   342  		if( ch==ESC1 )
   343  			cpt_outstat = ESC1SEEN;
   344  		else
   345  			dataULen--,out.putc( cpt_savechar=ch );
   346  		break;
   347  
   348  	case ESC1SEEN:
   349  		if( ch==ESC2 )
   350  			cpt_outstat = ESC2SEEN;
   351  		else
   352  		{
   353  			dataULen--,out.putc( cpt_savechar=ESC1 );
   354  			if( ch!=ESC1 )
   355  			{
   356  				cpt_outstat = NONESEEN;
   357  				dataULen--,out.putc( cpt_savechar=ch );
   358  			}
   359  		}
   360  		break;
   361  
   362  	case ESC2SEEN:
   363  		cpt_outstat = NONESEEN;
   364  		if( ch!=0 )
   365  			while( --ch )
   366  				dataULen--,out.putc(cpt_savechar);
   367  		else
   368  		{
   369  			dataULen--,out.putc( ESC1 );
   370  			dataULen--,out.putc( cpt_savechar=ESC2 );
   371  		}
   372      }
   373  }
   374  
   375  void CArcCpt::cpt_rle_lzh()
   376  {
   377  	int block_count;
   378  	unsigned int bptr;
   379  	int Huffchar, LZlength, LZoffs;
   380  
   381  	cpt_LZbuff[CIRCSIZE - 3] = 0;
   382  	cpt_LZbuff[CIRCSIZE - 2] = 0;
   383  	cpt_LZbuff[CIRCSIZE - 1] = 0;
   384  	cpt_LZptr = 0;
   385  
   386  	while( dataULen!=0 )
   387  	{
   388  		cpt_readHuff(256,cpt_Hufftree);
   389  		cpt_readHuff( 64,cpt_LZlength);
   390  		cpt_readHuff(128,cpt_LZoffs  );
   391  		block_count = 0;
   392  		cpt_newbits = (cpt.getc()<<8);
   393  		cpt_newbits = cpt_newbits | cpt.getc();
   394  		cpt_newbits = cpt_newbits << 16;
   395  		cpt_bitsavail = 16;
   396  		while( block_count<cpt_blocksize && dataULen!=0 )
   397  		{
   398  			if( cpt_getbit() )
   399  			{
   400  				Huffchar = gethuffbyte(cpt_Hufftree);
   401  				cpt_outch((unsigned char)Huffchar);
   402  				block_count += 2;
   403  			}
   404  			else
   405  			{
   406  				LZlength = gethuffbyte(cpt_LZlength);
   407  				LZoffs = gethuffbyte(cpt_LZoffs);
   408  				LZoffs = (LZoffs << 6) | cpt_get6bits();
   409  				bptr = cpt_LZptr - LZoffs;
   410  				while( LZlength-->0 )
   411  					cpt_outch(cpt_LZbuff[bptr++&(CIRCSIZE-1)]);
   412  				block_count += 3;
   413  			}
   414  		}
   415  	}
   416  }
   417  
   418  int CArcCpt::gethuffbyte(node* l_nodelist)
   419  {
   420  	register node *np;
   421  	np = l_nodelist;
   422  	while(np->flag == 0)
   423  		np = cpt_getbit() ? np->one : np->zero;
   424  	return np->byte;
   425  }
   426  
   427  void CArcCpt::cpt_readHuff(int size,node* Hufftree)
   428  {
   429  	sf_entry tree_entry[256 + SLACK];
   430  	int tree_entries;
   431  	int tree_MaxLength;
   432  	int treeBytes, i, len;
   433  	sf_entry *ejm1;
   434  	int j;
   435  	sf_entry *entry;
   436      sf_entry tmp;
   437      int entries;
   438      unsigned a, b;
   439  	int codelen, lvlstart, next, parents;
   440  	int tree_count[32];
   441  
   442  	treeBytes = cpt.getc();
   443  	if( size<treeBytes*2 )
   444  		return;
   445  	for( i=0; i!=32; i++ )
   446  		tree_count[i] = 0;
   447  	i = 0;
   448  	tree_MaxLength = 0;
   449  	tree_entries = 0;
   450  	while( treeBytes-->0 )
   451  	{
   452  		int c=cpt.getc();
   453  		len = c >> 4;
   454  
   455  		if(len != 0)
   456  		{
   457  			if(len > tree_MaxLength)
   458  				tree_MaxLength = len;
   459  			tree_count[len]++;
   460  			tree_entry[tree_entries].Value = i;
   461  			tree_entry[tree_entries++].BitLength = len;
   462  		}
   463  		i++;
   464  		len = c & 0x0f;
   465  		if(len != 0)
   466  		{
   467  			if(len > tree_MaxLength)
   468  				tree_MaxLength = len;
   469  			tree_count[len]++;
   470  			tree_entry[tree_entries].Value = i;
   471  			tree_entry[tree_entries++].BitLength = len;
   472  		}
   473  		i++;
   474  	}
   475  
   476  	j = 0;
   477      for( i=0; i<=tree_MaxLength; i++ )
   478  		j = (j << 1) + tree_count[i];
   479  	j = (1 <<tree_MaxLength) - j;
   480  	for( i=0; i<j; i++ )
   481  	{
   482  		tree_entry[tree_entries].Value = size;
   483  		tree_entry[tree_entries++].BitLength = tree_MaxLength;
   484  	}
   485  
   486  	entry = &(tree_entry[0]);
   487  	entries = tree_entries;
   488      for( i=0; ++i<entries; )
   489  	{
   490  		tmp = entry[i];
   491  		b = tmp.BitLength;
   492  		j = i;
   493  		while((j > 0) && ((a = (ejm1 = &(entry[j - 1]))->BitLength) >= b))
   494  		{
   495  			if((a == b) && (ejm1->Value <= tmp.Value))
   496  				break;
   497  			*(ejm1 + 1) = *ejm1;
   498  			--j;
   499  		}
   500  		entry[j] = tmp;
   501  	}
   502  
   503      i = tree_entries - 1;
   504      lvlstart = next = size * 2 + SLACK - 1;
   505      for(codelen = tree_MaxLength; codelen >= 1; --codelen)
   506  	{
   507  		while((i >= 0) && (tree_entry[i].BitLength == codelen))
   508  		{
   509  			Hufftree[next].byte = tree_entry[i].Value;
   510  			Hufftree[next].flag = 1;
   511  			next--;
   512  			i--;
   513  		}
   514  		parents = next;
   515  		if(codelen > 1)
   516  		{
   517  			for(j = lvlstart; j > parents + 1; j-= 2)
   518  			{
   519  				Hufftree[next].one = &(Hufftree[j]);
   520  				Hufftree[next].zero = &(Hufftree[j - 1]);
   521  				Hufftree[next].flag = 0;
   522  				next--;
   523  			}
   524  		}
   525  		lvlstart = parents;
   526  	}
   527  	Hufftree[0].one = &(Hufftree[next + 2]);
   528  	Hufftree[0].zero = &(Hufftree[next + 1]);
   529  	Hufftree[0].flag = 0;
   530  }
   531  
   532  int CArcCpt::cpt_get6bits()
   533  {
   534  	int cn,b=(cpt_newbits >> 26) & 0x3f;
   535  	cpt_bitsavail -= 6;
   536  	cpt_newbits <<= 6;
   537  	if(cpt_bitsavail < 16)
   538  	{
   539  		cn = (cpt.getc() << 8);
   540  		cn |= cpt.getc();
   541  		cpt_newbits |= (cn << (16 - cpt_bitsavail));
   542  		cpt_bitsavail += 16;
   543  	}
   544  	return b;
   545  }
   546  
   547  int CArcCpt::cpt_getbit()
   548  {
   549  	int b = (cpt_newbits >> 31) & 1;
   550  	cpt_bitsavail--;
   551  	if( cpt_bitsavail<16 )
   552  	{
   553  		cpt_newbits |= (cpt.getc() << 8);
   554  		cpt_newbits |= cpt.getc();
   555  		cpt_bitsavail += 16;
   556  	}
   557  	cpt_newbits <<= 1;
   558  	return b;
   559  }