245 строки
7.4 KiB
C
245 строки
7.4 KiB
C
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <zlib.h>
|
|
|
|
#include <dmg/dmg.h>
|
|
#include <inttypes.h>
|
|
|
|
#define SECTORS_AT_A_TIME 0x200
|
|
|
|
BLKXTable* insertBLKX(AbstractFile* out, AbstractFile* in, uint32_t firstSectorNumber, uint32_t numSectors, uint32_t blocksDescriptor,
|
|
uint32_t checksumType, ChecksumFunc uncompressedChk, void* uncompressedChkToken, ChecksumFunc compressedChk,
|
|
void* compressedChkToken, Volume* volume) {
|
|
BLKXTable* blkx;
|
|
|
|
uint32_t roomForRuns;
|
|
uint32_t curRun;
|
|
uint64_t curSector;
|
|
|
|
unsigned char* inBuffer;
|
|
unsigned char* outBuffer;
|
|
size_t bufferSize;
|
|
size_t have;
|
|
int ret;
|
|
|
|
z_stream strm;
|
|
|
|
|
|
blkx = (BLKXTable*) malloc(sizeof(BLKXTable) + (2 * sizeof(BLKXRun)));
|
|
roomForRuns = 2;
|
|
memset(blkx, 0, sizeof(BLKXTable) + (roomForRuns * sizeof(BLKXRun)));
|
|
|
|
blkx->fUDIFBlocksSignature = UDIF_BLOCK_SIGNATURE;
|
|
blkx->infoVersion = 1;
|
|
blkx->firstSectorNumber = firstSectorNumber;
|
|
blkx->sectorCount = numSectors;
|
|
blkx->dataStart = 0;
|
|
blkx->decompressBufferRequested = 0x208;
|
|
blkx->blocksDescriptor = blocksDescriptor;
|
|
blkx->reserved1 = 0;
|
|
blkx->reserved2 = 0;
|
|
blkx->reserved3 = 0;
|
|
blkx->reserved4 = 0;
|
|
blkx->reserved5 = 0;
|
|
blkx->reserved6 = 0;
|
|
memset(&(blkx->checksum), 0, sizeof(blkx->checksum));
|
|
blkx->checksum.type = checksumType;
|
|
blkx->checksum.size = 0x20;
|
|
blkx->blocksRunCount = 0;
|
|
|
|
bufferSize = SECTOR_SIZE * blkx->decompressBufferRequested;
|
|
|
|
ASSERT(inBuffer = (unsigned char*) malloc(bufferSize), "malloc");
|
|
ASSERT(outBuffer = (unsigned char*) malloc(bufferSize), "malloc");
|
|
|
|
curRun = 0;
|
|
curSector = 0;
|
|
|
|
while(numSectors > 0) {
|
|
if(curRun >= roomForRuns) {
|
|
roomForRuns <<= 1;
|
|
blkx = (BLKXTable*) realloc(blkx, sizeof(BLKXTable) + (roomForRuns * sizeof(BLKXRun)));
|
|
}
|
|
|
|
blkx->runs[curRun].type = BLOCK_ZLIB;
|
|
blkx->runs[curRun].reserved = 0;
|
|
blkx->runs[curRun].sectorStart = curSector;
|
|
blkx->runs[curRun].sectorCount = (numSectors > SECTORS_AT_A_TIME) ? SECTORS_AT_A_TIME : numSectors;
|
|
|
|
memset(&strm, 0, sizeof(strm));
|
|
strm.zalloc = Z_NULL;
|
|
strm.zfree = Z_NULL;
|
|
strm.opaque = Z_NULL;
|
|
|
|
printf("run %d: sectors=%" PRId64 ", left=%d\n", curRun, blkx->runs[curRun].sectorCount, numSectors);
|
|
|
|
ASSERT(deflateInit(&strm, Z_DEFAULT_COMPRESSION) == Z_OK, "deflateInit");
|
|
|
|
ASSERT((strm.avail_in = in->read(in, inBuffer, blkx->runs[curRun].sectorCount * SECTOR_SIZE)) == (blkx->runs[curRun].sectorCount * SECTOR_SIZE), "mRead");
|
|
strm.next_in = inBuffer;
|
|
|
|
if(uncompressedChk)
|
|
(*uncompressedChk)(uncompressedChkToken, inBuffer, blkx->runs[curRun].sectorCount * SECTOR_SIZE);
|
|
|
|
blkx->runs[curRun].compOffset = out->tell(out) - blkx->dataStart;
|
|
blkx->runs[curRun].compLength = 0;
|
|
|
|
strm.avail_out = bufferSize;
|
|
strm.next_out = outBuffer;
|
|
|
|
ASSERT((ret = deflate(&strm, Z_FINISH)) != Z_STREAM_ERROR, "deflate/Z_STREAM_ERROR");
|
|
if(ret != Z_STREAM_END) {
|
|
ASSERT(FALSE, "deflate");
|
|
}
|
|
have = bufferSize - strm.avail_out;
|
|
|
|
if((have / SECTOR_SIZE) > blkx->runs[curRun].sectorCount) {
|
|
blkx->runs[curRun].type = BLOCK_RAW;
|
|
ASSERT(out->write(out, inBuffer, blkx->runs[curRun].sectorCount * SECTOR_SIZE) == (blkx->runs[curRun].sectorCount * SECTOR_SIZE), "fwrite");
|
|
blkx->runs[curRun].compLength += blkx->runs[curRun].sectorCount * SECTOR_SIZE;
|
|
|
|
if(compressedChk)
|
|
(*compressedChk)(compressedChkToken, inBuffer, blkx->runs[curRun].sectorCount * SECTOR_SIZE);
|
|
|
|
} else {
|
|
ASSERT(out->write(out, outBuffer, have) == have, "fwrite");
|
|
|
|
if(compressedChk)
|
|
(*compressedChk)(compressedChkToken, outBuffer, have);
|
|
|
|
blkx->runs[curRun].compLength += have;
|
|
}
|
|
|
|
deflateEnd(&strm);
|
|
|
|
curSector += blkx->runs[curRun].sectorCount;
|
|
numSectors -= blkx->runs[curRun].sectorCount;
|
|
curRun++;
|
|
}
|
|
|
|
if(curRun >= roomForRuns) {
|
|
roomForRuns <<= 1;
|
|
blkx = (BLKXTable*) realloc(blkx, sizeof(BLKXTable) + (roomForRuns * sizeof(BLKXRun)));
|
|
}
|
|
|
|
blkx->runs[curRun].type = BLOCK_TERMINATOR;
|
|
blkx->runs[curRun].reserved = 0;
|
|
blkx->runs[curRun].sectorStart = curSector;
|
|
blkx->runs[curRun].sectorCount = 0;
|
|
blkx->runs[curRun].compOffset = out->tell(out) - blkx->dataStart;
|
|
blkx->runs[curRun].compLength = 0;
|
|
blkx->blocksRunCount = curRun + 1;
|
|
|
|
free(inBuffer);
|
|
free(outBuffer);
|
|
|
|
return blkx;
|
|
}
|
|
|
|
#define DEFAULT_BUFFER_SIZE (1 * 1024 * 1024)
|
|
|
|
void extractBLKX(AbstractFile* in, AbstractFile* out, BLKXTable* blkx) {
|
|
unsigned char* inBuffer;
|
|
unsigned char* outBuffer;
|
|
unsigned char zero;
|
|
size_t bufferSize;
|
|
size_t have;
|
|
off_t initialOffset;
|
|
int i;
|
|
int ret;
|
|
|
|
z_stream strm;
|
|
|
|
bufferSize = SECTOR_SIZE * blkx->decompressBufferRequested;
|
|
|
|
ASSERT(inBuffer = (unsigned char*) malloc(bufferSize), "malloc");
|
|
ASSERT(outBuffer = (unsigned char*) malloc(bufferSize), "malloc");
|
|
|
|
initialOffset = out->tell(out);
|
|
ASSERT(initialOffset != -1, "ftello");
|
|
|
|
zero = 0;
|
|
|
|
for(i = 0; i < blkx->blocksRunCount; i++) {
|
|
ASSERT(in->seek(in, blkx->dataStart + blkx->runs[i].compOffset) == 0, "fseeko");
|
|
ASSERT(out->seek(out, initialOffset + (blkx->runs[i].sectorStart * SECTOR_SIZE)) == 0, "mSeek");
|
|
|
|
if(blkx->runs[i].sectorCount > 0) {
|
|
ASSERT(out->seek(out, initialOffset + (blkx->runs[i].sectorStart + blkx->runs[i].sectorCount) * SECTOR_SIZE - 1) == 0, "mSeek");
|
|
ASSERT(out->write(out, &zero, 1) == 1, "mWrite");
|
|
ASSERT(out->seek(out, initialOffset + (blkx->runs[i].sectorStart * SECTOR_SIZE)) == 0, "mSeek");
|
|
}
|
|
|
|
if(blkx->runs[i].type == BLOCK_TERMINATOR) {
|
|
break;
|
|
}
|
|
|
|
if( blkx->runs[i].compLength == 0) {
|
|
continue;
|
|
}
|
|
|
|
printf("run %d: start=%" PRId64 " sectors=%" PRId64 ", length=%" PRId64 ", fileOffset=0x%" PRIx64 "\n", i, initialOffset + (blkx->runs[i].sectorStart * SECTOR_SIZE), blkx->runs[i].sectorCount, blkx->runs[i].compLength, blkx->runs[i].compOffset);
|
|
|
|
switch(blkx->runs[i].type) {
|
|
case BLOCK_ZLIB:
|
|
strm.zalloc = Z_NULL;
|
|
strm.zfree = Z_NULL;
|
|
strm.opaque = Z_NULL;
|
|
strm.avail_in = 0;
|
|
strm.next_in = Z_NULL;
|
|
|
|
ASSERT(inflateInit(&strm) == Z_OK, "inflateInit");
|
|
|
|
ASSERT((strm.avail_in = in->read(in, inBuffer, blkx->runs[i].compLength)) == blkx->runs[i].compLength, "fread");
|
|
strm.next_in = inBuffer;
|
|
|
|
do {
|
|
strm.avail_out = bufferSize;
|
|
strm.next_out = outBuffer;
|
|
ASSERT((ret = inflate(&strm, Z_NO_FLUSH)) != Z_STREAM_ERROR, "inflate/Z_STREAM_ERROR");
|
|
if(ret != Z_OK && ret != Z_BUF_ERROR && ret != Z_STREAM_END) {
|
|
ASSERT(FALSE, "inflate");
|
|
}
|
|
have = bufferSize - strm.avail_out;
|
|
ASSERT(out->write(out, outBuffer, have) == have, "mWrite");
|
|
} while (strm.avail_out == 0);
|
|
|
|
ASSERT(inflateEnd(&strm) == Z_OK, "inflateEnd");
|
|
break;
|
|
case BLOCK_RAW:
|
|
if(blkx->runs[i].compLength > bufferSize) {
|
|
uint64_t left = blkx->runs[i].compLength;
|
|
void* pageBuffer = malloc(DEFAULT_BUFFER_SIZE);
|
|
while(left > 0) {
|
|
size_t thisRead;
|
|
if(left > DEFAULT_BUFFER_SIZE) {
|
|
thisRead = DEFAULT_BUFFER_SIZE;
|
|
} else {
|
|
thisRead = left;
|
|
}
|
|
ASSERT((have = in->read(in, pageBuffer, thisRead)) == thisRead, "fread");
|
|
ASSERT(out->write(out, pageBuffer, have) == have, "mWrite");
|
|
left -= have;
|
|
}
|
|
free(pageBuffer);
|
|
} else {
|
|
ASSERT((have = in->read(in, inBuffer, blkx->runs[i].compLength)) == blkx->runs[i].compLength, "fread");
|
|
ASSERT(out->write(out, inBuffer, have) == have, "mWrite");
|
|
}
|
|
break;
|
|
case BLOCK_IGNORE:
|
|
break;
|
|
case BLOCK_COMMENT:
|
|
break;
|
|
case BLOCK_TERMINATOR:
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
free(inBuffer);
|
|
free(outBuffer);
|
|
}
|