mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-01-22 13:48:34 +00:00
176 lines
4.4 KiB
C++
176 lines
4.4 KiB
C++
// Copyright (c) 2012- PPSSPP Project.
|
|
|
|
// 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, version 2.0 or later versions.
|
|
|
|
// 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 2.0 for more details.
|
|
|
|
// A copy of the GPL 2.0 should have been included with the program.
|
|
// If not, see http://www.gnu.org/licenses/
|
|
|
|
// Official git repository and contact information can be found at
|
|
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
|
|
|
extern "C"
|
|
{
|
|
#include "zlib.h"
|
|
};
|
|
|
|
#include "BlockDevices.h"
|
|
#include <cstdio>
|
|
#include <cstring>
|
|
|
|
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;
|
|
}
|
|
|
|
// .CSO format
|
|
|
|
// complessed ISO(9660) header format
|
|
typedef struct ciso_header
|
|
{
|
|
unsigned char magic[4]; // +00 : 'C','I','S','O'
|
|
u32 header_size; // +04 : header size (==0x18)
|
|
u64 total_bytes; // +08 : number of original data size
|
|
u32 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;
|
|
|
|
|
|
// TODO: Need much better error handling.
|
|
|
|
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
|
|
{
|
|
DEBUG_LOG(LOADER, "Valid CSO!");
|
|
}
|
|
if (hdr.ver > 1)
|
|
{
|
|
ERROR_LOG(LOADER, "CSO version too high!");
|
|
//ARGH!
|
|
}
|
|
|
|
int hdrSize = hdr.header_size;
|
|
blockSize = hdr.block_size;
|
|
if (blockSize != 0x800)
|
|
{
|
|
ERROR_LOG(LOADER, "CSO Unsupported Block Size");
|
|
}
|
|
indexShift = hdr.align;
|
|
u64 totalSize = hdr.total_bytes;
|
|
numBlocks = (int)(totalSize / blockSize);
|
|
DEBUG_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;
|
|
}
|
|
|
|
bool CISOFileBlockDevice::ReadBlock(int blockNumber, u8 *outPtr)
|
|
{
|
|
u32 idx = index[blockNumber];
|
|
u32 idx2 = index[blockNumber+1];
|
|
u8 inbuffer[4096]; //too big
|
|
z_stream z;
|
|
|
|
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)
|
|
{
|
|
ERROR_LOG(LOADER, "deflateInit ERROR : %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)
|
|
{
|
|
ERROR_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 != (int)blockSize)
|
|
{
|
|
ERROR_LOG(LOADER, "block %d : block size error %d != %d\n", blockNumber, cmp_size, blockSize);
|
|
return 1;
|
|
}
|
|
}
|
|
return true;
|
|
}
|