mirror of https://github.com/mgba-emu/mgba.git
VFiles for abstract file operations, used at first in patches
This commit is contained in:
parent
d8654f3b88
commit
377d8e60a7
|
@ -7,6 +7,7 @@
|
||||||
#include "debugger/debugger.h"
|
#include "debugger/debugger.h"
|
||||||
|
|
||||||
#include "util/patch.h"
|
#include "util/patch.h"
|
||||||
|
#include "util/vfile.h"
|
||||||
|
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
|
@ -114,7 +115,7 @@ static THREAD_ENTRY _GBAThreadRun(void* context) {
|
||||||
GBALoadBIOS(&gba, threadContext->biosFd);
|
GBALoadBIOS(&gba, threadContext->biosFd);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (threadContext->patchFd >= 0 && loadPatch(threadContext->patchFd, &patch)) {
|
if (threadContext->patchFd >= 0 && loadPatch(VFileFromFD(threadContext->patchFd), &patch)) {
|
||||||
GBAApplyPatch(&gba, &patch);
|
GBAApplyPatch(&gba, &patch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,16 @@
|
||||||
#include "util/patch-ips.h"
|
#include "util/patch-ips.h"
|
||||||
|
|
||||||
#include "util/patch.h"
|
#include "util/patch.h"
|
||||||
|
#include "util/vfile.h"
|
||||||
|
|
||||||
static size_t _IPSOutputSize(struct Patch* patch, size_t inSize);
|
static size_t _IPSOutputSize(struct Patch* patch, size_t inSize);
|
||||||
static bool _IPSApplyPatch(struct Patch* patch, void* out, size_t outSize);
|
static bool _IPSApplyPatch(struct Patch* patch, void* out, size_t outSize);
|
||||||
|
|
||||||
bool loadPatchIPS(struct Patch* patch) {
|
bool loadPatchIPS(struct Patch* patch) {
|
||||||
lseek(patch->patchfd, 0, SEEK_SET);
|
patch->vf->seek(patch->vf, 0, SEEK_SET);
|
||||||
|
|
||||||
char buffer[5];
|
char buffer[5];
|
||||||
if (read(patch->patchfd, buffer, 5) != 5) {
|
if (patch->vf->read(patch->vf, buffer, 5) != 5) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,8 +18,8 @@ bool loadPatchIPS(struct Patch* patch) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
lseek(patch->patchfd, -3, SEEK_END);
|
patch->vf->seek(patch->vf, -3, SEEK_END);
|
||||||
if (read(patch->patchfd, buffer, 3) != 3) {
|
if (patch->vf->read(patch->vf, buffer, 3) != 3) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,7 +38,7 @@ size_t _IPSOutputSize(struct Patch* patch, size_t inSize) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _IPSApplyPatch(struct Patch* patch, void* out, size_t outSize) {
|
bool _IPSApplyPatch(struct Patch* patch, void* out, size_t outSize) {
|
||||||
if (lseek(patch->patchfd, 5, SEEK_SET) != 5) {
|
if (patch->vf->seek(patch->vf, 5, SEEK_SET) != 5) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
uint8_t* buf = out;
|
uint8_t* buf = out;
|
||||||
|
@ -46,7 +47,7 @@ bool _IPSApplyPatch(struct Patch* patch, void* out, size_t outSize) {
|
||||||
uint32_t offset = 0;
|
uint32_t offset = 0;
|
||||||
uint16_t size = 0;
|
uint16_t size = 0;
|
||||||
|
|
||||||
if (read(patch->patchfd, &offset, 3) != 3) {
|
if (patch->vf->read(patch->vf, &offset, 3) != 3) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,17 +56,17 @@ bool _IPSApplyPatch(struct Patch* patch, void* out, size_t outSize) {
|
||||||
}
|
}
|
||||||
|
|
||||||
offset = (offset >> 16) | (offset & 0xFF00) | ((offset << 16) & 0xFF0000);
|
offset = (offset >> 16) | (offset & 0xFF00) | ((offset << 16) & 0xFF0000);
|
||||||
if (read(patch->patchfd, &size, 2) != 2) {
|
if (patch->vf->read(patch->vf, &size, 2) != 2) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!size) {
|
if (!size) {
|
||||||
// RLE chunk
|
// RLE chunk
|
||||||
if (read(patch->patchfd, &size, 2) != 2) {
|
if (patch->vf->read(patch->vf, &size, 2) != 2) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
size = (size >> 8) | (size << 8);
|
size = (size >> 8) | (size << 8);
|
||||||
uint8_t byte;
|
uint8_t byte;
|
||||||
if (read(patch->patchfd, &byte, 1) != 1) {
|
if (patch->vf->read(patch->vf, &byte, 1) != 1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (offset + size > outSize) {
|
if (offset + size > outSize) {
|
||||||
|
@ -77,7 +78,7 @@ bool _IPSApplyPatch(struct Patch* patch, void* out, size_t outSize) {
|
||||||
if (offset + size > outSize) {
|
if (offset + size > outSize) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (read(patch->patchfd, &buf[offset], size) != size) {
|
if (patch->vf->read(patch->vf, &buf[offset], size) != size) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include "util/crc32.h"
|
#include "util/crc32.h"
|
||||||
#include "util/patch.h"
|
#include "util/patch.h"
|
||||||
|
#include "util/vfile.h"
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
IN_CHECKSUM = -12,
|
IN_CHECKSUM = -12,
|
||||||
|
@ -13,13 +14,13 @@ enum {
|
||||||
|
|
||||||
static size_t _UPSOutputSize(struct Patch* patch, size_t inSize);
|
static size_t _UPSOutputSize(struct Patch* patch, size_t inSize);
|
||||||
static bool _UPSApplyPatch(struct Patch* patch, void* out, size_t outSize);
|
static bool _UPSApplyPatch(struct Patch* patch, void* out, size_t outSize);
|
||||||
static size_t _UPSDecodeLength(int fd);
|
static size_t _UPSDecodeLength(struct VFile* vf);
|
||||||
|
|
||||||
bool loadPatchUPS(struct Patch* patch) {
|
bool loadPatchUPS(struct Patch* patch) {
|
||||||
lseek(patch->patchfd, 0, SEEK_SET);
|
patch->vf->seek(patch->vf, 0, SEEK_SET);
|
||||||
|
|
||||||
char buffer[BUFFER_SIZE];
|
char buffer[BUFFER_SIZE];
|
||||||
if (read(patch->patchfd, buffer, 4) != 4) {
|
if (patch->vf->read(patch->vf, buffer, 4) != 4) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,24 +28,24 @@ bool loadPatchUPS(struct Patch* patch) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t filesize = lseek(patch->patchfd, 0, SEEK_END);
|
size_t filesize = patch->vf->seek(patch->vf, 0, SEEK_END);
|
||||||
|
|
||||||
uint32_t goodCrc32;
|
uint32_t goodCrc32;
|
||||||
lseek(patch->patchfd, PATCH_CHECKSUM, SEEK_END);
|
patch->vf->seek(patch->vf, PATCH_CHECKSUM, SEEK_END);
|
||||||
if (read(patch->patchfd, &goodCrc32, 4) != 4) {
|
if (patch->vf->read(patch->vf, &goodCrc32, 4) != 4) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t blocksize;
|
size_t blocksize;
|
||||||
size_t alreadyRead = 0;
|
size_t alreadyRead = 0;
|
||||||
lseek(patch->patchfd, 0, SEEK_SET);
|
patch->vf->seek(patch->vf, 0, SEEK_SET);
|
||||||
uint32_t crc = 0;
|
uint32_t crc = 0;
|
||||||
while (alreadyRead < filesize + PATCH_CHECKSUM) {
|
while (alreadyRead < filesize + PATCH_CHECKSUM) {
|
||||||
size_t toRead = sizeof(buffer);
|
size_t toRead = sizeof(buffer);
|
||||||
if (toRead + alreadyRead > filesize + PATCH_CHECKSUM) {
|
if (toRead + alreadyRead > filesize + PATCH_CHECKSUM) {
|
||||||
toRead = filesize + PATCH_CHECKSUM - alreadyRead;
|
toRead = filesize + PATCH_CHECKSUM - alreadyRead;
|
||||||
}
|
}
|
||||||
blocksize = read(patch->patchfd, buffer, toRead);
|
blocksize = patch->vf->read(patch->vf, buffer, toRead);
|
||||||
alreadyRead += blocksize;
|
alreadyRead += blocksize;
|
||||||
crc = updateCrc32(crc, buffer, blocksize);
|
crc = updateCrc32(crc, buffer, blocksize);
|
||||||
if (blocksize < toRead) {
|
if (blocksize < toRead) {
|
||||||
|
@ -63,20 +64,20 @@ bool loadPatchUPS(struct Patch* patch) {
|
||||||
|
|
||||||
size_t _UPSOutputSize(struct Patch* patch, size_t inSize) {
|
size_t _UPSOutputSize(struct Patch* patch, size_t inSize) {
|
||||||
UNUSED(inSize);
|
UNUSED(inSize);
|
||||||
lseek(patch->patchfd, 4, SEEK_SET);
|
patch->vf->seek(patch->vf, 4, SEEK_SET);
|
||||||
if (_UPSDecodeLength(patch->patchfd) != inSize) {
|
if (_UPSDecodeLength(patch->vf) != inSize) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return _UPSDecodeLength(patch->patchfd);
|
return _UPSDecodeLength(patch->vf);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _UPSApplyPatch(struct Patch* patch, void* out, size_t outSize) {
|
bool _UPSApplyPatch(struct Patch* patch, void* out, size_t outSize) {
|
||||||
// TODO: Input checksum
|
// TODO: Input checksum
|
||||||
|
|
||||||
size_t filesize = lseek(patch->patchfd, 0, SEEK_END);
|
size_t filesize = patch->vf->seek(patch->vf, 0, SEEK_END);
|
||||||
lseek(patch->patchfd, 4, SEEK_SET);
|
patch->vf->seek(patch->vf, 4, SEEK_SET);
|
||||||
_UPSDecodeLength(patch->patchfd); // Discard input size
|
_UPSDecodeLength(patch->vf); // Discard input size
|
||||||
if (_UPSDecodeLength(patch->patchfd) != outSize) {
|
if (_UPSDecodeLength(patch->vf) != outSize) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,11 +85,11 @@ bool _UPSApplyPatch(struct Patch* patch, void* out, size_t outSize) {
|
||||||
size_t alreadyRead = 0;
|
size_t alreadyRead = 0;
|
||||||
uint8_t* buf = out;
|
uint8_t* buf = out;
|
||||||
while (alreadyRead < filesize + IN_CHECKSUM) {
|
while (alreadyRead < filesize + IN_CHECKSUM) {
|
||||||
offset += _UPSDecodeLength(patch->patchfd);
|
offset += _UPSDecodeLength(patch->vf);
|
||||||
uint8_t byte;
|
uint8_t byte;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
if (read(patch->patchfd, &byte, 1) != 1) {
|
if (patch->vf->read(patch->vf, &byte, 1) != 1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
buf[offset] ^= byte;
|
buf[offset] ^= byte;
|
||||||
|
@ -97,28 +98,28 @@ bool _UPSApplyPatch(struct Patch* patch, void* out, size_t outSize) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
alreadyRead = lseek(patch->patchfd, 0, SEEK_CUR);
|
alreadyRead = patch->vf->seek(patch->vf, 0, SEEK_CUR);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t goodCrc32;
|
uint32_t goodCrc32;
|
||||||
lseek(patch->patchfd, OUT_CHECKSUM, SEEK_END);
|
patch->vf->seek(patch->vf, OUT_CHECKSUM, SEEK_END);
|
||||||
if (read(patch->patchfd, &goodCrc32, 4) != 4) {
|
if (patch->vf->read(patch->vf, &goodCrc32, 4) != 4) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
lseek(patch->patchfd, 0, SEEK_SET);
|
patch->vf->seek(patch->vf, 0, SEEK_SET);
|
||||||
if (crc32(out, outSize) != goodCrc32) {
|
if (crc32(out, outSize) != goodCrc32) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t _UPSDecodeLength(int fd) {
|
size_t _UPSDecodeLength(struct VFile* vf) {
|
||||||
size_t shift = 1;
|
size_t shift = 1;
|
||||||
size_t value = 0;
|
size_t value = 0;
|
||||||
uint8_t byte;
|
uint8_t byte;
|
||||||
while (true) {
|
while (true) {
|
||||||
if (read(fd, &byte, 1) != 1) {
|
if (vf->read(vf, &byte, 1) != 1) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
value += (byte & 0x7f) * shift;
|
value += (byte & 0x7f) * shift;
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
#include "util/patch-ips.h"
|
#include "util/patch-ips.h"
|
||||||
#include "util/patch-ups.h"
|
#include "util/patch-ups.h"
|
||||||
|
|
||||||
bool loadPatch(int patchfd, struct Patch* patch) {
|
bool loadPatch(struct VFile* vf, struct Patch* patch) {
|
||||||
patch->patchfd = patchfd;
|
patch->vf = vf;
|
||||||
|
|
||||||
if (loadPatchIPS(patch)) {
|
if (loadPatchIPS(patch)) {
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -3,13 +3,15 @@
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
|
struct VFile;
|
||||||
|
|
||||||
struct Patch {
|
struct Patch {
|
||||||
int patchfd;
|
struct VFile* vf;
|
||||||
|
|
||||||
size_t (*outputSize)(struct Patch* patch, size_t inSize);
|
size_t (*outputSize)(struct Patch* patch, size_t inSize);
|
||||||
bool (*applyPatch)(struct Patch* patch, void* out, size_t outSize);
|
bool (*applyPatch)(struct Patch* patch, void* out, size_t outSize);
|
||||||
};
|
};
|
||||||
|
|
||||||
bool loadPatch(int patchfd, struct Patch* patch);
|
bool loadPatch(struct VFile* vf, struct Patch* patch);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
#include "util/vfile.h"
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
struct VFileFD {
|
||||||
|
struct VFile d;
|
||||||
|
int fd;
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool _vfdClose(struct VFile* vf);
|
||||||
|
static size_t _vfdSeek(struct VFile* vf, off_t offset, int whence);
|
||||||
|
static size_t _vfdRead(struct VFile* vf, void* buffer, size_t size);
|
||||||
|
static size_t _vfdReadline(struct VFile* vf, char* buffer, size_t size);
|
||||||
|
static size_t _vfdWrite(struct VFile* vf, void* buffer, size_t size);
|
||||||
|
|
||||||
|
struct VFile* VFileOpen(const char* path, int flags) {
|
||||||
|
int fd = open(path, flags);
|
||||||
|
return VFileFromFD(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct VFile* VFileFromFD(int fd) {
|
||||||
|
if (fd < 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct VFileFD* vfd = malloc(sizeof(struct VFileFD));
|
||||||
|
if (!vfd) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
vfd->fd = fd;
|
||||||
|
vfd->d.close = _vfdClose;
|
||||||
|
vfd->d.seek = _vfdSeek;
|
||||||
|
vfd->d.read = _vfdRead;
|
||||||
|
vfd->d.readline = _vfdReadline;
|
||||||
|
vfd->d.write = _vfdWrite;
|
||||||
|
|
||||||
|
return &vfd->d;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _vfdClose(struct VFile* vf) {
|
||||||
|
struct VFileFD* vfd = (struct VFileFD*) vf;
|
||||||
|
if (close(vfd->fd) < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
free(vfd);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t _vfdSeek(struct VFile* vf, off_t offset, int whence) {
|
||||||
|
struct VFileFD* vfd = (struct VFileFD*) vf;
|
||||||
|
return lseek(vfd->fd, offset, whence);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t _vfdRead(struct VFile* vf, void* buffer, size_t size) {
|
||||||
|
struct VFileFD* vfd = (struct VFileFD*) vf;
|
||||||
|
return read(vfd->fd, buffer, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t _vfdReadline(struct VFile* vf, char* buffer, size_t size) {
|
||||||
|
struct VFileFD* vfd = (struct VFileFD*) vf;
|
||||||
|
size_t bytesRead = 0;
|
||||||
|
while (bytesRead < size - 1) {
|
||||||
|
size_t newRead = read(vfd->fd, &buffer[bytesRead], 1);
|
||||||
|
bytesRead += newRead;
|
||||||
|
if (!newRead || buffer[bytesRead] == '\n') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buffer[bytesRead] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t _vfdWrite(struct VFile* vf, void* buffer, size_t size) {
|
||||||
|
struct VFileFD* vfd = (struct VFileFD*) vf;
|
||||||
|
return write(vfd->fd, buffer, size);
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
#ifndef VFILE_H
|
||||||
|
#define VFILE_H
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
struct VFile {
|
||||||
|
bool (*close)(struct VFile* vf);
|
||||||
|
size_t (*seek)(struct VFile* vf, off_t offset, int whence);
|
||||||
|
size_t (*read)(struct VFile* vf, void* buffer, size_t size);
|
||||||
|
size_t (*readline)(struct VFile* vf, char* buffer, size_t size);
|
||||||
|
size_t (*write)(struct VFile* vf, void* buffer, size_t size);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VFile* VFileOpen(const char* path, int flags);
|
||||||
|
struct VFile* VFileFromFD(int fd);
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue