diff --git a/Bin/LibD.pro b/Bin/LibD.pro index fbd96cf..35a6dbd 100644 --- a/Bin/LibD.pro +++ b/Bin/LibD.pro @@ -10,6 +10,7 @@ LIBS += -lGL \ -lSDL_mixer \ -lSDL_ttf \ -lminizip + win32: { LIBS -= -lGL \ -lGLU @@ -41,6 +42,7 @@ HEADERS += ../src/Actor/Player.h \ ../src/System/Debug.h \ ../src/System/ResourceManager.h \ ../src/System/Convert/str2int.h \ + ../src/System/Filesystem/SCpak.h \ ../src/System/Filesystem/IOapi.h \ ../src/System/Filesystem/FileTimestampChecker.h \ ../src/System/Convert/ConvertType.h \ @@ -109,6 +111,7 @@ SOURCES += ../src/Actor/Player.cpp \ ../src/Sprite/Sprite.cpp \ ../src/System/Debug.cpp \ ../src/System/Convert/str2int.cpp \ + ../src/System/Filesystem/SCpak.cpp \ ../src/System/Filesystem/FileTimestampChecker.cpp \ ../src/System/Filesystem/OutputCompressedFileStream.cpp \ ../src/System/Filesystem/InputCompressedFileStream.cpp \ diff --git a/src/System/Filesystem/SCpak.cpp b/src/System/Filesystem/SCpak.cpp new file mode 100644 index 0000000..6e096e8 --- /dev/null +++ b/src/System/Filesystem/SCpak.cpp @@ -0,0 +1,327 @@ +#include +#include "SCpak.h" + +unsigned char scpak_bits = 8; + +// These mark values 1-3 must be incremental!!! +unsigned char scpak_mark8_1 = 0xFA; +unsigned char scpak_mark8_2 = 0xFB; +unsigned char scpak_mark8_3 = 0xFC; + +unsigned short scpak_mark16_1 = 0xA0EA; +unsigned short scpak_mark16_2 = 0xA0EB; +unsigned short scpak_mark16_3 = 0xA0EC; + +void scpak_set_bits(unsigned char bits) { + if(bits == 8 || bits == 16) { + scpak_bits = bits; + } else { + // An error accured. + assert("scpak_set_bits - invalid parameter."); + } +} + +void scpak_set_8bit_params(unsigned char mark1, unsigned char mark2, unsigned char mark3) { + if(mark1 != mark2 && mark1 != mark3 && mark2 != mark3 + && mark2 == mark1 + 1 && mark3 == mark2 + 1) { + + scpak_mark8_1 = mark1; + scpak_mark8_2 = mark2; + scpak_mark8_3 = mark3; + } else { + // Error! + assert(!"scpak_set_8bit_params - invalid parameter."); + } +} + +void scpak_set_16bit_params(unsigned short mark1, unsigned short mark2, unsigned short mark3) { + if(mark1 != mark2 && mark1 != mark3 && mark2 != mark3 + && mark2 == mark1 + 1 && mark3 == mark2 + 1) { + scpak_mark16_1 = mark1; + scpak_mark16_2 = mark2; + scpak_mark16_3 - mark3; + } else { + // Error! + assert(!"scpak_set_16bit_params - invalid parameter."); + } +} + +int scpak_pack_8b(int size, unsigned const char* src, unsigned char* dest) { + int s; + int d = 0; + short count = 0; + unsigned char prev; + + if(size < 1) return 0; + + prev = src[0]; + + for(s = 1; s < size; s++) { + if(src[s] == prev && count < 255) { + count++; + } else { + if(count <= 1 && (prev < scpak_mark8_1 || prev > scpak_mark8_3)) { + if(count == 0) { + dest[d] = prev; + d++; + } else { + dest[d] = prev; + dest[d+1] = prev; + d+=2; + } + } else { + if(prev == 0) { + dest[d] = scpak_mark8_3; + dest[d+1] = (unsigned char)count; + d+=2; + } else { + if(count <= 15 && prev <=15) { + dest[d] = scpak_mark8_2; + dest[d+1] = prev | (count << 4); + d+=2; + } else { + dest[d] = scpak_mark8_1; + dest[d+1] = prev; + dest[d+2] = (unsigned char)count; + d+=3; + } + } + } + count = 0; + prev = src[s]; + if(d >= size - 3) break; + } + } + if(count <= 1 && (prev < scpak_mark8_1 || prev > scpak_mark8_3)) { + if(count == 0) { + dest[d] = prev; + d++; + } else { + dest[d] = prev; + dest[d+1] = prev; + d+=2; + } + } else { + if(prev == 0) { + dest[d] = scpak_mark8_3; + dest[d+1] = (unsigned char)count; + d+=2; + } else { + if(count <= 15 && prev <= 15) { + dest[d] = scpak_mark8_2; + dest[d+1] = prev | (count << 4); + d+=2; + } else { + dest[d] = scpak_mark8_1; + dest[d+1] = prev; + dest[d+2] = (unsigned char) count; + d+=3; + } + } + } + if(d > size - 3) return 0; + + return d; +} + +int scpak_unpack_8b(int size, unsigned const char* src, unsigned char* dest, int maxDestSize) { + int s; + int d = 0; + short count = 0; + unsigned char rep; + + if(size < 1) return 0; + + if(maxDestSize == 0) + maxDestSize = 0x7fffffff - 256; // Should really be INT_MAX - 256. (This ok for 32 bit.) + + for(s = 0; s < size; s++) { + rep = src[s]; + if(rep < scpak_mark8_1 || rep > scpak_mark8_3) { + if(d >= maxDestSize) { + return 0; + } + dest[d] = rep; + d++; + } else { + if(rep == scpak_mark8_1) { + rep = src[s+1]; + count = src[s+2]; + s+=2; + } else { + if(rep == scpak_mark8_3) { + rep = 0; + count = src[s+1]; + s++; + } else { + rep = src[s+1] & 15; + count = src[s+1] >> 4; + s++; + } + } + if(d + count + 1 > maxDestSize) { + /*count = maxDestSize - d - 1; + for( ; count >= 0; count--) { + dest[d] = rep; + d++; + } + assert(d == maxDestSize); + break;*/ + return 0; + } + for( ; count >= 0; count--) { + dest[d] = rep; + d++; + } + } + } + return d; +} + +int scpak_pack_16b(int size, unsigned const short* src, unsigned short* dest) { + int s; + int d = 0; + short count = 0; + unsigned short prev; + + if(size < 1) return 0; + + size = ((size+1) >> 1); + prev = src[0]; + + for(s = 1; s < size; s++) { + if(src[s] == prev && count < 255) { + count++; + } else { + if(count <= 1 && (prev < scpak_mark16_1 || prev > scpak_mark16_3)) { + if(count == 0) { + dest[d] = prev; + d++; + } else { + dest[d] = prev; + dest[d+1] = prev; + d+=2; + } + } else { + if(prev == 0) { + dest[d] = scpak_mark16_3; + dest[d+1] = count; + d+=2; + } else { + if(count <= 255 && prev <= 255) { + dest[d] = scpak_mark16_2; + dest[d+1] = prev | (count << 8); + d+=2; + } else { + dest[d] = scpak_mark16_1; + dest[d+1] = prev; + dest[d+2] = count; + d+=3; + } + } + } + count = 0; + prev = src[s]; + if(d >= size-3) break; + } + } + if(count <= 1 && (prev < scpak_mark16_1 || prev > scpak_mark16_3)) { + if(count == 0) { + dest[d] = prev; + d++; + } else { + dest[d] = prev; + dest[d+1] = prev; + d+=2; + } + } else { + if(prev == 0) { + dest[d] = scpak_mark16_3; + dest[d+1] = count; + d+=2; + } else { + if(count <= 255 && prev <= 255) { + dest[d] = scpak_mark16_2; + dest[d+1] = prev | (count << 8); + d+=2; + } else { + dest[d] = scpak_mark16_1; + dest[d+1] = prev; + dest[d+2] = count; + d+=3; + } + } + } + if(d > size-3) return 0; + + return d*2; +} + +int scpak_unpack_16b(int size, unsigned const short* src, unsigned short* dest, int maxDestSize) { + int s; + int d = 0; + short count = 0; + unsigned short rep; + + if(size < 1) return 0; + + assert((maxDestSize & 1) == 0); + + maxDestSize = (maxDestSize >> 1); + if(maxDestSize == 0) + maxDestSize = 0x7fffffff - 256; // This should be INT_MAX - 256. (This is ok for 32 bit.) + + size = ((size+1) >> 1); + + for(s = 0; s < size; s++) { + rep = src[s]; + if(rep < scpak_mark16_1 || rep > scpak_mark16_3) { + if(d > maxDestSize) { + return 0; + } + dest[d] = rep; + d++; + } else { + if(rep == scpak_mark16_1) { + rep = src[s+1]; + count = src[s+2]; + s+=2; + } else { + if(rep == scpak_mark16_3) { + rep = 0; + count = src[s+1]; + s++; + } + } + if(d + count + 1 > maxDestSize) { + return 0; + } + for( ; count >= 0; count--) { + dest[d] = rep; + d++; + } + } + } + return d*2; +} + +int scpak_pack(int size, unsigned const char* src, unsigned char* dest) { + if(scpak_bits == 8) { + return scpak_pack_8b(size, src, dest); + } else { + if(scpak_bits == 16) + return scpak_pack_16b(size, (unsigned const short*)src, (unsigned short*)dest); + } + return 0; +} + +int scpak_unpack(int size, unsigned const char* src, unsigned char* dest, int maxDestSize) { + if(scpak_bits == 8) { + return scpak_unpack_8b(size, src, dest, maxDestSize); + } else { + if(scpak_bits == 16) + return scpak_unpack_16b(size, (unsigned const short*)src, (unsigned short*)dest, maxDestSize); + } + return 0; +} + diff --git a/src/System/Filesystem/SCpak.h b/src/System/Filesystem/SCpak.h new file mode 100644 index 0000000..4d05cff --- /dev/null +++ b/src/System/Filesystem/SCpak.h @@ -0,0 +1,23 @@ +#pragma once + +// Size reflects the size of the unpacked source buffer. Destination should be +// slightly over allocated to be save. There is no predefined rule for the destination +// buffer over allocation, +16 bytes will be nice ;) +// +// If using 16 bit packing, buffer sizes must be padded to 2 byte size (pas source with zeroes!) +// returns 0 if packed data would have been larger than source, in which case you need to handle it +// differently.. +extern int scpak_pack(int size, unsigned const char* src, unsigned char* dest); + +// Size reflects the size of the unpacked source buffer, destination buffer should be large +// enough to fin the unpacked data (size of unpacked data should be written in the +// packfile or somewhere...) maxDestSize gives the maximum allowed size for unpacked data +// or if 0, no limit (could cause a buffer overflow...) +extern int scpak_unpack(int size, unsigned const char* src, unsigned char* dest, int maxDestSize = 0); + +// 8 or 16 bit supported. +extern void scpak_set_bits(unsigned char bits); + +extern void scpak_set_8bit_params(unsigned char mark1, unsigned char mark2, unsigned char mark3); +extern void scpak_set_16bit_params(unsigned short mark1, unsigned short mark2, unsigned short mark3); +