예제 #1
0
blargg_err_t Zip_Extractor::open_v()
{
	if ( arc().size() < end_entry_size )
		return blargg_err_file_type;

	// Read final end_read_size bytes of file
	BOOST::uint64_t file_pos = max( (BOOST::uint64_t) 0, arc().size() - end_read_size );
	file_pos -= file_pos % disk_block_size;
	RETURN_ERR( catalog.resize( arc().size() - file_pos ) );
	RETURN_ERR( arc().seek( file_pos ) );
	RETURN_ERR( arc().read( catalog.begin(), catalog.size() ) );

	// Find end-of-catalog entry
	BOOST::uint64_t end_pos = catalog.size() - end_entry_size;
	while ( end_pos >= 0 && memcmp( &catalog [end_pos], "PK\5\6", 4 ) )
		end_pos--;
	if ( end_pos < 0 )
		return blargg_err_file_type;
	end_entry_t const& end_entry = (end_entry_t&) catalog [end_pos];
	end_pos += file_pos;

	// some idiotic zip compressors add data to end of zip without setting comment len
//  check( arc().size() == end_pos + end_entry_size + get_le16( end_entry.comment_len ) );

	// Find file offset of beginning of catalog
	catalog_begin = get_le32( end_entry.dir_offset );
	int catalog_size = end_pos - catalog_begin;
	if ( catalog_size < 0 )
		return blargg_err_file_corrupt;
	catalog_size += end_entry_size;

	// See if catalog is entirely contained in bytes already read
	BOOST::uint64_t begin_offset = catalog_begin - file_pos;
	if ( begin_offset >= 0 )
		memmove( catalog.begin(), &catalog [begin_offset], catalog_size );

	RETURN_ERR( catalog.resize( catalog_size ) );
	if ( begin_offset < 0 )
	{
		// Catalog begins before bytes read, so it needs to be read
		RETURN_ERR( arc().seek( catalog_begin ) );
		RETURN_ERR( arc().read( catalog.begin(), catalog.size() ) );
	}

	// First entry in catalog should be a file or end of archive
	if ( memcmp( catalog.begin(), "PK\1\2", 4 ) && memcmp( catalog.begin(), "PK\5\6", 4 ) )
		return blargg_err_file_type;
	
	reorder_entry_header( 0 );
	return rewind_v();
}
예제 #2
0
blargg_err_t Zip_Extractor::update_info( bool advance_first )
{
	while ( 1 )
	{
		entry_t& e = (entry_t&) catalog [(size_t)catalog_pos];

		if ( memcmp( e.type, "\0K\1\2P", 5 ) && memcmp( e.type, "PK\1\2", 4 ) )
		{
			check( !memcmp( e.type, "\0K\5\6P", 5 ) );
			break;
		}

		unsigned len = get_le16( e.filename_len );
        BOOST::int64_t next_offset = catalog_pos + entry_size + len + get_le16( e.extra_len ) +	get_le16( e.comment_len );

		if (isZIP64)
		{
			if ((unsigned)next_offset > catalog.size() - end64_entry_size)
				return blargg_err_file_corrupt;
		}
		else
		{
			if ((unsigned)next_offset > catalog.size() - end_entry_size)
				return blargg_err_file_corrupt;
		}
		
		if ( catalog [(size_t)next_offset] == 'P' )
			reorder_entry_header( (long)next_offset );

		if ( !advance_first )
		{
			e.filename [len] = 0; // terminate name
			
			if ( is_normal_file( e, len ) )
			{
				set_name( e.filename );
				set_info( get_le32( e.size ), get_le32( e.date ), get_le32( e.crc ) );
				break;
			}
		}

		catalog_pos = next_offset;
		advance_first = false;
	}
	
	return blargg_ok;
}
예제 #3
0
blargg_err_t Zip_Extractor::update_info( bool advance_first )
{
	while ( 1 )
	{
		entry_t& e = (entry_t&) catalog [catalog_pos];

		if ( memcmp( e.type, "\0K\1\2P", 5 ) && memcmp( e.type, "PK\1\2", 4 ) )
		{
			check( !memcmp( e.type, "\0K\5\6P", 5 ) );
			break;
		}

		unsigned len = get_le16( e.filename_len );
		int next_offset = catalog_pos + entry_size + len + get_le16( e.extra_len ) +
				get_le16( e.comment_len );
		if ( (unsigned) next_offset > catalog.size() - end_entry_size )
			return blargg_err_file_corrupt;
		
		if ( catalog [next_offset] == 'P' )
			reorder_entry_header( next_offset );

		if ( !advance_first )
		{
			char unterminate = e.filename[len];
			e.filename [len] = 0; // terminate name
			std::string fname = e.filename;
			
			if ( is_normal_file( e, len ) )
			{
				e.filename[len] = unterminate;
				name.resize(fname.size()+1);
				if(len != 0)
				{
					memcpy(name.begin(),fname.c_str(),len);
					name[name.size()-1] = 0;
				}
				set_name( name.begin() );
				set_info( get_le32( e.size ), get_le32( e.date ), get_le32( e.crc ) );

				unsigned extra_len = get_le32(e.extra_len);

				//walk over extra fields
				unsigned i = len;
				while(i < extra_len + len)
				{
					unsigned id = get_le16(e.filename + i);
					i += 2;
					unsigned exlen = get_le16(e.filename + i);
					i += 2;
					int exfield = i;
					i += exlen;
					if(id == 0x7075) //INFO-ZIP unicode path extra field (contains version, checksum, and utf-8 filename)
					{
						unsigned version = (unsigned char)*(e.filename + exfield);
						if(version == 1)
						{
							exfield += 1; //skip version
							exfield += 4; //skip crc
							//the remainder is a utf-8 filename
							int fnamelen = exlen-5;
							char* tempbuf = (char*)malloc(fnamelen + 1);
							memcpy(tempbuf,e.filename + exfield, fnamelen);
							tempbuf[fnamelen] = 0;
							wchar_t* wfname_buf = blargg_to_wide(tempbuf);
							std::wstring wfname = wfname_buf;
							free(tempbuf);
							free(wfname_buf);
							
							size_t wfname_len = wfname.size();

							this->wname.resize(wfname_len+1);
							if(wfname_len != 0)
							{
								memcpy(this->wname.begin(),wfname.c_str(),wfname_len*sizeof(wchar_t));
								wname[wname.size()-1] = 0;
							}
							set_name( name.begin(), wname.begin() );
							
						}
					}
				}
				break;
			}
		}

		catalog_pos = next_offset;
		advance_first = false;
	}
	
	return blargg_ok;
}