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 "util/patch.h"
|
||||
#include "util/vfile.h"
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
|
@ -114,7 +115,7 @@ static THREAD_ENTRY _GBAThreadRun(void* context) {
|
|||
GBALoadBIOS(&gba, threadContext->biosFd);
|
||||
}
|
||||
|
||||
if (threadContext->patchFd >= 0 && loadPatch(threadContext->patchFd, &patch)) {
|
||||
if (threadContext->patchFd >= 0 && loadPatch(VFileFromFD(threadContext->patchFd), &patch)) {
|
||||
GBAApplyPatch(&gba, &patch);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
#include "util/patch-ips.h"
|
||||
|
||||
#include "util/patch.h"
|
||||
#include "util/vfile.h"
|
||||
|
||||
static size_t _IPSOutputSize(struct Patch* patch, size_t inSize);
|
||||
static bool _IPSApplyPatch(struct Patch* patch, void* out, size_t outSize);
|
||||
|
||||
bool loadPatchIPS(struct Patch* patch) {
|
||||
lseek(patch->patchfd, 0, SEEK_SET);
|
||||
patch->vf->seek(patch->vf, 0, SEEK_SET);
|
||||
|
||||
char buffer[5];
|
||||
if (read(patch->patchfd, buffer, 5) != 5) {
|
||||
if (patch->vf->read(patch->vf, buffer, 5) != 5) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -17,8 +18,8 @@ bool loadPatchIPS(struct Patch* patch) {
|
|||
return false;
|
||||
}
|
||||
|
||||
lseek(patch->patchfd, -3, SEEK_END);
|
||||
if (read(patch->patchfd, buffer, 3) != 3) {
|
||||
patch->vf->seek(patch->vf, -3, SEEK_END);
|
||||
if (patch->vf->read(patch->vf, buffer, 3) != 3) {
|
||||
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) {
|
||||
if (lseek(patch->patchfd, 5, SEEK_SET) != 5) {
|
||||
if (patch->vf->seek(patch->vf, 5, SEEK_SET) != 5) {
|
||||
return false;
|
||||
}
|
||||
uint8_t* buf = out;
|
||||
|
@ -46,7 +47,7 @@ bool _IPSApplyPatch(struct Patch* patch, void* out, size_t outSize) {
|
|||
uint32_t offset = 0;
|
||||
uint16_t size = 0;
|
||||
|
||||
if (read(patch->patchfd, &offset, 3) != 3) {
|
||||
if (patch->vf->read(patch->vf, &offset, 3) != 3) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -55,17 +56,17 @@ bool _IPSApplyPatch(struct Patch* patch, void* out, size_t outSize) {
|
|||
}
|
||||
|
||||
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;
|
||||
}
|
||||
if (!size) {
|
||||
// RLE chunk
|
||||
if (read(patch->patchfd, &size, 2) != 2) {
|
||||
if (patch->vf->read(patch->vf, &size, 2) != 2) {
|
||||
return false;
|
||||
}
|
||||
size = (size >> 8) | (size << 8);
|
||||
uint8_t byte;
|
||||
if (read(patch->patchfd, &byte, 1) != 1) {
|
||||
if (patch->vf->read(patch->vf, &byte, 1) != 1) {
|
||||
return false;
|
||||
}
|
||||
if (offset + size > outSize) {
|
||||
|
@ -77,7 +78,7 @@ bool _IPSApplyPatch(struct Patch* patch, void* out, size_t outSize) {
|
|||
if (offset + size > outSize) {
|
||||
return false;
|
||||
}
|
||||
if (read(patch->patchfd, &buf[offset], size) != size) {
|
||||
if (patch->vf->read(patch->vf, &buf[offset], size) != size) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "util/crc32.h"
|
||||
#include "util/patch.h"
|
||||
#include "util/vfile.h"
|
||||
|
||||
enum {
|
||||
IN_CHECKSUM = -12,
|
||||
|
@ -13,13 +14,13 @@ enum {
|
|||
|
||||
static size_t _UPSOutputSize(struct Patch* patch, size_t inSize);
|
||||
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) {
|
||||
lseek(patch->patchfd, 0, SEEK_SET);
|
||||
patch->vf->seek(patch->vf, 0, SEEK_SET);
|
||||
|
||||
char buffer[BUFFER_SIZE];
|
||||
if (read(patch->patchfd, buffer, 4) != 4) {
|
||||
if (patch->vf->read(patch->vf, buffer, 4) != 4) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -27,24 +28,24 @@ bool loadPatchUPS(struct Patch* patch) {
|
|||
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;
|
||||
lseek(patch->patchfd, PATCH_CHECKSUM, SEEK_END);
|
||||
if (read(patch->patchfd, &goodCrc32, 4) != 4) {
|
||||
patch->vf->seek(patch->vf, PATCH_CHECKSUM, SEEK_END);
|
||||
if (patch->vf->read(patch->vf, &goodCrc32, 4) != 4) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t blocksize;
|
||||
size_t alreadyRead = 0;
|
||||
lseek(patch->patchfd, 0, SEEK_SET);
|
||||
patch->vf->seek(patch->vf, 0, SEEK_SET);
|
||||
uint32_t crc = 0;
|
||||
while (alreadyRead < filesize + PATCH_CHECKSUM) {
|
||||
size_t toRead = sizeof(buffer);
|
||||
if (toRead + alreadyRead > filesize + PATCH_CHECKSUM) {
|
||||
toRead = filesize + PATCH_CHECKSUM - alreadyRead;
|
||||
}
|
||||
blocksize = read(patch->patchfd, buffer, toRead);
|
||||
blocksize = patch->vf->read(patch->vf, buffer, toRead);
|
||||
alreadyRead += blocksize;
|
||||
crc = updateCrc32(crc, buffer, blocksize);
|
||||
if (blocksize < toRead) {
|
||||
|
@ -63,20 +64,20 @@ bool loadPatchUPS(struct Patch* patch) {
|
|||
|
||||
size_t _UPSOutputSize(struct Patch* patch, size_t inSize) {
|
||||
UNUSED(inSize);
|
||||
lseek(patch->patchfd, 4, SEEK_SET);
|
||||
if (_UPSDecodeLength(patch->patchfd) != inSize) {
|
||||
patch->vf->seek(patch->vf, 4, SEEK_SET);
|
||||
if (_UPSDecodeLength(patch->vf) != inSize) {
|
||||
return 0;
|
||||
}
|
||||
return _UPSDecodeLength(patch->patchfd);
|
||||
return _UPSDecodeLength(patch->vf);
|
||||
}
|
||||
|
||||
bool _UPSApplyPatch(struct Patch* patch, void* out, size_t outSize) {
|
||||
// TODO: Input checksum
|
||||
|
||||
size_t filesize = lseek(patch->patchfd, 0, SEEK_END);
|
||||
lseek(patch->patchfd, 4, SEEK_SET);
|
||||
_UPSDecodeLength(patch->patchfd); // Discard input size
|
||||
if (_UPSDecodeLength(patch->patchfd) != outSize) {
|
||||
size_t filesize = patch->vf->seek(patch->vf, 0, SEEK_END);
|
||||
patch->vf->seek(patch->vf, 4, SEEK_SET);
|
||||
_UPSDecodeLength(patch->vf); // Discard input size
|
||||
if (_UPSDecodeLength(patch->vf) != outSize) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -84,11 +85,11 @@ bool _UPSApplyPatch(struct Patch* patch, void* out, size_t outSize) {
|
|||
size_t alreadyRead = 0;
|
||||
uint8_t* buf = out;
|
||||
while (alreadyRead < filesize + IN_CHECKSUM) {
|
||||
offset += _UPSDecodeLength(patch->patchfd);
|
||||
offset += _UPSDecodeLength(patch->vf);
|
||||
uint8_t byte;
|
||||
|
||||
while (true) {
|
||||
if (read(patch->patchfd, &byte, 1) != 1) {
|
||||
if (patch->vf->read(patch->vf, &byte, 1) != 1) {
|
||||
return false;
|
||||
}
|
||||
buf[offset] ^= byte;
|
||||
|
@ -97,28 +98,28 @@ bool _UPSApplyPatch(struct Patch* patch, void* out, size_t outSize) {
|
|||
break;
|
||||
}
|
||||
}
|
||||
alreadyRead = lseek(patch->patchfd, 0, SEEK_CUR);
|
||||
alreadyRead = patch->vf->seek(patch->vf, 0, SEEK_CUR);
|
||||
}
|
||||
|
||||
uint32_t goodCrc32;
|
||||
lseek(patch->patchfd, OUT_CHECKSUM, SEEK_END);
|
||||
if (read(patch->patchfd, &goodCrc32, 4) != 4) {
|
||||
patch->vf->seek(patch->vf, OUT_CHECKSUM, SEEK_END);
|
||||
if (patch->vf->read(patch->vf, &goodCrc32, 4) != 4) {
|
||||
return false;
|
||||
}
|
||||
|
||||
lseek(patch->patchfd, 0, SEEK_SET);
|
||||
patch->vf->seek(patch->vf, 0, SEEK_SET);
|
||||
if (crc32(out, outSize) != goodCrc32) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t _UPSDecodeLength(int fd) {
|
||||
size_t _UPSDecodeLength(struct VFile* vf) {
|
||||
size_t shift = 1;
|
||||
size_t value = 0;
|
||||
uint8_t byte;
|
||||
while (true) {
|
||||
if (read(fd, &byte, 1) != 1) {
|
||||
if (vf->read(vf, &byte, 1) != 1) {
|
||||
break;
|
||||
}
|
||||
value += (byte & 0x7f) * shift;
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
#include "util/patch-ips.h"
|
||||
#include "util/patch-ups.h"
|
||||
|
||||
bool loadPatch(int patchfd, struct Patch* patch) {
|
||||
patch->patchfd = patchfd;
|
||||
bool loadPatch(struct VFile* vf, struct Patch* patch) {
|
||||
patch->vf = vf;
|
||||
|
||||
if (loadPatchIPS(patch)) {
|
||||
return true;
|
||||
|
|
|
@ -3,13 +3,15 @@
|
|||
|
||||
#include "common.h"
|
||||
|
||||
struct VFile;
|
||||
|
||||
struct Patch {
|
||||
int patchfd;
|
||||
struct VFile* vf;
|
||||
|
||||
size_t (*outputSize)(struct Patch* patch, size_t inSize);
|
||||
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
|
||||
|
|
|
@ -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