[Add] Wrapper for the rle packer (SCpak).
This commit is contained in:
parent
0b6e0cf094
commit
7bcd594476
@ -43,6 +43,7 @@ HEADERS += ../src/Actor/Player.h \
|
||||
../src/System/ResourceManager.h \
|
||||
../src/System/Convert/str2int.h \
|
||||
../src/System/Filesystem/SCpak.h \
|
||||
../src/System/Filesystem/RlePackedFileWrapper.h \
|
||||
../src/System/Filesystem/IOapi.h \
|
||||
../src/System/Filesystem/FileTimestampChecker.h \
|
||||
../src/System/Convert/ConvertType.h \
|
||||
@ -112,6 +113,7 @@ SOURCES += ../src/Actor/Player.cpp \
|
||||
../src/System/Debug.cpp \
|
||||
../src/System/Convert/str2int.cpp \
|
||||
../src/System/Filesystem/SCpak.cpp \
|
||||
../src/System/Filesystem/RlePackedFileWrapper.cpp \
|
||||
../src/System/Filesystem/FileTimestampChecker.cpp \
|
||||
../src/System/Filesystem/OutputCompressedFileStream.cpp \
|
||||
../src/System/Filesystem/InputCompressedFileStream.cpp \
|
||||
|
348
src/System/Filesystem/RlePackedFileWrapper.cpp
Normal file
348
src/System/Filesystem/RlePackedFileWrapper.cpp
Normal file
@ -0,0 +1,348 @@
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "SCpak.h"
|
||||
#include "InputStreamWrapper.h"
|
||||
#include "RlePackedFileWrapper.h"
|
||||
|
||||
#define USE_SC_INPUT_STREAM_WRAPPER
|
||||
|
||||
static const int RLE_PACKED_CHUNK_MAGIC = *((int*)"RLE1");
|
||||
|
||||
using namespace saracraft::filesystem;
|
||||
|
||||
|
||||
struct RLE_PACKED_FILE {
|
||||
#ifdef USE_SC_INPUT_STREAM_WRAPPER
|
||||
SC_FILE* inputFile;
|
||||
#else
|
||||
FILE* inputtFile;
|
||||
#endif
|
||||
FILE* outputFile;
|
||||
bool errorFlag;
|
||||
bool inputIsRle;
|
||||
|
||||
RLE_PACKED_FILE(void) :
|
||||
inputFile(NULL), outputFile(NULL), errorFlag(false), inputIsRle(false) {
|
||||
|
||||
}
|
||||
|
||||
~RLE_PACKED_FILE(void) {
|
||||
assert(inputFile == NULL);
|
||||
assert(outputFile == NULL);
|
||||
}
|
||||
};
|
||||
|
||||
bool RlePackedDetect(const char* filename) {
|
||||
bool wasRLE = false;
|
||||
#ifdef USE_SC_INPUT_STREAM_WRAPPER
|
||||
SC_FILE* inputFile = sc_fopen(filename, "rb");
|
||||
#else
|
||||
FILE* inputFile = fopen(filename, "rb");
|
||||
#endif
|
||||
if(inputFile != NULL) {
|
||||
int chunkId;
|
||||
#ifdef USE_SC_INPUT_STREAM_WRAPPER
|
||||
int got = sc_fread(&chunkId, sizeof(int), 1, inputFile);
|
||||
#else
|
||||
int got = fread(&chunkId, sizeof(int), 1, inputFile);
|
||||
#endif
|
||||
if(got == 1 && chunkId == RLE_PACKED_CHUNK_MAGIC) {
|
||||
wasRLE = true;
|
||||
}
|
||||
|
||||
#ifdef USE_SC_INPUT_STREAM_WRAPPER
|
||||
sc_fclose(inputFile);
|
||||
#else
|
||||
fclose(inputFile);
|
||||
#endif
|
||||
}
|
||||
return wasRLE;
|
||||
}
|
||||
|
||||
RLE_PACKED_FILE* RlePacked_fopen(const char* filename, const char* params) {
|
||||
assert(params != NULL);
|
||||
if(params == NULL)
|
||||
return NULL;
|
||||
|
||||
if(strcmp(params, "rb") == 0) {
|
||||
bool rle = false;
|
||||
if(RlePackedDetect(filename))
|
||||
rle = true;
|
||||
|
||||
#ifdef USE_SC_INPUT_STREAM_WRAPPER
|
||||
SC_FILE* inputFile = sc_fopen(filename, params);
|
||||
#else
|
||||
FILE* inputFile = fopen(filename, params);
|
||||
#endif
|
||||
if(inputFile != NULL) {
|
||||
RLE_PACKED_FILE* f = new RLE_PACKED_FILE();
|
||||
f->inputFile = inputFile;
|
||||
f->inputIsRle = rle;
|
||||
return f;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else if(strcmp(params, "wb") == 0) {
|
||||
FILE* outputFile = fopen(filename, params);
|
||||
if(outputFile != NULL) {
|
||||
RLE_PACKED_FILE* f = new RLE_PACKED_FILE();
|
||||
f->outputFile = outputFile;
|
||||
return f;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
assert(!"RlePacked_fopen - unsupported open params.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t RlePacked_fread(void* buffer, size_t size, size_t count, RLE_PACKED_FILE* stream) {
|
||||
assert(stream != NULL);
|
||||
assert(stream->inputFile != NULL);
|
||||
|
||||
if(!stream->inputIsRle) {
|
||||
#ifdef USE_SC_INPUT_STREAM_WRAPPER
|
||||
size_t ret = sc_fread(buffer, size, count, stream->inputFile);
|
||||
#else
|
||||
size_t ret = fread(buffer, size, count, stream->inputFile);
|
||||
#endif
|
||||
if(ret <= 0)
|
||||
stream->errorFlag = true;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int tmpgot = 0;
|
||||
int chunkId = 0;
|
||||
char isPacked = 0;
|
||||
int packedSize = 0;
|
||||
int unpackedSize = 0;
|
||||
|
||||
#ifdef USE_SC_INPUT_STREAM_WRAPPER
|
||||
tmpgot = sc_fread(&chunkId, sizeof(int), 1, stream->inputFile);
|
||||
#else
|
||||
tmpgot = fread(&chunkId, sizeof(int), 1, stream->inputFile);
|
||||
#endif
|
||||
if(tmpgot != 1) {
|
||||
assert(!"RlePacked_fread - no more data available (expected chunk id, but got nothing).");
|
||||
stream->errorFlag = true;
|
||||
return 0;
|
||||
}
|
||||
if(chunkId != RLE_PACKED_CHUNK_MAGIC) {
|
||||
assert(!"RlePacked_fread - invalid data (expected chunk id, but got something else).");
|
||||
stream->errorFlag = true;
|
||||
return 0;
|
||||
}
|
||||
#ifdef USE_SC_INPUT_STREAM_WRAPPER
|
||||
tmpgot = sc_fread(&isPacked, sizeof(char), 1, stream->inputFile);
|
||||
#else
|
||||
tmpgot = fread(&isPacked, sizor(char), 1, stream->inputFile);
|
||||
#endif
|
||||
if(tmpgot != 1) {
|
||||
assert(!"RlePacked_fread - truncated chunk header (expected packed flag). ");
|
||||
stream->errorFlag = true;
|
||||
return 0;
|
||||
}
|
||||
if(isPacked != 0 && isPacked != 1) {
|
||||
assert(!"RlePacked_fread - invalid data (expected packed flag, but got something else). ");
|
||||
stream->errorFlag = true;
|
||||
return 0;
|
||||
}
|
||||
#ifdef USE_SC_INPUT_STREAM_WRAPPER
|
||||
tmpgot = sc_fread(&packedSize, sizeof(int), 1, stream->inputFile);
|
||||
#else
|
||||
tmpgot = fread(&packedSize, sizeof(int), 1, stream->inputFile);
|
||||
#endif
|
||||
if(tmpgot != 1) {
|
||||
assert(!"RlePacked_fread - truncated chunk header (expected packed size). ");
|
||||
stream->errorFlag = true;
|
||||
return 0;
|
||||
}
|
||||
if(packedSize <= 0) {
|
||||
assert(!"RlePacked_fread - invalid data (packed size is zero or negative). ");
|
||||
stream->errorFlag = true;
|
||||
return 0;
|
||||
}
|
||||
if(packedSize > (int)count * (int)size) {
|
||||
assert(!"RlePacked_fread - invalid data (size of packed chunk is larger than requested data). ");
|
||||
stream->errorFlag = true;
|
||||
return 0;
|
||||
}
|
||||
#ifdef USE_SC_INPUT_STREAM_WRAPPER
|
||||
tmpgot = sc_fread(&unpackedSize, sizeof(int), 1, stream->inputFile);
|
||||
#else
|
||||
tmpgot = fread(&unpackedSize, sizeof(int), 1, stream->inputFile);
|
||||
#endif
|
||||
if(tmpgot != 1) {
|
||||
assert(!"RlePacked_fread - truncated chunk header (expected unpacked size). ");
|
||||
stream->errorFlag = true;
|
||||
return 0;
|
||||
}
|
||||
if(unpackedSize <= 0) {
|
||||
assert(!"RlePacked_fread - invalid data (unpacked size is zero or negative). ");
|
||||
stream->errorFlag = true;
|
||||
return 0;
|
||||
}
|
||||
if(unpackedSize != count * size) {
|
||||
assert(!"RlePacked_fread - invalid data (size of unpacked chunk does not equal requested size).");
|
||||
stream->errorFlag = true;
|
||||
return 0;
|
||||
}
|
||||
if(!isPacked && packedSize != unpackedSize) {
|
||||
assert(!"RlePacked_fread - invalid data (supposed to be unpacked chunk, but packed and unpacked size mismatch).");
|
||||
stream->errorFlag = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned char* packedbuf = new unsigned char[packedSize+16];
|
||||
|
||||
#ifdef USE_SC_INPUT_STREAM_WRAPPER
|
||||
int got = sc_fread(packedbuf, packedSize, 1, stream->inputFile);
|
||||
#else
|
||||
int got = fread(packedbuf, packedSize, 1, stream->inputFile);
|
||||
#endif
|
||||
if(got == 1) {
|
||||
if(isPacked) {
|
||||
scpak_set_bits(16);
|
||||
scpak_set_16bit_params(0xA0EA, 0xA0EB, 0xA0EC);
|
||||
int resultSize = scpak_unpack(packedSize, packedbuf, (unsigned char*)buffer, unpackedSize);
|
||||
if(resultSize != unpackedSize) {
|
||||
assert(!"RlePacked_fread - invalid data (chunk header unpacked size did not match actual resulting unpacked size).");
|
||||
stream->errorFlag = true;
|
||||
delete [] packedbuf;
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
memcpy(buffer, packedbuf, packedSize);
|
||||
}
|
||||
delete [] packedbuf;
|
||||
return count;
|
||||
} else {
|
||||
delete [] packedbuf;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
size_t RlePacked_fwrite(void* buffer, size_t size, size_t count, RLE_PACKED_FILE* stream) {
|
||||
assert(stream != NULL);
|
||||
assert(stream->outputFile != NULL);
|
||||
assert(size > 0 && count > 0);
|
||||
|
||||
int unpackedSize = (int)size*(int)count;
|
||||
assert(unpackedSize > 0);
|
||||
|
||||
unsigned char* packedbuf = new unsigned char[unpackedSize+16];
|
||||
|
||||
scpak_set_bits(16);
|
||||
scpak_set_16bit_params(0xA0EA, 0xA0EB, 0xA0EC);
|
||||
int packedSize = scpak_pack(unpackedSize, (unsigned char*)buffer, packedbuf);
|
||||
|
||||
char isPacked = 1;
|
||||
if(packedSize == 0) {
|
||||
isPacked = 0;
|
||||
packedSize = unpackedSize;
|
||||
memcpy(packedbuf, buffer, packedSize);
|
||||
}
|
||||
|
||||
int tmpgot = 0;
|
||||
|
||||
tmpgot = fwrite(&RLE_PACKED_CHUNK_MAGIC, sizeof(int), 1, stream->outputFile);
|
||||
if(tmpgot != 1) {
|
||||
assert(!"RlePacked_fwrte - write failed (chunk id).");
|
||||
stream->errorFlag = true;
|
||||
delete [] packedbuf;
|
||||
return 0;
|
||||
}
|
||||
|
||||
tmpgot = fwrite(&isPacked, sizeof(char), 1, stream->outputFile);
|
||||
if(tmpgot != 1) {
|
||||
assert(!"RlePacked_fwrite - write failed (chunk packed flag).");
|
||||
stream->errorFlag = true;
|
||||
delete [] packedbuf;
|
||||
return 0;
|
||||
}
|
||||
|
||||
tmpgot = fwrite(&packedSize, sizeof(int), 1, stream->outputFile);
|
||||
if(tmpgot != 1) {
|
||||
assert(!"RlePacked_fwrite - write failed (chunk packed size).");
|
||||
stream->errorFlag = true;
|
||||
delete [] packedbuf;
|
||||
return 0;
|
||||
}
|
||||
|
||||
tmpgot = fwrite(&unpackedSize, sizeof(int), 1, stream->outputFile);
|
||||
if(tmpgot != 1) {
|
||||
assert(!"RlePacked_fwrite - write failed (chunk unpacked size).");
|
||||
stream->errorFlag = true;
|
||||
delete [] packedbuf;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int got = fwrite(packedbuf, packedSize, 1, stream->outputFile);
|
||||
if(got != 1) {
|
||||
assert(!"RlePacked_fwrite - write failed (packed data).");
|
||||
stream->errorFlag = true;
|
||||
delete [] packedbuf;
|
||||
return 0;
|
||||
}
|
||||
|
||||
delete [] packedbuf;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
long RlePacked_fsize(RLE_PACKED_FILE* stream) {
|
||||
assert(stream != NULL);
|
||||
assert(stream->inputFile != NULL || stream->outputFile != NULL);
|
||||
|
||||
if(stream->inputFile != NULL) {
|
||||
#ifdef USE_SC_INPUT_STREAM_WRAPPER
|
||||
return sc_fsize(stream->inputFile);
|
||||
#else
|
||||
fpos_t pos;
|
||||
if(fgetpos(stream->inputFile, &pos) != 0) {
|
||||
assert(!"fgetpos failed.");
|
||||
stream->errorFlag = true;
|
||||
return -1;
|
||||
}
|
||||
fseek(stream->inputFile, 0, SEEK_END);
|
||||
long tmp = ftell(stream->inputFile);
|
||||
|
||||
if(fsetpos(stream->inputFile, &pos) != 0) {
|
||||
assert(!"fsetpos failed.");
|
||||
stream->errorFlag = true;
|
||||
return -1;
|
||||
}
|
||||
return tmp;
|
||||
#endif
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int RlePacked_fclose(RLE_PACKED_FILE* stream) {
|
||||
assert(stream != NULL);
|
||||
assert(stream->inputFile != NULL || stream->outputFile != NULL);
|
||||
|
||||
int result = 0;
|
||||
if(stream->inputFile != NULL) {
|
||||
#ifdef USE_SC_INPUT_STREAM_WRAPPER
|
||||
result = sc_fclose(stream->inputFile);
|
||||
#else
|
||||
result = fclose(stream->inputFile);
|
||||
#endif
|
||||
stream->inputFile = NULL;
|
||||
}
|
||||
if(stream->outputFile != NULL) {
|
||||
fclose(stream->outputFile);
|
||||
stream->outputFile = NULL;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool RlePackedWasError(RLE_PACKED_FILE* stream) {
|
||||
assert(stream != NULL);
|
||||
return stream->errorFlag;
|
||||
}
|
||||
|
24
src/System/Filesystem/RlePackedFileWrapper.h
Normal file
24
src/System/Filesystem/RlePackedFileWrapper.h
Normal file
@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
// A silly read/write "chunk packed" file.
|
||||
// *Must* read data in the same sized chunks as it was written!
|
||||
// Also reading/writing in really small chunks will just result in extremely
|
||||
// large files..
|
||||
|
||||
struct RLE_PACKED_FILE;
|
||||
|
||||
// Return true if the file seems to be rle packed.
|
||||
bool RlePackedDetect(const char* filename);
|
||||
|
||||
RLE_PACKED_FILE* RlePacked_fopen(const char* filename, const char* params);
|
||||
|
||||
size_t RlePacked_fread(void* buffer, size_t size, size_t count, RLE_PACKED_FILE* stream);
|
||||
|
||||
size_t RlePacked_fwrite(void* buffer, size_t size, size_t count, RLE_PACKED_FILE* stream);
|
||||
|
||||
long RlePacked_fsize(RLE_PACKED_FILE* stream);
|
||||
|
||||
bool RlePackedWasError(RLE_PACKED_FILE* stream);
|
||||
|
||||
int RlePacked_fclose(RLE_PACKED_FILE* stream);
|
||||
|
Loading…
Reference in New Issue
Block a user