VFiles for abstract file operations, used at first in patches

This commit is contained in:
Jeffrey Pfau 2014-07-16 01:31:10 -07:00
parent d8654f3b88
commit 377d8e60a7
7 changed files with 136 additions and 38 deletions

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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;

View File

@ -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

76
src/util/vfile.c Normal file
View File

@ -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);
}

17
src/util/vfile.h Normal file
View File

@ -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