www.pudn.com > potemkin_sourceforPSP.rar > BlockDevices.cpp
#include "stdafx.h"
extern "C"
{
#include "../../zlib/zlib.h"
};
#include "BlockDevices.h"
FileBlockDevice::FileBlockDevice(std::string _filename)
: filename(_filename)
{
f = fopen(_filename.c_str(), "rb");
fseek(f,0,SEEK_END);
filesize = ftell(f);
fseek(f,0,SEEK_SET);
}
FileBlockDevice::~FileBlockDevice()
{
fclose(f);
}
bool FileBlockDevice::ReadBlock(int blockNumber, u8 *outPtr)
{
fseek(f, blockNumber * GetBlockSize(), SEEK_SET);
fread(outPtr, 2048, 1, f);
return true;
}
//complessed ISO(9660) header format
typedef struct ciso_header
{
unsigned char magic[4]; // +00 : 'C','I','S','O'
unsigned long header_size; // +04 : header size (==0x18)
unsigned long long total_bytes; // +08 : number of original data size
unsigned long block_size; // +10 : number of compressed block size
unsigned char ver; // +14 : version 01
unsigned char align; // +15 : align of index value
unsigned char rsv_06[2]; // +16 : reserved
#if 0
// INDEX BLOCK
unsigned int index[0]; // +18 : block[0] index
unsigned int index[1]; // +1C : block[1] index
:
:
unsigned int index[last]; // +?? : block[last]
unsigned int index[last+1]; // +?? : end of last data point
// DATA BLOCK
unsigned char data[]; // +?? : compressed or plain sector data
#endif
} CISO_H;
CISOFileBlockDevice::CISOFileBlockDevice(std::string _filename)
: filename(_filename)
{
//CISO format is EXTREMELY crappy and incomplete. All tools make broken CISO.
f = fopen(_filename.c_str(), "rb");
CISO_H hdr;
fread(&hdr, 1, sizeof(CISO_H), f);
if (memcmp(hdr.magic, "CISO", 4) != 0)
{
//ARGH!
}
else
{
LOG(LOADER, "Valid CSO!");
}
if (hdr.ver > 1)
{
LOG(LOADER, "CSO version too high!");
//ARGH!
}
int hdrSize = hdr.header_size;
blockSize = hdr.block_size;
if (blockSize != 0x800)
{
LOG(LOADER, "CSO Unsupported Block Size");
}
indexShift = hdr.align;
u64 totalSize = hdr.total_bytes;
numBlocks = (int)(totalSize / blockSize);
LOG(LOADER, "hdrSize=%i numBlocks=%i align=%i", hdrSize, numBlocks, indexShift);
int indexSize = numBlocks + 1;
index = new u32[indexSize];
fread(index, 4, indexSize, f);
}
CISOFileBlockDevice::~CISOFileBlockDevice()
{
fclose(f);
delete [] index;
}
u8 inbuffer[4096]; //too big
z_stream z;
u8 inbuffer2[4096]; //too big
bool CISOFileBlockDevice::ReadBlock(int blockNumber, u8 *outPtr)
{
u32 idx = index[blockNumber];
u32 idx2 = index[blockNumber+1];
int plain = idx & 0x80000000;
idx = (idx & 0x7FFFFFFF) << indexShift;
idx2 = (idx2 & 0x7FFFFFFF) << indexShift;
u32 compressedReadPos = idx;
u32 compressedReadSize = idx2 - idx;
fseek(f, compressedReadPos, SEEK_SET);
fread(inbuffer, compressedReadSize, 1, f);
if (plain)
{
memset(outPtr, 0, 2048);
memcpy(outPtr, inbuffer, compressedReadSize);
}
else
{
memset(outPtr, 0, 2048);
z.zalloc = Z_NULL;
z.zfree = Z_NULL;
z.opaque = Z_NULL;
if(inflateInit2(&z, -15) != Z_OK)
{
LOG(LOADER, "deflateInit : %s\n", (z.msg) ? z.msg : "???");
return 1;
}
z.avail_in = compressedReadSize;
z.next_out = outPtr;
z.avail_out = blockSize;
z.next_in = inbuffer;
int status = inflate(&z, Z_FULL_FLUSH);
if(status != Z_STREAM_END)
//if (status != Z_OK)
{
LOG(LOADER, "block %d:inflate : %s[%d]\n", blockNumber, (z.msg) ? z.msg : "error", status);
return 1;
}
int cmp_size = blockSize - z.avail_out;
if(cmp_size != blockSize)
{
LOG(LOADER, "block %d : block size error %d != %d\n", blockNumber, cmp_size, blockSize);
return 1;
}
}
return true;
}
/*
#ifndef __CISO_H__
#define __CISO_H__
#define SWAPLL(x) \
( \
(((x) & 0xff00000000000000LL) >> 8 * 7) \
| (((x) & 0xff000000000000LL) >> 8 * 5) \
| (((x) & 0xff0000000000LL) >> 8 * 3) \
| (((x) & 0xff00000000LL) >> 8 * 1) \
| (((x) & 0xff000000LL) << 8 * 1) \
| (((x) & 0xff0000LL) << 8 * 3) \
| (((x) & 0xff00LL) << 8 * 5) \
| (((x) & 0xffLL) << 8 * 7) \
)
#define SWAPL(x) (((((unsigned long) x)) >> 24) | (((x) & 0xff0000) >> 8) | (((x) & 0xff00) << 8) | (((x)) << 24))
#define SWAPW(x) ((((x) & 0xff00) >> 8) | (((x) & 0xff) << 8))
//note:
//file_pos_sector[n] = (index[n]&0x7fffffff) << CISO_H.align
//file_size_sector[n] = ( (index[n+1]&0x7fffffff) << CISO_H.align) - file_pos_sector[n]
//if(index[n]&0x80000000)
//// read 0x800 without compress
//else
//// read file_size_sector[n] bytes and decompress data
#endif
const char *fname_in, *fname_out;
FILE *fin, *fout;
z_stream z;
unsigned int *index_buf = NULL;
unsigned int *crc_buf = NULL;
unsigned char *block_buf1 = NULL;
unsigned char *block_buf2 = NULL;
//***************************************************************************
//compress ISO to CSO
//***************************************************************************
CISO_H ciso;
int ciso_total_block;
unsigned long long check_file_size(FILE * fp)
{
unsigned long long pos;
if(fseek(fp, 0, SEEK_END) < 0)
return -1;
pos = ftell(fp);
if(pos == -1)
return pos;
// init ciso header
memset(&ciso, 0, sizeof(ciso));
ciso.magic[0] = 'C';
ciso.magic[1] = 'I';
ciso.magic[2] = 'S';
ciso.magic[3] = 'O';
ciso.ver = 0x01;
ciso.block_size = 0x800; // ISO9660 one of sector
ciso.total_bytes = pos;
#if 0
// align >0 has bug
for(ciso.align = 0; (ciso.total_bytes >> ciso.align) > 0x80000000LL; ciso.align++);
#endif
ciso_total_block = pos / ciso.block_size;
fseek(fp, 0, SEEK_SET);
return pos;
}
void endianconvert_header(CISO_H *header)
{
// typedef struct ciso_header
// {
// unsigned char magic[4]; // +00 : 'C','I','S','O'
// unsigned long header_size; // +04 : header size (==0x18)
// unsigned long long total_bytes; // +08 : number of original data size
// unsigned long block_size; // +10 : number of compressed block size
// unsigned char ver; // +14 : version 01
// unsigned char align; // +15 : align of index value
// unsigned char rsv_06[2]; // +16 : reserved
// } CISO_H;
header->header_size = SWAPL(header->header_size);
header->total_bytes = SWAPLL(header->total_bytes);
header->block_size = SWAPL(header->block_size);
}
//****************************************************************************
//decompress CSO to ISO
//****************************************************************************
int decomp_ciso(void)
{
unsigned long long file_size;
unsigned int index, index2;
unsigned long long read_pos, read_size;
int total_sectors;
int index_size;
int block;
unsigned char buf4[4];
int cmp_size;
int status;
int percent_period;
int percent_cnt;
int plain;
// read header
if(fread(&ciso, 1, sizeof(ciso), fin) != sizeof(ciso))
{
printf("file read error\n");
return 1;
}
endianconvert_header(&ciso);
// check header
if(
ciso.magic[0] != 'C' ||
ciso.magic[1] != 'I' ||
ciso.magic[2] != 'S' ||
ciso.magic[3] != 'O' ||
ciso.block_size == 0 ||
ciso.total_bytes == 0
)
{
printf("ciso file format error\n");
return 1;
}
ciso_total_block = ciso.total_bytes / ciso.block_size;
// printf("header_size: %d\n", ciso.header_size); // only for debug
// printf("total_bytes: %lld\n", ciso.total_bytes); // only for debug
// printf("block_size: %d\n", ciso.block_size); // only for debug
// printf("total block: %d\n", ciso_total_block); // only for debug
// allocate index block
index_size = (ciso_total_block + 1) * sizeof(unsigned long);
// printf("index size: %d\n", index_size); // only for debug
index_buf = malloc(index_size);
block_buf1 = malloc(ciso.block_size);
block_buf2 = malloc(ciso.block_size * 2);
if(!index_buf || !block_buf1 || !block_buf2)
{
printf("Can't allocate memory\n");
return 1;
}
memset(index_buf, 0, index_size);
// read index block
if(fread(index_buf, 1, index_size, fin) != index_size)
{
printf("file read error\n");
return 1;
}
// show info
printf("Decompress '%s' to '%s'\n", fname_in, fname_out);
printf("Total File Size %lld bytes\n", ciso.total_bytes);
printf("block size %d bytes\n", ciso.block_size);
printf("total blocks %d blocks\n", ciso_total_block);
printf("index align %d\n", 1 << ciso.align);
// init zlib
z.zalloc = Z_NULL;
z.zfree = Z_NULL;
z.opaque = Z_NULL;
// decompress data
percent_period = ciso_total_block / 100;
percent_cnt = 0;
for(block = 0; block < ciso_total_block; block++)
{
if(--percent_cnt <= 0)
{
percent_cnt = percent_period;
printf("decompress %d%%\r", block / percent_period);
fflush(stdout);
}
if(inflateInit2(&z, -15) != Z_OK)
{
printf("deflateInit : %s\n", (z.msg) ? z.msg : "???");
return 1;
}
// check index
index = SWAPL(index_buf[block]);
plain = index & 0x80000000;
index &= 0x7fffffff;
read_pos = index << (ciso.align);
if(plain)
{
read_size = ciso.block_size;
}
else
{
index2 = SWAPL(index_buf[block + 1]) & 0x7fffffff;
read_size = (index2 - index) << (ciso.align);
}
fseek(fin, read_pos, SEEK_SET);
z.avail_in = fread(block_buf2, 1, read_size, fin);
if(z.avail_in != read_size)
{
printf("block=%d : read error\n", block);
return 1;
}
if(plain)
{
memcpy(block_buf1, block_buf2, read_size);
cmp_size = read_size;
}
else
{
z.next_out = block_buf1;
z.avail_out = ciso.block_size;
z.next_in = block_buf2;
status = inflate(&z, Z_FULL_FLUSH);
if(status != Z_STREAM_END)
//if (status != Z_OK)
{
printf("block %d:inflate : %s[%d]\n", block, (z.msg) ? z.msg : "error", status);
return 1;
}
cmp_size = ciso.block_size - z.avail_out;
if(cmp_size != ciso.block_size)
{
printf("block %d : block size error %d != %d\n", block, cmp_size, ciso.block_size);
return 1;
}
}
// write decompressed block
if(fwrite(block_buf1, 1, cmp_size, fout) != cmp_size)
{
printf("block %d : Write error\n", block);
return 1;
}
// term zlib
if(inflateEnd(&z) != Z_OK)
{
printf("inflateEnd : %s\n", (z.msg) ? z.msg : "error");
return 1;
}
}
printf("ciso decompress completed\n");
return 0;
}
*/