1 Star 3 Fork 2

只要998/Onscripter-Official

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
SarReader.cpp 12.65 KB
一键复制 编辑 原始数据 按行查看 历史
只要998 提交于 2020-04-20 20:31 . no commit message
/* -*- C++ -*-
*
* SarReader.cpp - Reader from a SAR archive
*
* Copyright (c) 2001-2014 Ogapee. All rights reserved.
*
* ogapee@aqua.dti2.ne.jp
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "SarReader.h"
#define WRITE_LENGTH 4096
#if defined(PSP)
extern int psp_power_resume_number;
#endif
SarReader::SarReader( const char *path, const unsigned char *key_table )
:DirectReader( path, key_table )
{
root_archive_info = last_archive_info = &archive_info;
num_of_sar_archives = 0;
}
SarReader::~SarReader()
{
close();
}
int SarReader::open( const char *name )
{
ArchiveInfo* info = new ArchiveInfo();
if ( (info->file_handle = fopen( name, "rb" ) ) == NULL ){
delete info;
return -1;
}
info->file_name = new char[strlen(name)+1];
memcpy(info->file_name, name, strlen(name)+1);
readArchive( info );
last_archive_info->next = info;
last_archive_info = last_archive_info->next;
num_of_sar_archives++;
return 0;
}
void SarReader::readArchive( ArchiveInfo *ai, int archive_type, unsigned int offset )
{
unsigned int i;
/* Read header */
for (i=0; i<offset; i++)
readChar( ai->file_handle ); // for commands "ns2" and "ns3"
if ( archive_type == ARCHIVE_TYPE_NS2 ) {
// new archive type since NScr2.91
// - header starts with base_offset (byte-swapped), followed by
// filename data - doesn't tell how many files!
// - filenames are surrounded by ""s
// - new NS2 filename def: "filename", length (4bytes, swapped)
// - no compression type? really, no compression.
// - not sure if NS2 uses key_table or not, using default funcs for now
ai->base_offset = swapLong( readLong( ai->file_handle ) );
ai->base_offset += offset;
// need to parse the whole header to see how many files there are
ai->num_of_files = 0;
long unsigned int cur_offset = offset + 4;
// there's an extra byte at the end of the header, not sure what for
while(1){
unsigned char ch = key_table[fgetc( ai->file_handle )];
if (ch != '"') break;
cur_offset++;
do cur_offset++;
while( (ch = key_table[fgetc( ai->file_handle )] ) != '"' );
cur_offset += 4;
readLong( ai->file_handle );
ai->num_of_files++;
}
ai->fi_list = new FileInfo[ ai->num_of_files ];
// now go back to the beginning and read the file info
cur_offset = ai->base_offset;
fseek( ai->file_handle, 4 + offset, SEEK_SET );
for ( i=0 ; i<ai->num_of_files ; i++ ){
unsigned int count = 0;
//skip the beginning double-quote
unsigned char ch = key_table[fgetc( ai->file_handle )];
while( (ch = key_table[fgetc( ai->file_handle )] ) != '"' ){
if ( 'a' <= ch && ch <= 'z' ) ch += 'A' - 'a';
ai->fi_list[i].name[count++] = ch;
}
ai->fi_list[i].name[count] = '\0';
ai->fi_list[i].compression_type = getRegisteredCompressionType( ai->fi_list[i].name );
ai->fi_list[i].offset = cur_offset;
ai->fi_list[i].length = swapLong( readLong( ai->file_handle ) );
ai->fi_list[i].original_length = ai->fi_list[i].length;
cur_offset += ai->fi_list[i].length;
}
} else {
// old NSA filename def: filename, ending '\0' byte , compr-type byte,
// start (4byte), length (4byte))
ai->num_of_files = readShort( ai->file_handle );
ai->fi_list = new FileInfo[ ai->num_of_files ];
ai->base_offset = readLong( ai->file_handle );
ai->base_offset += offset;
for ( i=0 ; i<ai->num_of_files ; i++ ){
unsigned char ch;
int count = 0;
while( (ch = key_table[fgetc( ai->file_handle )] ) ){
if ( 'a' <= ch && ch <= 'z' ) ch += 'A' - 'a';
ai->fi_list[i].name[count++] = ch;
}
ai->fi_list[i].name[count] = ch;
if ( archive_type == ARCHIVE_TYPE_NSA )
ai->fi_list[i].compression_type = readChar( ai->file_handle );
else
ai->fi_list[i].compression_type = NO_COMPRESSION;
ai->fi_list[i].offset = readLong( ai->file_handle ) + ai->base_offset;
ai->fi_list[i].length = readLong( ai->file_handle );
if ( archive_type == ARCHIVE_TYPE_NSA ){
ai->fi_list[i].original_length = readLong( ai->file_handle );
}
else{
ai->fi_list[i].original_length = ai->fi_list[i].length;
}
/* Registered Plugin check */
if ( ai->fi_list[i].compression_type == NO_COMPRESSION )
ai->fi_list[i].compression_type = getRegisteredCompressionType( ai->fi_list[i].name );
if ( ai->fi_list[i].compression_type == NBZ_COMPRESSION ||
ai->fi_list[i].compression_type == SPB_COMPRESSION ){
// Delaying checking decompressed file length to prevent
// massive random access in the archives at the start-up.
ai->fi_list[i].original_length = 0;
}
}
}
}
int SarReader::writeHeaderSub( ArchiveInfo *ai, FILE *fp, int archive_type, int nsa_offset )
{
unsigned int i, j;
fseek( fp, 0L, SEEK_SET );
for (int k=0 ; k<nsa_offset ; k++)
fputc( 0, fp );
writeShort( fp, ai->num_of_files );
writeLong( fp, ai->base_offset-nsa_offset );
for ( i=0 ; i<ai->num_of_files ; i++ ){
for ( j=0 ; ai->fi_list[i].name[j] ; j++ )
fputc( ai->fi_list[i].name[j], fp );
fputc( ai->fi_list[i].name[j], fp );
if ( archive_type >= ARCHIVE_TYPE_NSA )
writeChar( fp, ai->fi_list[i].compression_type );
writeLong( fp, ai->fi_list[i].offset - ai->base_offset );
writeLong( fp, ai->fi_list[i].length );
if ( archive_type >= ARCHIVE_TYPE_NSA ){
writeLong( fp, ai->fi_list[i].original_length );
}
}
return 0;
}
int SarReader::writeHeader( FILE *fp )
{
ArchiveInfo *ai = archive_info.next;
return writeHeaderSub( ai, fp );
}
size_t SarReader::putFileSub( ArchiveInfo *ai, FILE *fp, int no, size_t offset, size_t length, size_t original_length, int compression_type, bool modified_flag, unsigned char *buffer )
{
ai->fi_list[no].compression_type = compression_type;
ai->fi_list[no].length = length;
ai->fi_list[no].original_length = original_length;
fseek( fp, offset, SEEK_SET );
if ( modified_flag ){
if ( ai->fi_list[no].compression_type == NBZ_COMPRESSION ){
writeLong( fp, ai->fi_list[no].original_length );
fseek( ai->file_handle, ai->fi_list[no].offset+2, SEEK_SET );
if ( readChar( ai->file_handle ) != 'B' || readChar( ai->file_handle ) != 'Z' ){ // in case the original is not compressed in NBZ
ai->fi_list[no].length = encodeNBZ( fp, length, buffer ) + 4;
ai->fi_list[no].offset = offset;
return ai->fi_list[no].length;
}
}
else{
ai->fi_list[no].compression_type = NO_COMPRESSION;
}
}
else{
fseek( ai->file_handle, ai->fi_list[no].offset, SEEK_SET );
fread( buffer, 1, ai->fi_list[no].length, ai->file_handle );
}
size_t len = ai->fi_list[no].length, c;
while( len > 0 ){
if ( len > WRITE_LENGTH ) c = WRITE_LENGTH;
else c = len;
len -= c;
fwrite( buffer, 1, c, fp );
buffer += c;
}
ai->fi_list[no].offset = offset;
return ai->fi_list[no].length;
}
size_t SarReader::putFile( FILE *fp, int no, size_t offset, size_t length, size_t original_length, bool modified_flag, unsigned char *buffer )
{
ArchiveInfo *ai = archive_info.next;
return putFileSub( ai, fp, no, offset, length, original_length, ai->fi_list[no].compression_type, modified_flag, buffer );
}
int SarReader::close()
{
ArchiveInfo *info = archive_info.next;
for ( int i=0 ; i<num_of_sar_archives ; i++ ){
last_archive_info = info;
info = info->next;
delete last_archive_info;
}
return 0;
}
const char *SarReader::getArchiveName() const
{
return "sar";
}
int SarReader::getNumFiles(){
ArchiveInfo *info = archive_info.next;
int num = 0;
for ( int i=0 ; i<num_of_sar_archives ; i++ ){
num += info->num_of_files;
info = info->next;
}
return num;
}
int SarReader::getIndexFromFile( ArchiveInfo *ai, const char *file_name )
{
unsigned int i, len;
len = strlen( file_name );
if ( len > MAX_FILE_NAME_LENGTH ) len = MAX_FILE_NAME_LENGTH;
memcpy( capital_name, file_name, len );
capital_name[ len ] = '\0';
for ( i=0 ; i<len ; i++ ){
if ( 'a' <= capital_name[i] && capital_name[i] <= 'z' ) capital_name[i] += 'A' - 'a';
else if ( capital_name[i] == '/' ) capital_name[i] = '\\';
}
for ( i=0 ; i<ai->num_of_files ; i++ ){
if ( !strcmp( capital_name, ai->fi_list[i].name ) ) break;
}
return i;
}
size_t SarReader::getFileLength( const char *file_name )
{
size_t ret;
if ( ( ret = DirectReader::getFileLength( file_name ) ) ) return ret;
ArchiveInfo *info = archive_info.next;
unsigned int j = 0;
for ( int i=0 ; i<num_of_sar_archives ; i++ ){
j = getIndexFromFile( info, file_name );
if ( j != info->num_of_files ) break;
info = info->next;
}
if ( !info ) return 0;
if ( info->fi_list[j].original_length != 0 )
return info->fi_list[j].original_length;
int type = info->fi_list[j].compression_type;
if ( type == NO_COMPRESSION )
type = getRegisteredCompressionType( file_name );
if ( type == NBZ_COMPRESSION || type == SPB_COMPRESSION ) {
info->fi_list[j].original_length = getDecompressedFileLength( type, info->file_handle, info->fi_list[j].offset );
}
return info->fi_list[j].original_length;
}
size_t SarReader::getFileSub( ArchiveInfo *ai, const char *file_name, unsigned char *buf )
{
unsigned int i = getIndexFromFile( ai, file_name );
if ( i == ai->num_of_files ) return 0;
#if defined(PSP)
if (ai->power_resume_number != psp_power_resume_number){
FILE *fp = fopen(ai->file_name, "rb");
ai->file_handle = fp;
ai->power_resume_number = psp_power_resume_number;
}
#endif
int type = ai->fi_list[i].compression_type;
if ( type == NO_COMPRESSION ) type = getRegisteredCompressionType( file_name );
if ( type == NBZ_COMPRESSION ){
return decodeNBZ( ai->file_handle, ai->fi_list[i].offset, buf );
}
else if ( type == LZSS_COMPRESSION ){
return decodeLZSS( ai, i, buf );
}
else if ( type == SPB_COMPRESSION ){
return decodeSPB( ai->file_handle, ai->fi_list[i].offset, buf );
}
fseek( ai->file_handle, ai->fi_list[i].offset, SEEK_SET );
size_t ret = fread( buf, 1, ai->fi_list[i].length, ai->file_handle );
if (key_table_flag)
for (size_t j=0 ; j<ret ; j++) buf[j] = key_table[buf[j]];
return ret;
}
size_t SarReader::getFile( const char *file_name, unsigned char *buf, int *location )
{
size_t ret;
if ( ( ret = DirectReader::getFile( file_name, buf, location ) ) ) return ret;
ArchiveInfo *info = archive_info.next;
size_t j = 0;
for ( int i=0 ; i<num_of_sar_archives ; i++ ){
if ( (j = getFileSub( info, file_name, buf )) > 0 ) break;
info = info->next;
}
if ( location ) *location = ARCHIVE_TYPE_SAR;
return j;
}
SarReader::FileInfo SarReader::getFileByIndex( unsigned int index )
{
ArchiveInfo *info = archive_info.next;
for ( int i=0 ; i<num_of_sar_archives ; i++ ){
if ( index < info->num_of_files ) return info->fi_list[index];
index -= info->num_of_files;
info = info->next;
}
fprintf( stderr, "SarReader::getFileByIndex Index %d is out of range\n", index );
return archive_info.fi_list[index];
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
C++
1
https://gitee.com/only998/Onscripter-Official.git
git@gitee.com:only998/Onscripter-Official.git
only998
Onscripter-Official
Onscripter-Official
master

搜索帮助

D67c1975 1850385 1daf7b77 1850385