From 1ecdd9f980a842af9ad5702330b35e9f6a432e90 Mon Sep 17 00:00:00 2001 From: Jonas Kulla Date: Wed, 23 Jul 2014 22:57:39 +0200 Subject: [PATCH] filesystem.cpp: Split out RGSSAD parts --- CMakeLists.txt | 2 + mkxp.pro | 6 +- src/filesystem.cpp | 465 +----------------------------------------- src/rgssad.cpp | 488 +++++++++++++++++++++++++++++++++++++++++++++ src/rgssad.h | 29 +++ 5 files changed, 524 insertions(+), 466 deletions(-) create mode 100644 src/rgssad.cpp create mode 100644 src/rgssad.h diff --git a/CMakeLists.txt b/CMakeLists.txt index bdd6c29..959eafb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -139,6 +139,7 @@ set(MAIN_HEADERS src/aldatasource.h src/alstream.h src/audiostream.h + src/rgssad.h ) set(MAIN_SOURCE @@ -174,6 +175,7 @@ set(MAIN_SOURCE src/sdlsoundsource.cpp src/alstream.cpp src/audiostream.cpp + src/rgssad.cpp ) source_group("MKXP Source" FILES ${MAIN_SOURCE} ${MAIN_HEADERS}) diff --git a/mkxp.pro b/mkxp.pro index 41f1587..7a87626 100644 --- a/mkxp.pro +++ b/mkxp.pro @@ -130,7 +130,8 @@ HEADERS += \ src/soundemitter.h \ src/aldatasource.h \ src/alstream.h \ - src/audiostream.h + src/audiostream.h \ + src/rgssad.h SOURCES += \ src/main.cpp \ @@ -164,7 +165,8 @@ SOURCES += \ src/soundemitter.cpp \ src/sdlsoundsource.cpp \ src/alstream.cpp \ - src/audiostream.cpp + src/audiostream.cpp \ + src/rgssad.cpp EMBED = \ shader/transSimple.frag \ diff --git a/src/filesystem.cpp b/src/filesystem.cpp index 73061c3..e78805f 100644 --- a/src/filesystem.cpp +++ b/src/filesystem.cpp @@ -21,6 +21,7 @@ #include "filesystem.h" +#include "rgssad.h" #include "font.h" #include "util.h" #include "exception.h" @@ -36,470 +37,6 @@ #include #include -struct RGSS_entryData -{ - int64_t offset; - uint64_t size; - uint32_t startMagic; -}; - -struct RGSS_entryHandle -{ - RGSS_entryData data; - uint32_t currentMagic; - uint64_t currentOffset; - PHYSFS_Io *io; - - RGSS_entryHandle(const RGSS_entryData &data, PHYSFS_Io *archIo) - : data(data), - currentMagic(data.startMagic), - currentOffset(0) - { - io = archIo->duplicate(archIo); - } - - ~RGSS_entryHandle() - { - io->destroy(io); - } -}; - -struct RGSS_archiveData -{ - PHYSFS_Io *archiveIo; - - /* Maps: file path - * to: entry data */ - BoostHash entryHash; - - /* Maps: directory path, - * to: list of contained entries */ - BoostHash > dirHash; -}; - -static bool -readUint32(PHYSFS_Io *io, uint32_t &result) -{ - char buff[4]; - PHYSFS_sint64 count = io->read(io, buff, 4); - - result = ((buff[0] << 0x00) & 0x000000FF) | - ((buff[1] << 0x08) & 0x0000FF00) | - ((buff[2] << 0x10) & 0x00FF0000) | - ((buff[3] << 0x18) & 0xFF000000) ; - - return (count == 4); -} - -#define RGSS_HEADER_1 0x53534752 -#define RGSS_HEADER_2 0x01004441 - -#define RGSS_MAGIC 0xDEADCAFE - -#define PHYSFS_ALLOC(type) \ - static_cast(PHYSFS_getAllocator()->Malloc(sizeof(type))) - -static inline uint32_t -advanceMagic(uint32_t &magic) -{ - uint32_t old = magic; - - magic = magic * 7 + 3; - - return old; -} - -static PHYSFS_sint64 -RGSS_ioRead(PHYSFS_Io *self, void *buffer, PHYSFS_uint64 len) -{ - RGSS_entryHandle *entry = static_cast(self->opaque); - - PHYSFS_Io *io = entry->io; - - uint64_t toRead = std::min(entry->data.size - entry->currentOffset, len); - uint64_t offs = entry->currentOffset; - - io->seek(io, entry->data.offset + offs); - - /* We divide up the bytes to be read in 3 categories: - * - * preAlign: If the current read address is not dword - * aligned, this is the number of bytes to read til - * we reach alignment again (therefore can only be - * 3 or less). - * - * align: The number of aligned dwords we can read - * times 4 (= number of bytes). - * - * postAlign: The number of bytes to read after the - * last aligned dword. Always 3 or less. - * - * Treating the pre- and post aligned reads specially, - * we can read all aligned dwords in one syscall directly - * into the write buffer and then run the xor chain on - * it afterwards. */ - - uint8_t preAlign = 4 - (offs % 4); - - if (preAlign == 4) - preAlign = 0; - else - preAlign = std::min(preAlign, len); - - uint8_t postAlign = (len > preAlign) ? (offs + len) % 4 : 0; - - uint64_t align = len - (preAlign + postAlign); - - /* Byte buffer pointer */ - uint8_t *bBufferP = static_cast(buffer); - - if (preAlign > 0) - { - uint32_t dword; - io->read(io, &dword, preAlign); - - /* Need to align the bytes with the - * magic before xoring */ - dword <<= 8 * (offs % 4); - dword ^= entry->currentMagic; - - /* Shift them back to normal */ - dword >>= 8 * (offs % 4); - memcpy(bBufferP, &dword, preAlign); - - bBufferP += preAlign; - - /* Only advance the magic if we actually - * reached the next alignment */ - if ((offs+preAlign) % 4 == 0) - advanceMagic(entry->currentMagic); - } - - if (align > 0) - { - /* Double word buffer pointer */ - uint32_t *dwBufferP = reinterpret_cast(bBufferP); - - /* Read aligned dwords in one go */ - io->read(io, bBufferP, align); - - /* Then xor them */ - for (uint64_t i = 0; i < (align / 4); ++i) - dwBufferP[i] ^= advanceMagic(entry->currentMagic); - - bBufferP += align; - } - - if (postAlign > 0) - { - uint32_t dword; - io->read(io, &dword, postAlign); - - /* Bytes are already aligned with magic */ - dword ^= entry->currentMagic; - memcpy(bBufferP, &dword, postAlign); - } - - entry->currentOffset += toRead; - - return toRead; -} - -static int -RGSS_ioSeek(PHYSFS_Io *self, PHYSFS_uint64 offset) -{ - RGSS_entryHandle *entry = static_cast(self->opaque); - - if (offset == entry->currentOffset) - return 1; - - if (offset > entry->data.size-1) - return 0; - - /* If rewinding, we need to rewind to begining */ - if (offset < entry->currentOffset) - { - entry->currentOffset = 0; - entry->currentMagic = entry->data.startMagic; - } - - /* For each overstepped alignment, advance magic */ - uint64_t currentDword = entry->currentOffset / 4; - uint64_t targetDword = offset / 4; - uint64_t dwordsSought = targetDword - currentDword; - - for (uint64_t i = 0; i < dwordsSought; ++i) - advanceMagic(entry->currentMagic); - - entry->currentOffset = offset; - entry->io->seek(entry->io, entry->data.offset + entry->currentOffset); - - return 1; -} - -static PHYSFS_sint64 -RGSS_ioTell(PHYSFS_Io *self) -{ - RGSS_entryHandle *entry = static_cast(self->opaque); - - return entry->currentOffset; -} - -static PHYSFS_sint64 -RGSS_ioLength(PHYSFS_Io *self) -{ - RGSS_entryHandle *entry = static_cast(self->opaque); - - return entry->data.size; -} - -static PHYSFS_Io* -RGSS_ioDuplicate(PHYSFS_Io *self) -{ - RGSS_entryHandle *entry = static_cast(self->opaque); - RGSS_entryHandle *entryDup = new RGSS_entryHandle(*entry); - - PHYSFS_Io *dup = PHYSFS_ALLOC(PHYSFS_Io); - *dup = *self; - dup->opaque = entryDup; - - return dup; -} - -static void -RGSS_ioDestroy(PHYSFS_Io *self) -{ - RGSS_entryHandle *entry = static_cast(self->opaque); - - delete entry; - - PHYSFS_getAllocator()->Free(self); -} - -static const PHYSFS_Io RGSS_IoTemplate = -{ - 0, /* version */ - 0, /* opaque */ - RGSS_ioRead, - 0, /* write */ - RGSS_ioSeek, - RGSS_ioTell, - RGSS_ioLength, - RGSS_ioDuplicate, - 0, /* flush */ - RGSS_ioDestroy -}; - -static void* -RGSS_openArchive(PHYSFS_Io *io, const char *, int forWrite) -{ - if (forWrite) - return 0; - - /* Check header */ - uint32_t header1, header2; - - if (!readUint32(io, header1)) - return 0; - - if (!readUint32(io, header2)) - return 0; - - if (header1 != RGSS_HEADER_1 || header2 != RGSS_HEADER_2) - return 0; - - RGSS_archiveData *data = new RGSS_archiveData; - data->archiveIo = io; - - uint32_t magic = RGSS_MAGIC; - - /* Top level entry list */ - BoostSet &topLevel = data->dirHash[""]; - - while (true) - { - /* Read filename length, - * if nothing was read, no files remain */ - uint32_t nameLen; - - if (!readUint32(io, nameLen)) - break; - - nameLen ^= advanceMagic(magic); - - static char nameBuf[512]; - uint32_t i; - for (i = 0; i < nameLen; ++i) - { - char c; - io->read(io, &c, 1); - nameBuf[i] = c ^ (advanceMagic(magic) & 0xFF); - if (nameBuf[i] == '\\') - nameBuf[i] = '/'; - } - nameBuf[i] = 0; - - uint32_t entrySize; - readUint32(io, entrySize); - entrySize ^= advanceMagic(magic); - - RGSS_entryData entry; - entry.offset = io->tell(io); - entry.size = entrySize; - entry.startMagic = magic; - - data->entryHash.insert(nameBuf, entry); - - /* Check for top level entries */ - for (i = 0; i < nameLen; ++i) - { - bool slash = nameBuf[i] == '/'; - if (!slash && i+1 < nameLen) - continue; - - if (slash) - nameBuf[i] = '\0'; - - topLevel.insert(nameBuf); - - if (slash) - nameBuf[i] = '/'; - } - - /* Check for more entries */ - for (i = nameLen; i > 0; i--) - if (nameBuf[i] == '/') - { - nameBuf[i] = '\0'; - - const char *dir = nameBuf; - const char *entry = &nameBuf[i+1]; - - BoostSet &entryList = data->dirHash[dir]; - entryList.insert(entry); - } - - io->seek(io, entry.offset + entry.size); - } - - return data; -} - -static void -RGSS_enumerateFiles(void *opaque, const char *dirname, - PHYSFS_EnumFilesCallback cb, - const char *origdir, void *callbackdata) -{ - RGSS_archiveData *data = static_cast(opaque); - - std::string _dirname(dirname); - - if (!data->dirHash.contains(_dirname)) - return; - - const BoostSet &entries = data->dirHash[_dirname]; - - BoostSet::const_iterator iter; - for (iter = entries.cbegin(); iter != entries.cend(); ++iter) - cb(callbackdata, origdir, iter->c_str()); -} - -static PHYSFS_Io* -RGSS_openRead(void *opaque, const char *filename) -{ - RGSS_archiveData *data = static_cast(opaque); - - if (!data->entryHash.contains(filename)) - return 0; - - RGSS_entryHandle *entry = - new RGSS_entryHandle(data->entryHash[filename], data->archiveIo); - - PHYSFS_Io *io = PHYSFS_ALLOC(PHYSFS_Io); - - *io = RGSS_IoTemplate; - io->opaque = entry; - - return io; -} - -static int -RGSS_stat(void *opaque, const char *filename, PHYSFS_Stat *stat) -{ - RGSS_archiveData *data = static_cast(opaque); - - bool hasFile = data->entryHash.contains(filename); - bool hasDir = data->dirHash.contains(filename); - - if (!hasFile && !hasDir) - { - PHYSFS_setErrorCode(PHYSFS_ERR_NOT_FOUND); - return 0; - } - - stat->modtime = - stat->createtime = - stat->accesstime = 0; - stat->readonly = 1; - - if (hasFile) - { - RGSS_entryData &entry = data->entryHash[filename]; - - stat->filesize = entry.size; - stat->filetype = PHYSFS_FILETYPE_REGULAR; - } - else - { - stat->filesize = 0; - stat->filetype = PHYSFS_FILETYPE_DIRECTORY; - } - - return 1; -} - -static void -RGSS_closeArchive(void *opaque) -{ - RGSS_archiveData *data = static_cast(opaque); - - delete data; -} - -static PHYSFS_Io* -RGSS_noop1(void*, const char*) -{ - return 0; -} - -static int -RGSS_noop2(void*, const char*) -{ - return 0; -} - -static const PHYSFS_Archiver RGSS_Archiver = -{ - 0, - { - "RGSSAD", - "RGSS encrypted archive format", - "Jonas Kulla ", - "http://k-du.de/rgss/rgss.html", - 0 /* symlinks not supported */ - }, - RGSS_openArchive, - RGSS_enumerateFiles, - RGSS_openRead, - RGSS_noop1, /* openWrite */ - RGSS_noop1, /* openAppend */ - RGSS_noop2, /* remove */ - RGSS_noop2, /* mkdir */ - RGSS_stat, - RGSS_closeArchive -}; - - static inline PHYSFS_File *sdlPHYS(SDL_RWops *ops) { return static_cast(ops->hidden.unknown.data1); diff --git a/src/rgssad.cpp b/src/rgssad.cpp new file mode 100644 index 0000000..dd94f51 --- /dev/null +++ b/src/rgssad.cpp @@ -0,0 +1,488 @@ +/* +** rgssad.cpp +** +** This file is part of mkxp. +** +** Copyright (C) 2014 Jonas Kulla +** +** mkxp 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, either version 2 of the License, or +** (at your option) any later version. +** +** mkxp 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 for more details. +** +** You should have received a copy of the GNU General Public License +** along with mkxp. If not, see . +*/ + +#include "rgssad.h" +#include "boost-hash.h" + +#include + +struct RGSS_entryData +{ + int64_t offset; + uint64_t size; + uint32_t startMagic; +}; + +struct RGSS_entryHandle +{ + RGSS_entryData data; + uint32_t currentMagic; + uint64_t currentOffset; + PHYSFS_Io *io; + + RGSS_entryHandle(const RGSS_entryData &data, PHYSFS_Io *archIo) + : data(data), + currentMagic(data.startMagic), + currentOffset(0) + { + io = archIo->duplicate(archIo); + } + + ~RGSS_entryHandle() + { + io->destroy(io); + } +}; + +struct RGSS_archiveData +{ + PHYSFS_Io *archiveIo; + + /* Maps: file path + * to: entry data */ + BoostHash entryHash; + + /* Maps: directory path, + * to: list of contained entries */ + BoostHash > dirHash; +}; + +static bool +readUint32(PHYSFS_Io *io, uint32_t &result) +{ + char buff[4]; + PHYSFS_sint64 count = io->read(io, buff, 4); + + result = ((buff[0] << 0x00) & 0x000000FF) | + ((buff[1] << 0x08) & 0x0000FF00) | + ((buff[2] << 0x10) & 0x00FF0000) | + ((buff[3] << 0x18) & 0xFF000000) ; + + return (count == 4); +} + +#define RGSS_HEADER_1 0x53534752 +#define RGSS_HEADER_2 0x01004441 + +#define RGSS_MAGIC 0xDEADCAFE + +#define PHYSFS_ALLOC(type) \ + static_cast(PHYSFS_getAllocator()->Malloc(sizeof(type))) + +static inline uint32_t +advanceMagic(uint32_t &magic) +{ + uint32_t old = magic; + + magic = magic * 7 + 3; + + return old; +} + +static PHYSFS_sint64 +RGSS_ioRead(PHYSFS_Io *self, void *buffer, PHYSFS_uint64 len) +{ + RGSS_entryHandle *entry = static_cast(self->opaque); + + PHYSFS_Io *io = entry->io; + + uint64_t toRead = std::min(entry->data.size - entry->currentOffset, len); + uint64_t offs = entry->currentOffset; + + io->seek(io, entry->data.offset + offs); + + /* We divide up the bytes to be read in 3 categories: + * + * preAlign: If the current read address is not dword + * aligned, this is the number of bytes to read til + * we reach alignment again (therefore can only be + * 3 or less). + * + * align: The number of aligned dwords we can read + * times 4 (= number of bytes). + * + * postAlign: The number of bytes to read after the + * last aligned dword. Always 3 or less. + * + * Treating the pre- and post aligned reads specially, + * we can read all aligned dwords in one syscall directly + * into the write buffer and then run the xor chain on + * it afterwards. */ + + uint8_t preAlign = 4 - (offs % 4); + + if (preAlign == 4) + preAlign = 0; + else + preAlign = std::min(preAlign, len); + + uint8_t postAlign = (len > preAlign) ? (offs + len) % 4 : 0; + + uint64_t align = len - (preAlign + postAlign); + + /* Byte buffer pointer */ + uint8_t *bBufferP = static_cast(buffer); + + if (preAlign > 0) + { + uint32_t dword; + io->read(io, &dword, preAlign); + + /* Need to align the bytes with the + * magic before xoring */ + dword <<= 8 * (offs % 4); + dword ^= entry->currentMagic; + + /* Shift them back to normal */ + dword >>= 8 * (offs % 4); + memcpy(bBufferP, &dword, preAlign); + + bBufferP += preAlign; + + /* Only advance the magic if we actually + * reached the next alignment */ + if ((offs+preAlign) % 4 == 0) + advanceMagic(entry->currentMagic); + } + + if (align > 0) + { + /* Double word buffer pointer */ + uint32_t *dwBufferP = reinterpret_cast(bBufferP); + + /* Read aligned dwords in one go */ + io->read(io, bBufferP, align); + + /* Then xor them */ + for (uint64_t i = 0; i < (align / 4); ++i) + dwBufferP[i] ^= advanceMagic(entry->currentMagic); + + bBufferP += align; + } + + if (postAlign > 0) + { + uint32_t dword; + io->read(io, &dword, postAlign); + + /* Bytes are already aligned with magic */ + dword ^= entry->currentMagic; + memcpy(bBufferP, &dword, postAlign); + } + + entry->currentOffset += toRead; + + return toRead; +} + +static int +RGSS_ioSeek(PHYSFS_Io *self, PHYSFS_uint64 offset) +{ + RGSS_entryHandle *entry = static_cast(self->opaque); + + if (offset == entry->currentOffset) + return 1; + + if (offset > entry->data.size-1) + return 0; + + /* If rewinding, we need to rewind to begining */ + if (offset < entry->currentOffset) + { + entry->currentOffset = 0; + entry->currentMagic = entry->data.startMagic; + } + + /* For each overstepped alignment, advance magic */ + uint64_t currentDword = entry->currentOffset / 4; + uint64_t targetDword = offset / 4; + uint64_t dwordsSought = targetDword - currentDword; + + for (uint64_t i = 0; i < dwordsSought; ++i) + advanceMagic(entry->currentMagic); + + entry->currentOffset = offset; + entry->io->seek(entry->io, entry->data.offset + entry->currentOffset); + + return 1; +} + +static PHYSFS_sint64 +RGSS_ioTell(PHYSFS_Io *self) +{ + RGSS_entryHandle *entry = static_cast(self->opaque); + + return entry->currentOffset; +} + +static PHYSFS_sint64 +RGSS_ioLength(PHYSFS_Io *self) +{ + RGSS_entryHandle *entry = static_cast(self->opaque); + + return entry->data.size; +} + +static PHYSFS_Io* +RGSS_ioDuplicate(PHYSFS_Io *self) +{ + RGSS_entryHandle *entry = static_cast(self->opaque); + RGSS_entryHandle *entryDup = new RGSS_entryHandle(*entry); + + PHYSFS_Io *dup = PHYSFS_ALLOC(PHYSFS_Io); + *dup = *self; + dup->opaque = entryDup; + + return dup; +} + +static void +RGSS_ioDestroy(PHYSFS_Io *self) +{ + RGSS_entryHandle *entry = static_cast(self->opaque); + + delete entry; + + PHYSFS_getAllocator()->Free(self); +} + +static const PHYSFS_Io RGSS_IoTemplate = +{ + 0, /* version */ + 0, /* opaque */ + RGSS_ioRead, + 0, /* write */ + RGSS_ioSeek, + RGSS_ioTell, + RGSS_ioLength, + RGSS_ioDuplicate, + 0, /* flush */ + RGSS_ioDestroy +}; + +static void* +RGSS_openArchive(PHYSFS_Io *io, const char *, int forWrite) +{ + if (forWrite) + return 0; + + /* Check header */ + uint32_t header1, header2; + + if (!readUint32(io, header1)) + return 0; + + if (!readUint32(io, header2)) + return 0; + + if (header1 != RGSS_HEADER_1 || header2 != RGSS_HEADER_2) + return 0; + + RGSS_archiveData *data = new RGSS_archiveData; + data->archiveIo = io; + + uint32_t magic = RGSS_MAGIC; + + /* Top level entry list */ + BoostSet &topLevel = data->dirHash[""]; + + while (true) + { + /* Read filename length, + * if nothing was read, no files remain */ + uint32_t nameLen; + + if (!readUint32(io, nameLen)) + break; + + nameLen ^= advanceMagic(magic); + + static char nameBuf[512]; + uint32_t i; + for (i = 0; i < nameLen; ++i) + { + char c; + io->read(io, &c, 1); + nameBuf[i] = c ^ (advanceMagic(magic) & 0xFF); + if (nameBuf[i] == '\\') + nameBuf[i] = '/'; + } + nameBuf[i] = 0; + + uint32_t entrySize; + readUint32(io, entrySize); + entrySize ^= advanceMagic(magic); + + RGSS_entryData entry; + entry.offset = io->tell(io); + entry.size = entrySize; + entry.startMagic = magic; + + data->entryHash.insert(nameBuf, entry); + + /* Check for top level entries */ + for (i = 0; i < nameLen; ++i) + { + bool slash = nameBuf[i] == '/'; + if (!slash && i+1 < nameLen) + continue; + + if (slash) + nameBuf[i] = '\0'; + + topLevel.insert(nameBuf); + + if (slash) + nameBuf[i] = '/'; + } + + /* Check for more entries */ + for (i = nameLen; i > 0; i--) + if (nameBuf[i] == '/') + { + nameBuf[i] = '\0'; + + const char *dir = nameBuf; + const char *entry = &nameBuf[i+1]; + + BoostSet &entryList = data->dirHash[dir]; + entryList.insert(entry); + } + + io->seek(io, entry.offset + entry.size); + } + + return data; +} + +static void +RGSS_enumerateFiles(void *opaque, const char *dirname, + PHYSFS_EnumFilesCallback cb, + const char *origdir, void *callbackdata) +{ + RGSS_archiveData *data = static_cast(opaque); + + std::string _dirname(dirname); + + if (!data->dirHash.contains(_dirname)) + return; + + const BoostSet &entries = data->dirHash[_dirname]; + + BoostSet::const_iterator iter; + for (iter = entries.cbegin(); iter != entries.cend(); ++iter) + cb(callbackdata, origdir, iter->c_str()); +} + +static PHYSFS_Io* +RGSS_openRead(void *opaque, const char *filename) +{ + RGSS_archiveData *data = static_cast(opaque); + + if (!data->entryHash.contains(filename)) + return 0; + + RGSS_entryHandle *entry = + new RGSS_entryHandle(data->entryHash[filename], data->archiveIo); + + PHYSFS_Io *io = PHYSFS_ALLOC(PHYSFS_Io); + + *io = RGSS_IoTemplate; + io->opaque = entry; + + return io; +} + +static int +RGSS_stat(void *opaque, const char *filename, PHYSFS_Stat *stat) +{ + RGSS_archiveData *data = static_cast(opaque); + + bool hasFile = data->entryHash.contains(filename); + bool hasDir = data->dirHash.contains(filename); + + if (!hasFile && !hasDir) + { + PHYSFS_setErrorCode(PHYSFS_ERR_NOT_FOUND); + return 0; + } + + stat->modtime = + stat->createtime = + stat->accesstime = 0; + stat->readonly = 1; + + if (hasFile) + { + RGSS_entryData &entry = data->entryHash[filename]; + + stat->filesize = entry.size; + stat->filetype = PHYSFS_FILETYPE_REGULAR; + } + else + { + stat->filesize = 0; + stat->filetype = PHYSFS_FILETYPE_DIRECTORY; + } + + return 1; +} + +static void +RGSS_closeArchive(void *opaque) +{ + RGSS_archiveData *data = static_cast(opaque); + + delete data; +} + +static PHYSFS_Io* +RGSS_noop1(void*, const char*) +{ + return 0; +} + +static int +RGSS_noop2(void*, const char*) +{ + return 0; +} + +const PHYSFS_Archiver RGSS_Archiver = +{ + 0, + { + "RGSSAD", + "RGSS encrypted archive format", + "Jonas Kulla ", + "http://k-du.de/rgss/rgss.html", + 0 /* symlinks not supported */ + }, + RGSS_openArchive, + RGSS_enumerateFiles, + RGSS_openRead, + RGSS_noop1, /* openWrite */ + RGSS_noop1, /* openAppend */ + RGSS_noop2, /* remove */ + RGSS_noop2, /* mkdir */ + RGSS_stat, + RGSS_closeArchive +}; diff --git a/src/rgssad.h b/src/rgssad.h new file mode 100644 index 0000000..b93eba6 --- /dev/null +++ b/src/rgssad.h @@ -0,0 +1,29 @@ +/* +** rgssad.h +** +** This file is part of mkxp. +** +** Copyright (C) 2014 Jonas Kulla +** +** mkxp 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, either version 2 of the License, or +** (at your option) any later version. +** +** mkxp 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 for more details. +** +** You should have received a copy of the GNU General Public License +** along with mkxp. If not, see . +*/ + +#ifndef RGSSAD_H +#define RGSSAD_H + +#include + +extern const PHYSFS_Archiver RGSS_Archiver; + +#endif // RGSSAD_H