mirror of
https://github.com/d0k3/GodMode9.git
synced 2025-06-26 13:42:47 +00:00
add BEAT interactivity, fix typos and other small bugs
This commit is contained in:
parent
e4b98e0932
commit
ce9f0a25ef
@ -16,18 +16,31 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <libgen.h>
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include "timer.h"
|
||||||
#include "crc32.h"
|
#include "crc32.h"
|
||||||
#include "bps.h"
|
|
||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
#include "ui.h"
|
#include "ui.h"
|
||||||
|
|
||||||
#define BEAT_VLIBUFSZ (16)
|
#include "hid.h"
|
||||||
|
#include "bps.h"
|
||||||
|
|
||||||
|
#define BEAT_VLIBUFSZ (8)
|
||||||
#define BEAT_MAXPATH (256)
|
#define BEAT_MAXPATH (256)
|
||||||
#define BEAT_RANGESZ(c, i) ((c)->ranges[1][i] - (c)->ranges[0][i])
|
#define BEAT_FILEBUFSZ (256 * 1024)
|
||||||
|
|
||||||
|
#define BEAT_RANGE(c, i) ((c)->ranges[1][i] - (c)->ranges[0][i])
|
||||||
|
#define BEAT_UPDATEDELAYMS (1000 / 4)
|
||||||
|
|
||||||
|
#define BEAT_ABSPOS(c, i) ((c)->foff[i] + (c)->ranges[0][i])
|
||||||
|
|
||||||
#define BEAT_READONLY (FA_READ | FA_OPEN_EXISTING)
|
#define BEAT_READONLY (FA_READ | FA_OPEN_EXISTING)
|
||||||
#define BEAT_RWCREATE (FA_READ | FA_WRITE | FA_CREATE_NEW)
|
#define BEAT_RWCREATE (FA_READ | FA_WRITE | FA_CREATE_ALWAYS)
|
||||||
|
|
||||||
|
static u32 progress_refcnt = 0;
|
||||||
|
static u64 progress_timer = 0;
|
||||||
|
|
||||||
static size_t fs_size(const char *path)
|
static size_t fs_size(const char *path)
|
||||||
{
|
{
|
||||||
@ -37,6 +50,15 @@ static size_t fs_size(const char *path)
|
|||||||
return fno.fsize;
|
return fno.fsize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char *basepath(const char *path)
|
||||||
|
{
|
||||||
|
const char *ret = path + strlen(path);
|
||||||
|
while((--ret) > path) {
|
||||||
|
if (*ret == '/') break;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/* Possible error codes */
|
/* Possible error codes */
|
||||||
enum {
|
enum {
|
||||||
BEAT_OK = 0,
|
BEAT_OK = 0,
|
||||||
@ -69,23 +91,23 @@ enum {
|
|||||||
|
|
||||||
/* File handles used within the Beat state */
|
/* File handles used within the Beat state */
|
||||||
enum {
|
enum {
|
||||||
BEAT_PATCHFILE = 0,
|
BEAT_PF = 0, // patch file
|
||||||
BEAT_SRCFILE,
|
BEAT_IF, // input file
|
||||||
BEAT_DSTFILE,
|
BEAT_OF, // output file
|
||||||
BEAT_FILECOUNT,
|
BEAT_FILENUM,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const u8 bps_signature[] = { 'B', 'P', 'S', '1' };
|
static const u8 bps_signature[] = { 'B', 'P', 'S', '1' };
|
||||||
static const u8 bps_chksumoffs[BEAT_FILECOUNT] = {
|
static const u8 bps_chksumoffs[BEAT_FILENUM] = {
|
||||||
[BEAT_PATCHFILE] = 4, [BEAT_DSTFILE] = 8, [BEAT_SRCFILE] = 12,
|
[BEAT_PF] = 4, [BEAT_OF] = 8, [BEAT_IF] = 12,
|
||||||
};
|
};
|
||||||
static const u8 bpm_signature[] = { 'B', 'P', 'M', '1' };
|
static const u8 bpm_signature[] = { 'B', 'P', 'M', '1' };
|
||||||
|
|
||||||
/** BEAT STATE STORAGE */
|
/** BEAT STATE STORAGE */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
u8 *copybuf;
|
u8 *copybuf;
|
||||||
ssize_t foffset[BEAT_FILECOUNT], eoal_offset;
|
size_t foff[BEAT_FILENUM], eoal_offset;
|
||||||
size_t ranges[2][BEAT_FILECOUNT];
|
size_t ranges[2][BEAT_FILENUM];
|
||||||
u32 ocrc; // Output crc
|
u32 ocrc; // Output crc
|
||||||
|
|
||||||
union {
|
union {
|
||||||
@ -97,10 +119,26 @@ typedef struct {
|
|||||||
const char *bpm_path, *source_dir, *target_dir;
|
const char *bpm_path, *source_dir, *target_dir;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
FIL file[BEAT_FILECOUNT];
|
char processing[BEAT_MAXPATH];
|
||||||
|
FIL file[BEAT_FILENUM];
|
||||||
} BEAT_Context;
|
} BEAT_Context;
|
||||||
|
|
||||||
typedef int (*BEAT_Action)(BEAT_Context*, u64);
|
typedef int (*BEAT_Action)(BEAT_Context*, u32);
|
||||||
|
|
||||||
|
static bool BEAT_UpdateProgress(const BEAT_Context *ctx)
|
||||||
|
{ // only updates progress for the parent patch, so the embedded BPS wont be displayed
|
||||||
|
u64 tmr;
|
||||||
|
if (progress_refcnt > 2) bkpt; // nope, bug out
|
||||||
|
|
||||||
|
tmr = timer_msec(progress_timer);
|
||||||
|
if (CheckButton(BUTTON_B)) return false; // check for an abort situation
|
||||||
|
if (progress_refcnt != 1) return true; // only show the first level progress
|
||||||
|
if (tmr < BEAT_UPDATEDELAYMS) return true; // give it some time
|
||||||
|
|
||||||
|
progress_timer = timer_start();
|
||||||
|
ShowProgress(ctx->foff[BEAT_PF], BEAT_RANGE(ctx, BEAT_PF), ctx->processing);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static const char *BEAT_ErrString(int error)
|
static const char *BEAT_ErrString(int error)
|
||||||
{ // Get an error description string
|
{ // Get an error description string
|
||||||
@ -120,103 +158,94 @@ static const char *BEAT_ErrString(int error)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int BEAT_Read(BEAT_Context *ctx, int id, void *out, size_t len, bool advance)
|
static int BEAT_Read(BEAT_Context *ctx, int id, void *out, size_t len, int fwd)
|
||||||
{ // Read up to `len` bytes from the context file `id` to the `out` buffer
|
{ // Read up to `len` bytes from the context file `id` to the `out` buffer
|
||||||
FRESULT res;
|
|
||||||
UINT br;
|
UINT br;
|
||||||
len = min(len, BEAT_RANGESZ(ctx, id) - ctx->foffset[id]);
|
FRESULT res;
|
||||||
fvx_lseek(&ctx->file[id], ctx->ranges[0][id] + ctx->foffset[id]); // ALWAYS use the state offset + start range
|
if ((len + ctx->foff[id]) > BEAT_RANGE(ctx, id))
|
||||||
if (advance) ctx->foffset[id] += len;
|
return BEAT_OVERFLOW;
|
||||||
|
|
||||||
|
fvx_lseek(&ctx->file[id], BEAT_ABSPOS(ctx, id)); // ALWAYS use the state offset + start range
|
||||||
|
ctx->foff[id] += len * fwd;
|
||||||
res = fvx_read(&ctx->file[id], out, len, &br);
|
res = fvx_read(&ctx->file[id], out, len, &br);
|
||||||
return (res == FR_OK && br == len) ? BEAT_OK : BEAT_IO_ERROR;
|
return (res == FR_OK && br == len) ? BEAT_OK : BEAT_IO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int BEAT_WriteOut(BEAT_Context *ctx, const u8 *in, size_t len, bool advance)
|
static int BEAT_WriteOut(BEAT_Context *ctx, const u8 *in, size_t len, int fwd)
|
||||||
{ // Write `len` bytes from `in` to BEAT_DSTFILE, updates the output CRC
|
{ // Write `len` bytes from `in` to BEAT_OF, updates the output CRC
|
||||||
FRESULT res;
|
|
||||||
UINT bw;
|
UINT bw;
|
||||||
if ((len + ctx->foffset[BEAT_DSTFILE]) > BEAT_RANGESZ(ctx, BEAT_DSTFILE))
|
FRESULT res;
|
||||||
|
if ((len + ctx->foff[BEAT_OF]) > BEAT_RANGE(ctx, BEAT_OF))
|
||||||
return BEAT_OVERFLOW;
|
return BEAT_OVERFLOW;
|
||||||
|
|
||||||
// Blindly assume all writes will be done linearly
|
// Blindly assume all writes will be done linearly
|
||||||
ctx->ocrc = ~crc32_calculate(~ctx->ocrc, in, len);
|
ctx->ocrc = ~crc32_calculate(~ctx->ocrc, in, len);
|
||||||
fvx_lseek(&ctx->file[BEAT_DSTFILE], ctx->ranges[0][BEAT_DSTFILE] + ctx->foffset[BEAT_DSTFILE]);
|
fvx_lseek(&ctx->file[BEAT_OF], BEAT_ABSPOS(ctx, BEAT_OF));
|
||||||
if (advance) ctx->foffset[BEAT_DSTFILE] += len;
|
ctx->foff[BEAT_OF] += len * fwd;
|
||||||
res = fvx_write(&ctx->file[BEAT_DSTFILE], in, len, &bw);
|
res = fvx_write(&ctx->file[BEAT_OF], in, len, &bw);
|
||||||
return (res == FR_OK && bw == len) ? BEAT_OK : BEAT_IO_ERROR;
|
return (res == FR_OK && bw == len) ? BEAT_OK : BEAT_IO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void BEAT_SeekOff(BEAT_Context *ctx, int id, ssize_t offset)
|
static void BEAT_SeekOff(BEAT_Context *ctx, int id, ssize_t offset)
|
||||||
{ ctx->foffset[id] += offset; } // Seek `offset` bytes forward
|
{ ctx->foff[id] += offset; } // Seek `offset` bytes forward
|
||||||
static void BEAT_SeekAbs(BEAT_Context *ctx, int id, size_t pos)
|
static void BEAT_SeekAbs(BEAT_Context *ctx, int id, size_t pos)
|
||||||
{ ctx->foffset[id] = pos; } // Seek to absolute position `pos`
|
{ ctx->foff[id] = pos; } // Seek to absolute position `pos`
|
||||||
|
|
||||||
static int BEAT_NextVLI(BEAT_Context *ctx, u64 *vli)
|
static int BEAT_NextVLI(BEAT_Context *ctx, u32 *vli)
|
||||||
{ // Read the next VLI in the file, update the seek position
|
{ // Read the next VLI in the file, update the seek position
|
||||||
u8 vli_rdbuf[BEAT_VLIBUFSZ], *scan = vli_rdbuf;
|
|
||||||
u32 iter = 0;
|
|
||||||
u64 ret = 0;
|
|
||||||
int res;
|
int res;
|
||||||
|
u32 ret = 0;
|
||||||
|
u32 iter = 0;
|
||||||
|
u8 vli_rdbuf[BEAT_VLIBUFSZ], *scan = vli_rdbuf;
|
||||||
|
|
||||||
res = BEAT_Read(ctx, BEAT_PATCHFILE, vli_rdbuf, sizeof(vli_rdbuf), false);
|
res = BEAT_Read(ctx, BEAT_PF, vli_rdbuf, sizeof(vli_rdbuf), 0);
|
||||||
if (res != BEAT_OK) return res;
|
if (res != BEAT_OK) return res;
|
||||||
|
|
||||||
while(scan < &vli_rdbuf[sizeof(vli_rdbuf)]) {
|
while(scan < &vli_rdbuf[sizeof(vli_rdbuf)]) {
|
||||||
u64 val = *(scan++);
|
u32 val = *(scan++);
|
||||||
ret += (val & 0x7F) << iter;
|
ret += (val & 0x7F) << iter;
|
||||||
if (val & 0x80) break;
|
if (val & 0x80) break;
|
||||||
iter += 7;
|
iter += 7;
|
||||||
ret += (u64)(1ULL << iter);
|
ret += (u32)(1ULL << iter);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Seek forward only by the amount of used bytes
|
// Seek forward only by the amount of used bytes
|
||||||
BEAT_SeekOff(ctx, BEAT_PATCHFILE, scan - vli_rdbuf);
|
BEAT_SeekOff(ctx, BEAT_PF, scan - vli_rdbuf);
|
||||||
*vli = ret;
|
*vli = ret;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static s64 BEAT_DecodeSigned(u64 val) // Extract the signed number
|
static s32 BEAT_DecodeSigned(u32 val) // Extract the signed number
|
||||||
{ if (val&1) return -(val>>1); else return (val>>1); }
|
{ if (val&1) return -(val>>1); else return (val>>1); }
|
||||||
|
|
||||||
static int BEAT_NextAction(int *act, u64 *len, BEAT_Context *ctx)
|
|
||||||
{ // Decode next action word, retrieves state and length parameters
|
|
||||||
int res;
|
|
||||||
ssize_t end;
|
|
||||||
u64 val;
|
|
||||||
|
|
||||||
end = BEAT_RANGESZ(ctx, BEAT_PATCHFILE) - ctx->foffset[BEAT_PATCHFILE];
|
|
||||||
|
|
||||||
if (end == ctx->eoal_offset) return BEAT_EOAL;
|
|
||||||
if (end < ctx->eoal_offset) return BEAT_PATCH_EXPECT;
|
|
||||||
|
|
||||||
res = BEAT_NextVLI(ctx, &val);
|
|
||||||
*act = val & 3;
|
|
||||||
*len = (val >> 2) + 1;
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int BEAT_RunActions(BEAT_Context *ctx, const BEAT_Action *acts)
|
static int BEAT_RunActions(BEAT_Context *ctx, const BEAT_Action *acts)
|
||||||
{ // Parses an action list and runs commands specified in `acts`
|
{ // Parses an action list and runs commands specified in `acts`
|
||||||
int cmd;
|
u32 vli, len;
|
||||||
u64 len;
|
int cmd, res;
|
||||||
|
|
||||||
while(1) {
|
while((res == BEAT_OK) &&
|
||||||
int res = BEAT_NextAction(&cmd, &len, ctx);
|
(ctx->foff[BEAT_PF] < (BEAT_RANGE(ctx, BEAT_PF) - ctx->eoal_offset))) {
|
||||||
if (res == BEAT_EOAL) return BEAT_EOAL; // End of patch
|
res = BEAT_NextVLI(ctx, &vli); // get next action
|
||||||
if (res != BEAT_OK) return res; // Failed to get next action
|
cmd = vli & 3;
|
||||||
|
len = (vli >> 2) + 1;
|
||||||
|
if (res != BEAT_OK) return res;
|
||||||
|
|
||||||
|
if (!BEAT_UpdateProgress(ctx)) return BEAT_ABORTED;
|
||||||
|
|
||||||
res = (acts[cmd])(ctx, len); // Execute next action
|
res = (acts[cmd])(ctx, len); // Execute next action
|
||||||
if (res == BEAT_ABORTED) return BEAT_ABORTED; // Return on user abort
|
if (res != BEAT_OK) return res; // Break on error or user abort
|
||||||
if (res != BEAT_OK) return res; // Break on error
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void BEAT_ReleaseCTX(BEAT_Context *ctx)
|
static void BEAT_ReleaseCTX(BEAT_Context *ctx)
|
||||||
{ // Release any resources associated to the context
|
{ // Release any resources associated to the context
|
||||||
free(ctx->copybuf);
|
free(ctx->copybuf);
|
||||||
for (int i = 0; i < BEAT_FILECOUNT; i++) {
|
for (int i = 0; i < BEAT_FILENUM; i++) {
|
||||||
if (fvx_opened(&ctx->file[i])) fvx_close(&ctx->file[i]);
|
if (fvx_opened(&ctx->file[i])) fvx_close(&ctx->file[i]);
|
||||||
}
|
}
|
||||||
|
progress_refcnt--; // lol what even are atomics
|
||||||
}
|
}
|
||||||
|
|
||||||
// BPS Specific functions
|
// BPS Specific functions
|
||||||
@ -227,12 +256,12 @@ static void BEAT_ReleaseCTX(BEAT_Context *ctx)
|
|||||||
- extracts initial info
|
- extracts initial info
|
||||||
- leaves the file ready to begin state machine execution
|
- leaves the file ready to begin state machine execution
|
||||||
*/
|
*/
|
||||||
static int BPS_InitCTX_Advanced(BEAT_Context *ctx, const char *bps_path, const char *in_path, const char *out_path, size_t start, size_t end)
|
static int BPS_InitCTX_Advanced(BEAT_Context *ctx, const char *bps_path, const char *in_path, const char *out_path, size_t start, size_t end, bool do_chksum)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
u8 read_magic[4];
|
u8 read_magic[4];
|
||||||
u64 vli, in_sz, metaend_off;
|
u32 vli, in_sz, metaend_off;
|
||||||
u32 chksum[BEAT_FILECOUNT], expected_chksum[BEAT_FILECOUNT];
|
u32 chksum[BEAT_FILENUM], expected_chksum[BEAT_FILENUM];
|
||||||
|
|
||||||
// Clear stackbuf
|
// Clear stackbuf
|
||||||
memset(ctx, 0, sizeof(*ctx));
|
memset(ctx, 0, sizeof(*ctx));
|
||||||
@ -243,24 +272,25 @@ static int BPS_InitCTX_Advanced(BEAT_Context *ctx, const char *bps_path, const c
|
|||||||
end = fs_size(bps_path);
|
end = fs_size(bps_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get checksums of BPS and input files
|
if (do_chksum) // get BPS checksum
|
||||||
chksum[BEAT_PATCHFILE] = crc32_calculate_from_file(bps_path, start, end - start - 4);
|
chksum[BEAT_PF] = crc32_calculate_from_file(bps_path, start, end - start - 4);
|
||||||
chksum[BEAT_SRCFILE] = crc32_calculate_from_file(in_path, 0, fs_size(in_path));
|
|
||||||
|
strcpy(ctx->processing, basepath(bps_path));
|
||||||
|
|
||||||
// open all files
|
// open all files
|
||||||
fvx_open(&ctx->file[BEAT_PATCHFILE], bps_path, BEAT_READONLY);
|
fvx_open(&ctx->file[BEAT_PF], bps_path, BEAT_READONLY);
|
||||||
ctx->ranges[0][BEAT_PATCHFILE] = start;
|
ctx->ranges[0][BEAT_PF] = start;
|
||||||
ctx->ranges[1][BEAT_PATCHFILE] = end;
|
ctx->ranges[1][BEAT_PF] = end;
|
||||||
|
|
||||||
fvx_open(&ctx->file[BEAT_SRCFILE], in_path, BEAT_READONLY);
|
fvx_open(&ctx->file[BEAT_IF], in_path, BEAT_READONLY);
|
||||||
ctx->ranges[0][BEAT_SRCFILE] = 0;
|
ctx->ranges[0][BEAT_IF] = 0;
|
||||||
ctx->ranges[1][BEAT_SRCFILE] = fs_size(in_path);
|
ctx->ranges[1][BEAT_IF] = fs_size(in_path);
|
||||||
|
|
||||||
res = fvx_open(&ctx->file[BEAT_DSTFILE], out_path, BEAT_RWCREATE);
|
res = fvx_open(&ctx->file[BEAT_OF], out_path, BEAT_RWCREATE);
|
||||||
if (res != FR_OK) return BEAT_IO_ERROR;
|
if (res != FR_OK) return BEAT_IO_ERROR;
|
||||||
|
|
||||||
// Verify BPS1 header magic
|
// Verify BPS1 header magic
|
||||||
res = BEAT_Read(ctx, BEAT_PATCHFILE, read_magic, sizeof(read_magic), true);
|
res = BEAT_Read(ctx, BEAT_PF, read_magic, sizeof(read_magic), 1);
|
||||||
if (res != BEAT_OK) return BEAT_IO_ERROR;
|
if (res != BEAT_OK) return BEAT_IO_ERROR;
|
||||||
res = memcmp(read_magic, bps_signature, sizeof(bps_signature));
|
res = memcmp(read_magic, bps_signature, sizeof(bps_signature));
|
||||||
if (res != 0) return BEAT_BADPATCH;
|
if (res != 0) return BEAT_BADPATCH;
|
||||||
@ -268,113 +298,114 @@ static int BPS_InitCTX_Advanced(BEAT_Context *ctx, const char *bps_path, const c
|
|||||||
// Check input size
|
// Check input size
|
||||||
res = BEAT_NextVLI(ctx, &in_sz);
|
res = BEAT_NextVLI(ctx, &in_sz);
|
||||||
if (res != BEAT_OK) return res;
|
if (res != BEAT_OK) return res;
|
||||||
if (ctx->ranges[1][BEAT_SRCFILE] != in_sz) return BEAT_BADINPUT;
|
if (ctx->ranges[1][BEAT_IF] != in_sz) return BEAT_BADINPUT;
|
||||||
|
|
||||||
// Get expected output size
|
// Get expected output size
|
||||||
res = BEAT_NextVLI(ctx, &vli);
|
res = BEAT_NextVLI(ctx, &vli);
|
||||||
if (res != BEAT_OK) return res;
|
if (res != BEAT_OK) return res;
|
||||||
ctx->ranges[0][BEAT_DSTFILE] = 0;
|
ctx->ranges[0][BEAT_OF] = 0;
|
||||||
ctx->ranges[1][BEAT_DSTFILE] = vli;
|
ctx->ranges[1][BEAT_OF] = vli;
|
||||||
|
|
||||||
// Get end of metadata offset
|
// Get end of metadata offset
|
||||||
res = BEAT_NextVLI(ctx, &metaend_off);
|
res = BEAT_NextVLI(ctx, &metaend_off);
|
||||||
if (res != BEAT_OK) return res;
|
if (res != BEAT_OK) return res;
|
||||||
metaend_off += ctx->foffset[BEAT_PATCHFILE];
|
metaend_off += ctx->foff[BEAT_PF];
|
||||||
|
|
||||||
// Read checksums from BPS file
|
// Read checksums from BPS file
|
||||||
for (int i = 0; i < BEAT_FILECOUNT; i++) {
|
for (int i = 0; i < BEAT_FILENUM; i++) {
|
||||||
BEAT_SeekAbs(ctx, BEAT_PATCHFILE, ctx->ranges[1][BEAT_PATCHFILE] - ctx->ranges[0][BEAT_PATCHFILE] - bps_chksumoffs[i]);
|
BEAT_SeekAbs(ctx, BEAT_PF, BEAT_RANGE(ctx, BEAT_PF) - bps_chksumoffs[i]);
|
||||||
BEAT_Read(ctx, BEAT_PATCHFILE, &expected_chksum[i], sizeof(u32), false);
|
BEAT_Read(ctx, BEAT_PF, &expected_chksum[i], sizeof(u32), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify patch and input checksums
|
if (do_chksum) { // Verify patch checksum
|
||||||
if (chksum[BEAT_PATCHFILE] != expected_chksum[BEAT_PATCHFILE]) return BEAT_BADCHKSUM;
|
if (chksum[BEAT_PF] != expected_chksum[BEAT_PF]) return BEAT_BADCHKSUM;
|
||||||
if (chksum[BEAT_SRCFILE] != expected_chksum[BEAT_SRCFILE]) return BEAT_BADCHKSUM;
|
}
|
||||||
|
|
||||||
// Initialize output checksums
|
// Initialize output checksums
|
||||||
ctx->ocrc = 0;
|
ctx->ocrc = 0;
|
||||||
ctx->xocrc = expected_chksum[BEAT_DSTFILE];
|
ctx->xocrc = expected_chksum[BEAT_OF];
|
||||||
|
|
||||||
// Allocate temporary block copy buffer
|
// Allocate temporary block copy buffer
|
||||||
ctx->copybuf = malloc(STD_BUFFER_SIZE);
|
ctx->copybuf = malloc(BEAT_FILEBUFSZ);
|
||||||
if (ctx->copybuf == NULL) return BEAT_OUT_OF_MEMORY;
|
if (ctx->copybuf == NULL) return BEAT_OUT_OF_MEMORY;
|
||||||
|
|
||||||
// Seek back to the start of action stream / end of metadata
|
// Seek back to the start of action stream / end of metadata
|
||||||
BEAT_SeekAbs(ctx, BEAT_PATCHFILE, metaend_off);
|
BEAT_SeekAbs(ctx, BEAT_PF, metaend_off);
|
||||||
|
progress_refcnt++;
|
||||||
return BEAT_OK;
|
return BEAT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int BPS_InitCTX(BEAT_Context *ctx, const char *bps_path, const char *in_path, const char *out_path)
|
static int BPS_InitCTX(BEAT_Context *ctx, const char *bps, const char *in, const char *out)
|
||||||
{
|
{ return BPS_InitCTX_Advanced(ctx, bps, in, out, 0, 0, true); }
|
||||||
return BPS_InitCTX_Advanced(ctx, bps_path, in_path, out_path, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Generic helper function to copy from `src_id` to BEAT_DSTFILE
|
Generic helper function to copy from `src_id` to BEAT_OF
|
||||||
Used by SourceRead, TargetRead and CreateFile
|
Used by SourceRead, TargetRead and CreateFile
|
||||||
*/
|
*/
|
||||||
static int BEAT_BlkCopy(BEAT_Context *ctx, int src_id, u64 len)
|
static int BEAT_BlkCopy(BEAT_Context *ctx, int src_id, u32 len)
|
||||||
{
|
{
|
||||||
while(len > 0) {
|
while(len > 0) {
|
||||||
ssize_t blksz = min(len, STD_BUFFER_SIZE);
|
ssize_t blksz = min(len, BEAT_FILEBUFSZ);
|
||||||
int res = BEAT_Read(ctx, src_id, ctx->copybuf, blksz, true);
|
int res = BEAT_Read(ctx, src_id, ctx->copybuf, blksz, 1);
|
||||||
if (res != BEAT_OK) return res;
|
if (res != BEAT_OK) return res;
|
||||||
|
|
||||||
res = BEAT_WriteOut(ctx, ctx->copybuf, blksz, true);
|
res = BEAT_WriteOut(ctx, ctx->copybuf, blksz, 1);
|
||||||
if (res != BEAT_OK) return res;
|
if (res != BEAT_OK) return res;
|
||||||
|
|
||||||
|
if (!BEAT_UpdateProgress(ctx)) return BEAT_ABORTED;
|
||||||
|
|
||||||
len -= blksz;
|
len -= blksz;
|
||||||
}
|
}
|
||||||
return BEAT_OK;
|
return BEAT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int BPS_SourceRead(BEAT_Context *ctx, u64 len)
|
static int BPS_SourceRead(BEAT_Context *ctx, u32 len)
|
||||||
{ // This command copies bytes from the source file to the target file
|
{ // This command copies bytes from the source file to the target file
|
||||||
BEAT_SeekAbs(ctx, BEAT_SRCFILE, ctx->foffset[BEAT_DSTFILE]);
|
BEAT_SeekAbs(ctx, BEAT_IF, ctx->foff[BEAT_OF]);
|
||||||
return BEAT_BlkCopy(ctx, BEAT_SRCFILE, len);
|
return BEAT_BlkCopy(ctx, BEAT_IF, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
[...] the actual data is not available to the patch applier,
|
[...] the actual data is not available to the patch applier,
|
||||||
so it is stored directly inside the patch.
|
so it is stored directly inside the patch.
|
||||||
*/
|
*/
|
||||||
static int BPS_TargetRead(BEAT_Context *ctx, u64 len)
|
static int BPS_TargetRead(BEAT_Context *ctx, u32 len)
|
||||||
{
|
{
|
||||||
return BEAT_BlkCopy(ctx, BEAT_PATCHFILE, len);
|
return BEAT_BlkCopy(ctx, BEAT_PF, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
An offset is supplied to seek the sourceRelativeOffset to the desired
|
An offset is supplied to seek the sourceRelativeOffset to the desired
|
||||||
location, and then data is copied from said offset to the target file
|
location, and then data is copied from said offset to the target file
|
||||||
*/
|
*/
|
||||||
static int BPS_SourceCopy(BEAT_Context *ctx, u64 len)
|
static int BPS_SourceCopy(BEAT_Context *ctx, u32 len)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
u64 vli;
|
u32 vli;
|
||||||
s64 offset;
|
s32 offset;
|
||||||
|
|
||||||
res = BEAT_NextVLI(ctx, &vli);
|
res = BEAT_NextVLI(ctx, &vli);
|
||||||
if (res != BEAT_OK) return res;
|
if (res != BEAT_OK) return res;
|
||||||
|
|
||||||
offset = BEAT_DecodeSigned(vli);
|
offset = BEAT_DecodeSigned(vli);
|
||||||
BEAT_SeekAbs(ctx, BEAT_SRCFILE, ctx->source_relative + offset);
|
BEAT_SeekAbs(ctx, BEAT_IF, ctx->source_relative + offset);
|
||||||
ctx->source_relative += offset + len;
|
ctx->source_relative += offset + len;
|
||||||
|
|
||||||
return BEAT_BlkCopy(ctx, BEAT_SRCFILE, len);
|
return BEAT_BlkCopy(ctx, BEAT_IF, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This command treats all of the data that has already been written to the target file as a dictionary */
|
/* This command treats all of the data that has already been written to the target file as a dictionary */
|
||||||
static int BPS_TargetCopy(BEAT_Context *ctx, u64 len)
|
static int BPS_TargetCopy(BEAT_Context *ctx, u32 len)
|
||||||
{ // the black sheep of the family, needs special care
|
{ // the black sheep of the family, needs special care
|
||||||
int res;
|
int res;
|
||||||
s64 offset;
|
s32 offset;
|
||||||
u64 out_off, rel_off, vli;
|
u32 out_off, rel_off, vli;
|
||||||
|
|
||||||
res = BEAT_NextVLI(ctx, &vli);
|
res = BEAT_NextVLI(ctx, &vli);
|
||||||
if (res != BEAT_OK) return res;
|
if (res != BEAT_OK) return res;
|
||||||
|
|
||||||
offset = BEAT_DecodeSigned(vli);
|
offset = BEAT_DecodeSigned(vli);
|
||||||
out_off = ctx->foffset[BEAT_DSTFILE];
|
out_off = ctx->foff[BEAT_OF];
|
||||||
rel_off = ctx->target_relative + offset;
|
rel_off = ctx->target_relative + offset;
|
||||||
if (rel_off > out_off) return BEAT_BADPATCH; // Illegal
|
if (rel_off > out_off) return BEAT_BADPATCH; // Illegal
|
||||||
|
|
||||||
@ -382,11 +413,11 @@ static int BPS_TargetCopy(BEAT_Context *ctx, u64 len)
|
|||||||
u8 *remfill;
|
u8 *remfill;
|
||||||
ssize_t blksz, distance, remainder;
|
ssize_t blksz, distance, remainder;
|
||||||
|
|
||||||
blksz = min(len, STD_BUFFER_SIZE);
|
blksz = min(len, BEAT_FILEBUFSZ);
|
||||||
distance = min((ssize_t)(out_off - rel_off), blksz);
|
distance = min((ssize_t)(out_off - rel_off), blksz);
|
||||||
|
|
||||||
BEAT_SeekAbs(ctx, BEAT_DSTFILE, rel_off);
|
BEAT_SeekAbs(ctx, BEAT_OF, rel_off);
|
||||||
res = BEAT_Read(ctx, BEAT_DSTFILE, ctx->copybuf, distance, false);
|
res = BEAT_Read(ctx, BEAT_OF, ctx->copybuf, distance, 0);
|
||||||
if (res != BEAT_OK) return res;
|
if (res != BEAT_OK) return res;
|
||||||
|
|
||||||
remfill = ctx->copybuf + distance;
|
remfill = ctx->copybuf + distance;
|
||||||
@ -398,16 +429,17 @@ static int BPS_TargetCopy(BEAT_Context *ctx, u64 len)
|
|||||||
remainder -= remblk;
|
remainder -= remblk;
|
||||||
}
|
}
|
||||||
|
|
||||||
BEAT_SeekAbs(ctx, BEAT_DSTFILE, out_off);
|
BEAT_SeekAbs(ctx, BEAT_OF, out_off);
|
||||||
res = BEAT_WriteOut(ctx, ctx->copybuf, blksz, false);
|
res = BEAT_WriteOut(ctx, ctx->copybuf, blksz, 0);
|
||||||
if (res != BEAT_OK) return res;
|
if (res != BEAT_OK) return res;
|
||||||
|
|
||||||
|
if (!BEAT_UpdateProgress(ctx)) return BEAT_ABORTED;
|
||||||
rel_off += blksz;
|
rel_off += blksz;
|
||||||
out_off += blksz;
|
out_off += blksz;
|
||||||
len -= blksz;
|
len -= blksz;
|
||||||
}
|
}
|
||||||
|
|
||||||
BEAT_SeekAbs(ctx, BEAT_DSTFILE, out_off);
|
BEAT_SeekAbs(ctx, BEAT_OF, out_off);
|
||||||
ctx->target_relative = rel_off;
|
ctx->target_relative = rel_off;
|
||||||
return BEAT_OK;
|
return BEAT_OK;
|
||||||
}
|
}
|
||||||
@ -433,10 +465,10 @@ static int BPS_RunActions(BEAT_Context *ctx)
|
|||||||
static int BPM_OpenFile(BEAT_Context *ctx, int id, const char *path, size_t max_sz)
|
static int BPM_OpenFile(BEAT_Context *ctx, int id, const char *path, size_t max_sz)
|
||||||
{
|
{
|
||||||
FRESULT res;
|
FRESULT res;
|
||||||
if (fvx_opened(&ctx->file[id])) fvx_close(&ctx->file[id]);
|
|
||||||
|
|
||||||
|
if (fvx_opened(&ctx->file[id])) fvx_close(&ctx->file[id]);
|
||||||
res = fvx_open(&ctx->file[id], path, max_sz ? BEAT_RWCREATE : BEAT_READONLY);
|
res = fvx_open(&ctx->file[id], path, max_sz ? BEAT_RWCREATE : BEAT_READONLY);
|
||||||
if (res == FR_OK) return BEAT_IO_ERROR;
|
if (res != FR_OK) return BEAT_IO_ERROR;
|
||||||
|
|
||||||
ctx->ranges[0][id] = 0;
|
ctx->ranges[0][id] = 0;
|
||||||
if (max_sz > 0) {
|
if (max_sz > 0) {
|
||||||
@ -448,14 +480,14 @@ static int BPM_OpenFile(BEAT_Context *ctx, int id, const char *path, size_t max_
|
|||||||
// if a new file is opened it makes no sense to keep the old CRC
|
// if a new file is opened it makes no sense to keep the old CRC
|
||||||
// a single outfile wont be created from more than one infile (& patch)
|
// a single outfile wont be created from more than one infile (& patch)
|
||||||
ctx->ocrc = 0;
|
ctx->ocrc = 0;
|
||||||
ctx->foffset[id] = 0;
|
ctx->foff[id] = 0;
|
||||||
return BEAT_OK;
|
return BEAT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int BPM_InitCTX(BEAT_Context *ctx, const char *bpm_path, const char *src_dir, const char *dst_dir)
|
static int BPM_InitCTX(BEAT_Context *ctx, const char *bpm_path, const char *src_dir, const char *dst_dir)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
u64 metaend_off;
|
u32 metaend_off;
|
||||||
u8 read_magic[4];
|
u8 read_magic[4];
|
||||||
u32 chksum, expected_chksum;
|
u32 chksum, expected_chksum;
|
||||||
|
|
||||||
@ -467,37 +499,44 @@ static int BPM_InitCTX(BEAT_Context *ctx, const char *bpm_path, const char *src_
|
|||||||
ctx->eoal_offset = 4;
|
ctx->eoal_offset = 4;
|
||||||
|
|
||||||
chksum = crc32_calculate_from_file(bpm_path, 0, fs_size(bpm_path) - 4);
|
chksum = crc32_calculate_from_file(bpm_path, 0, fs_size(bpm_path) - 4);
|
||||||
res = BPM_OpenFile(ctx, BEAT_PATCHFILE, bpm_path, 0);
|
res = BPM_OpenFile(ctx, BEAT_PF, bpm_path, 0);
|
||||||
res = BEAT_Read(ctx, BEAT_PATCHFILE, read_magic, sizeof(read_magic), true);
|
if (res != BEAT_OK) return res;
|
||||||
|
res = BEAT_Read(ctx, BEAT_PF, read_magic, sizeof(read_magic), 1);
|
||||||
if (res != BEAT_OK) return res;
|
if (res != BEAT_OK) return res;
|
||||||
res = memcmp(read_magic, bpm_signature, sizeof(bpm_signature));
|
res = memcmp(read_magic, bpm_signature, sizeof(bpm_signature));
|
||||||
|
ShowPrompt(false, "%.4s %.4s", bpm_signature, read_magic);
|
||||||
if (res != 0) return BEAT_BADPATCH;
|
if (res != 0) return BEAT_BADPATCH;
|
||||||
|
|
||||||
// Get end of metadata offset
|
// Get end of metadata offset
|
||||||
res = BEAT_NextVLI(ctx, &metaend_off);
|
res = BEAT_NextVLI(ctx, &metaend_off);
|
||||||
if (res != BEAT_OK) return res;
|
if (res != BEAT_OK) return res;
|
||||||
metaend_off += ctx->foffset[BEAT_PATCHFILE];
|
metaend_off += ctx->foff[BEAT_PF];
|
||||||
|
|
||||||
// Read checksums from BPS file
|
// Read checksums from BPS file
|
||||||
BEAT_SeekAbs(ctx, BEAT_PATCHFILE, BEAT_RANGESZ(ctx, BEAT_PATCHFILE) - 4);
|
BEAT_SeekAbs(ctx, BEAT_PF, BEAT_RANGE(ctx, BEAT_PF) - 4);
|
||||||
res = BEAT_Read(ctx, BEAT_PATCHFILE, &expected_chksum, sizeof(u32), false);
|
res = BEAT_Read(ctx, BEAT_PF, &expected_chksum, sizeof(u32), 0);
|
||||||
if (res != BEAT_OK) return res;
|
if (res != BEAT_OK) return res;
|
||||||
if (expected_chksum != chksum) return BEAT_BADCHKSUM;
|
if (expected_chksum != chksum) return BEAT_BADCHKSUM;
|
||||||
|
|
||||||
// Allocate temporary block copy buffer
|
// Allocate temporary block copy buffer
|
||||||
ctx->copybuf = malloc(STD_BUFFER_SIZE);
|
ctx->copybuf = malloc(BEAT_FILEBUFSZ);
|
||||||
if (ctx->copybuf == NULL) return BEAT_OUT_OF_MEMORY;
|
if (ctx->copybuf == NULL) return BEAT_OUT_OF_MEMORY;
|
||||||
|
|
||||||
// Seek back to the start of action stream / end of metadata
|
// Seek back to the start of action stream / end of metadata
|
||||||
BEAT_SeekAbs(ctx, BEAT_PATCHFILE, metaend_off);
|
BEAT_SeekAbs(ctx, BEAT_PF, metaend_off);
|
||||||
|
progress_refcnt++;
|
||||||
return BEAT_OK;
|
return BEAT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int BPM_NextPath(BEAT_Context *ctx, char *out, int name_len)
|
static int BPM_NextPath(BEAT_Context *ctx, char *out, int name_len)
|
||||||
{
|
{
|
||||||
if (name_len >= BEAT_MAXPATH) return BEAT_BADPATCH;
|
if (name_len >= BEAT_MAXPATH) return BEAT_BADPATCH;
|
||||||
int res = BEAT_Read(ctx, BEAT_PATCHFILE, out, name_len, true);
|
int res = BEAT_Read(ctx, BEAT_PF, out, name_len, 1);
|
||||||
|
out[name_len] = '\0';
|
||||||
|
if (res == BEAT_OK) {
|
||||||
out[name_len] = '\0'; // make sure the buffer ends with a zero char
|
out[name_len] = '\0'; // make sure the buffer ends with a zero char
|
||||||
|
strcpy(ctx->processing, out);
|
||||||
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -513,7 +552,7 @@ static int BPM_MakeRelativePaths(BEAT_Context *ctx, char *src, char *dst, int na
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int BPM_CreatePath(BEAT_Context *ctx, u64 name_len)
|
static int BPM_CreatePath(BEAT_Context *ctx, u32 name_len)
|
||||||
{ // Create a directory
|
{ // Create a directory
|
||||||
char path[BEAT_MAXPATH];
|
char path[BEAT_MAXPATH];
|
||||||
int res = BPM_MakeRelativePaths(ctx, NULL, path, name_len);
|
int res = BPM_MakeRelativePaths(ctx, NULL, path, name_len);
|
||||||
@ -524,9 +563,9 @@ static int BPM_CreatePath(BEAT_Context *ctx, u64 name_len)
|
|||||||
return BEAT_OK;
|
return BEAT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int BPM_CreateFile(BEAT_Context *ctx, u64 name_len)
|
static int BPM_CreateFile(BEAT_Context *ctx, u32 name_len)
|
||||||
{ // Create a file and fill it with data provided in the BPM
|
{ // Create a file and fill it with data provided in the BPM
|
||||||
u64 file_sz;
|
u32 file_sz;
|
||||||
u32 checksum;
|
u32 checksum;
|
||||||
char path[BEAT_MAXPATH];
|
char path[BEAT_MAXPATH];
|
||||||
|
|
||||||
@ -535,20 +574,20 @@ static int BPM_CreateFile(BEAT_Context *ctx, u64 name_len)
|
|||||||
|
|
||||||
res = BEAT_NextVLI(ctx, &file_sz); // get new file size
|
res = BEAT_NextVLI(ctx, &file_sz); // get new file size
|
||||||
if (res != BEAT_OK) return res;
|
if (res != BEAT_OK) return res;
|
||||||
res = BPM_OpenFile(ctx, BEAT_DSTFILE, path, file_sz); // open file as RW
|
res = BPM_OpenFile(ctx, BEAT_OF, path, file_sz); // open file as RW
|
||||||
if (res != BEAT_OK) return res;
|
if (res != BEAT_OK) return res;
|
||||||
res = BEAT_BlkCopy(ctx, BEAT_PATCHFILE, file_sz); // copy data to new file
|
res = BEAT_BlkCopy(ctx, BEAT_PF, file_sz); // copy data to new file
|
||||||
if (res != BEAT_OK) return res;
|
if (res != BEAT_OK) return res;
|
||||||
|
|
||||||
res = BEAT_Read(ctx, BEAT_PATCHFILE, &checksum, sizeof(u32), true);
|
res = BEAT_Read(ctx, BEAT_PF, &checksum, sizeof(u32), 1);
|
||||||
if (res != BEAT_OK) return res;
|
if (res != BEAT_OK) return res;
|
||||||
if (ctx->ocrc != checksum) return BEAT_BADOUTPUT; // get and check CRC32
|
if (ctx->ocrc != checksum) return BEAT_BADOUTPUT; // get and check CRC32
|
||||||
return BEAT_OK;
|
return BEAT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int BPM_ModifyFile(BEAT_Context *ctx, u64 name_len)
|
static int BPM_ModifyFile(BEAT_Context *ctx, u32 name_len)
|
||||||
{ // Apply a BPS patch
|
{ // Apply a BPS patch
|
||||||
u64 origin, bps_sz;
|
u32 origin, bps_sz;
|
||||||
BEAT_Context bps_context;
|
BEAT_Context bps_context;
|
||||||
char src[BEAT_MAXPATH], dst[BEAT_MAXPATH];
|
char src[BEAT_MAXPATH], dst[BEAT_MAXPATH];
|
||||||
|
|
||||||
@ -562,19 +601,20 @@ static int BPM_ModifyFile(BEAT_Context *ctx, u64 name_len)
|
|||||||
|
|
||||||
res = BPS_InitCTX_Advanced(
|
res = BPS_InitCTX_Advanced(
|
||||||
&bps_context, ctx->bpm_path, src, dst,
|
&bps_context, ctx->bpm_path, src, dst,
|
||||||
ctx->foffset[BEAT_PATCHFILE], ctx->foffset[BEAT_PATCHFILE] + bps_sz
|
ctx->foff[BEAT_PF], ctx->foff[BEAT_PF] + bps_sz,
|
||||||
|
false
|
||||||
); // create a BPS context using the current ranges
|
); // create a BPS context using the current ranges
|
||||||
if (res == BEAT_OK) res = BPS_RunActions(&bps_context); // run if OK
|
if (res == BEAT_OK) res = BPS_RunActions(&bps_context); // run if OK
|
||||||
BEAT_ReleaseCTX(&bps_context);
|
BEAT_ReleaseCTX(&bps_context);
|
||||||
if (res != BEAT_OK) return res; // break off if there was an error
|
if (res != BEAT_OK) return res; // break off if there was an error
|
||||||
|
|
||||||
BEAT_SeekOff(ctx, BEAT_PATCHFILE, bps_sz); // advance beyond the BPS
|
BEAT_SeekOff(ctx, BEAT_PF, bps_sz); // advance beyond the BPS
|
||||||
return BEAT_OK;
|
return BEAT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int BPM_MirrorFile(BEAT_Context *ctx, u64 name_len)
|
static int BPM_MirrorFile(BEAT_Context *ctx, u32 name_len)
|
||||||
{ // Copy a file from source to target without any modifications
|
{ // Copy a file from source to target without any modifications
|
||||||
u64 origin;
|
u32 origin;
|
||||||
u32 checksum;
|
u32 checksum;
|
||||||
char src[BEAT_MAXPATH], dst[BEAT_MAXPATH];
|
char src[BEAT_MAXPATH], dst[BEAT_MAXPATH];
|
||||||
|
|
||||||
@ -582,18 +622,18 @@ static int BPM_MirrorFile(BEAT_Context *ctx, u64 name_len)
|
|||||||
if (res != BEAT_OK) return res;
|
if (res != BEAT_OK) return res;
|
||||||
|
|
||||||
// open source and destination files, read the origin dummy
|
// open source and destination files, read the origin dummy
|
||||||
res = BPM_OpenFile(ctx, BEAT_SRCFILE, src, 0);
|
res = BPM_OpenFile(ctx, BEAT_IF, src, 0);
|
||||||
if (res != BEAT_OK) return res;
|
if (res != BEAT_OK) return res;
|
||||||
res = BPM_OpenFile(ctx, BEAT_DSTFILE, dst, ctx->ranges[1][BEAT_SRCFILE]);
|
res = BPM_OpenFile(ctx, BEAT_OF, dst, ctx->ranges[1][BEAT_IF]);
|
||||||
if (res != BEAT_OK) return res;
|
if (res != BEAT_OK) return res;
|
||||||
res = BEAT_NextVLI(ctx, &origin);
|
res = BEAT_NextVLI(ctx, &origin);
|
||||||
if (res != BEAT_OK) return res;
|
if (res != BEAT_OK) return res;
|
||||||
|
|
||||||
// copy straight from source to destination
|
// copy straight from source to destination
|
||||||
res = BEAT_BlkCopy(ctx, BEAT_SRCFILE, ctx->ranges[1][BEAT_SRCFILE]);
|
res = BEAT_BlkCopy(ctx, BEAT_IF, ctx->ranges[1][BEAT_IF]);
|
||||||
if (res != BEAT_OK) return res;
|
if (res != BEAT_OK) return res;
|
||||||
|
|
||||||
res = BEAT_Read(ctx, BEAT_PATCHFILE, &checksum, sizeof(u32), true);
|
res = BEAT_Read(ctx, BEAT_PF, &checksum, sizeof(u32), 1);
|
||||||
if (res != BEAT_OK) return res;
|
if (res != BEAT_OK) return res;
|
||||||
if (ctx->ocrc != checksum) return BEAT_BADOUTPUT; // verify checksum
|
if (ctx->ocrc != checksum) return BEAT_BADOUTPUT; // verify checksum
|
||||||
return BEAT_OK;
|
return BEAT_OK;
|
||||||
@ -617,6 +657,8 @@ static int BEAT_Run(const char *p, const char *s, const char *d, bool bpm)
|
|||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
BEAT_Context ctx;
|
BEAT_Context ctx;
|
||||||
|
|
||||||
|
progress_timer = timer_start();
|
||||||
res = (bpm ? BPM_InitCTX : BPS_InitCTX)(&ctx, p, s, d);
|
res = (bpm ? BPM_InitCTX : BPS_InitCTX)(&ctx, p, s, d);
|
||||||
if (res != BEAT_OK) {
|
if (res != BEAT_OK) {
|
||||||
ShowPrompt(false, "Failed to initialize %s file:\n%s",
|
ShowPrompt(false, "Failed to initialize %s file:\n%s",
|
||||||
@ -625,7 +667,7 @@ static int BEAT_Run(const char *p, const char *s, const char *d, bool bpm)
|
|||||||
res = (bpm ? BPM_RunActions : BPS_RunActions)(&ctx);
|
res = (bpm ? BPM_RunActions : BPS_RunActions)(&ctx);
|
||||||
switch(res) {
|
switch(res) {
|
||||||
case BEAT_OK:
|
case BEAT_OK:
|
||||||
ShowPrompt(false, "Successfully patched");
|
ShowPrompt(false, "Patch successfully applied");
|
||||||
break;
|
break;
|
||||||
case BEAT_ABORTED:
|
case BEAT_ABORTED:
|
||||||
ShowPrompt(false, "Patching aborted by user");
|
ShowPrompt(false, "Patching aborted by user");
|
||||||
@ -641,6 +683,5 @@ static int BEAT_Run(const char *p, const char *s, const char *d, bool bpm)
|
|||||||
|
|
||||||
int ApplyBPSPatch(const char* modifyName, const char* sourceName, const char* targetName)
|
int ApplyBPSPatch(const char* modifyName, const char* sourceName, const char* targetName)
|
||||||
{ return BEAT_Run(modifyName, sourceName, targetName, false); }
|
{ return BEAT_Run(modifyName, sourceName, targetName, false); }
|
||||||
|
|
||||||
int ApplyBPMPatch(const char* patchName, const char* sourcePath, const char* targetPath)
|
int ApplyBPMPatch(const char* patchName, const char* sourcePath, const char* targetPath)
|
||||||
{ return BEAT_Run(patchName, sourcePath, targetPath, true); }
|
{ return BEAT_Run(patchName, sourcePath, targetPath, true); }
|
||||||
|
Loading…
x
Reference in New Issue
Block a user