rockbox/apps/plugins/xworld/bank.c
Franklin Wei 33cb13dee5 Xworld - Another World interpreter for Rockbox
Co-conspirators: Franklin Wei, Benjamin Brown

--------------------------------------------------------------------
This work is based on:
- Fabien Sanglard's "Fabother World" based on
- Piotr Padkowski's newRaw interpreter which was based on
- Gregory Montoir's reverse engineering of
- Eric Chahi's assembly code

--------------------------------------------------------------------
Progress:

* The plugin runs pretty nicely (with sound!) on most color targets
* Keymaps for color LCD targets are complete
* The manual entry is finished
* Grayscale/monochrome support is NOT PLANNED
  - the game looks horrible in grayscale! :p

--------------------------------------------------------------------
Notes:

* The original game strings were built-in to the executable, and
  were copyrighted and could not be used.
* This port ships with an alternate set of strings by default, but
  can load the "official" strings from a file at runtime.

--------------------------------------------------------------------
To be done (in descending order of importance):

* vertical stride compatibility                          <30% done>
* optimization                                           <10% done>

Change-Id: I3155b0d97c2ac470cb8a2040f40d4139ddcebfa5
Reviewed-on: http://gerrit.rockbox.org/1077
Reviewed-by: Michael Giacomelli <giac2000@hotmail.com>
2014-12-23 23:48:12 +01:00

153 lines
4.6 KiB
C

/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2014 Franklin Wei, Benjamin Brown
* Copyright (C) 2004 Gregory Montoir
*
* 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; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
***************************************************************************/
#include "plugin.h"
#include "bank.h"
#include "file.h"
#include "resource.h"
void bank_create(struct Bank* b, const char *dataDir)
{
b->_dataDir = dataDir;
}
bool bank_read(struct Bank* b, const struct MemEntry *me, uint8_t *buf) {
bool ret = false;
char bankName[10];
rb->snprintf(bankName, 10, "bank%02x", me->bankId);
File f;
file_create(&f, false);
if (!file_open(&f, bankName, b->_dataDir, "rb"))
error("bank_read() unable to open '%s' in dir '%s'", bankName, b->_dataDir);
file_seek(&f, me->bankOffset);
/* Depending if the resource is packed or not we */
/* can read directly or unpack it. */
if (me->packedSize == me->size) {
file_read(&f, buf, me->packedSize);
ret = true;
} else {
file_read(&f, buf, me->packedSize);
b->_startBuf = buf;
b->_iBuf = buf + me->packedSize - 4;
ret = bank_unpack(b);
}
file_close(&f);
return ret;
}
void bank_decUnk1(struct Bank* b, uint8_t numChunks, uint8_t addCount) {
uint16_t count = bank_getCode(b, numChunks) + addCount + 1;
debug(DBG_BANK, "bank_decUnk1(%d, %d) count=%d", numChunks, addCount, count);
b->_unpCtx.datasize -= count;
while (count--) {
assert(b->_oBuf >= b->_iBuf && b->_oBuf >= b->_startBuf);
*b->_oBuf = (uint8_t)bank_getCode(b, 8);
--b->_oBuf;
}
}
/*
Note from fab: This look like run-length encoding.
*/
void bank_decUnk2(struct Bank* b, uint8_t numChunks) {
uint16_t i = bank_getCode(b, numChunks);
uint16_t count = b->_unpCtx.size + 1;
debug(DBG_BANK, "bank_decUnk2(%d) i=%d count=%d", numChunks, i, count);
b->_unpCtx.datasize -= count;
while (count--) {
assert(b->_oBuf >= b->_iBuf && b->_oBuf >= b->_startBuf);
*b->_oBuf = *(b->_oBuf + i);
--b->_oBuf;
}
}
/*
Most resource in the banks are compacted.
*/
bool bank_unpack(struct Bank* b) {
b->_unpCtx.size = 0;
b->_unpCtx.datasize = READ_BE_UINT32(b->_iBuf);
b->_iBuf -= 4;
b->_oBuf = b->_startBuf + b->_unpCtx.datasize - 1;
b->_unpCtx.crc = READ_BE_UINT32(b->_iBuf);
b->_iBuf -= 4;
b->_unpCtx.chk = READ_BE_UINT32(b->_iBuf);
b->_iBuf -= 4;
b->_unpCtx.crc ^= b->_unpCtx.chk;
do {
if (!bank_nextChunk(b)) {
b->_unpCtx.size = 1;
if (!bank_nextChunk(b)) {
bank_decUnk1(b, 3, 0);
} else {
bank_decUnk2(b, 8);
}
} else {
uint16_t c = bank_getCode(b, 2);
if (c == 3) {
bank_decUnk1(b, 8, 8);
} else {
if (c < 2) {
b->_unpCtx.size = c + 2;
bank_decUnk2(b, c + 9);
} else {
b->_unpCtx.size = bank_getCode(b, 8);
bank_decUnk2(b, 12);
}
}
}
} while (b->_unpCtx.datasize > 0);
return (b->_unpCtx.crc == 0);
}
uint16_t bank_getCode(struct Bank* b, uint8_t numChunks) {
uint16_t c = 0;
while (numChunks--) {
c <<= 1;
if (bank_nextChunk(b)) {
c |= 1;
}
}
return c;
}
bool bank_nextChunk(struct Bank* b) {
bool CF = bank_rcr(b, false);
if (b->_unpCtx.chk == 0) {
assert(b->_iBuf >= b->_startBuf);
b->_unpCtx.chk = READ_BE_UINT32(b->_iBuf);
b->_iBuf -= 4;
b->_unpCtx.crc ^= b->_unpCtx.chk;
CF = bank_rcr(b, true);
}
return CF;
}
bool bank_rcr(struct Bank* b, bool CF) {
bool rCF = (b->_unpCtx.chk & 1);
b->_unpCtx.chk >>= 1;
if (CF) b->_unpCtx.chk |= 0x80000000;
return rCF;
}