Update UPS handler, wipe some outdated cruft

This commit is contained in:
Alcaro 2016-12-21 14:26:36 +01:00
parent 0e31df85fd
commit e2026b1056
6 changed files with 41 additions and 106 deletions

View File

@ -1,4 +1,3 @@
#include "arlib.h"
#include "flips.h"
/*

View File

@ -1 +1,3 @@
#include "patch/patch.h"
#define FLIPSVER "2.00"

View File

@ -197,6 +197,8 @@ result apply(const file& patch_, const file& source_, file& target_, bool accept
target_.write(out->v());
free(out->ptr);
patch_.unmap(patch.v());
source_.unmap(in.v());
return error;
#undef read8
#undef decodeto
@ -205,6 +207,8 @@ result apply(const file& patch_, const file& source_, file& target_, bool accept
exit:
free(out->ptr);
patch_.unmap(patch.v());
source_.unmap(in.v());
out->len=0;
out->ptr=NULL;
if (metadata)

View File

@ -1,36 +0,0 @@
#include "global.h"
enum ipserror {
ips_ok,//Patch applied or created successfully.
ips_notthis,//The patch is most likely not intended for this ROM.
ips_thisout,//You most likely applied the patch on the output ROM.
ips_scrambled,//The patch is technically valid, but seems scrambled or malformed.
ips_invalid,//The patch is invalid.
ips_16MB,//One or both files is bigger than 16MB. The IPS format doesn't support that. The created
//patch contains only the differences to that point.
ips_identical,//The input buffers are identical.
ips_shut_up_gcc//This one isn't used, it's just to kill a stray comma warning.
};
//Applies the IPS patch in [patch, patchlen] to [in, inlen] and stores it to [out, outlen]. Send the
// return value in out to ips_free when you're done with it.
enum ipserror ips_apply(struct mem patch, struct mem in, struct mem * out);
//Creates an IPS patch that converts source to target and stores it to patch.
enum ipserror ips_create(struct mem source, struct mem target, struct mem * patch);
//Frees the memory returned in the output parameters of the above. Do not call it twice on the same
// input, nor on anything you got from anywhere else. ips_free is guaranteed to be equivalent to
// calling stdlib.h's free() on mem.ptr.
void ips_free(struct mem mem);
//ips_study allows you to detect most patching errors without applying it to a ROM, or even a ROM to
// apply it to. ips_apply calls ips_study and ips_apply_study, so if you call ips_study yourself,
// it's recommended to call ips_apply_study to not redo the calculation. ips_free is still
// required.
struct ipsstudy;
enum ipserror ips_study(struct mem patch, struct ipsstudy * study);
enum ipserror ips_apply_study(struct mem patch, struct ipsstudy * study, struct mem in, struct mem * out);

View File

@ -1,30 +0,0 @@
#include "global.h"
//Several of those are unused, but remain there so the remaining ones match bpserror.
enum upserror {
ups_ok,//Patch applied or created successfully.
ups_unused1, //bps_to_output
ups_not_this,//This is not the intended input file for this patch.
ups_broken, //This is not a UPS patch, or it's malformed somehow.
ups_unused2, //bps_io
ups_identical,//The input files are identical.
ups_too_big, //Somehow, you're asking for something a size_t can't represent.
ups_unused3, //bps_out_of_mem
ups_unused4, //bps_canceled
ups_shut_up_gcc//This one isn't used, it's just to kill a stray comma warning.
};
//Applies the UPS patch in [patch, patchlen] to [in, inlen] and stores it to [out, outlen]. Send the
// return value in out to ups_free when you're done with it.
enum upserror ups_apply(struct mem patch, struct mem in, struct mem * out);
//Creates an UPS patch that converts source to target and stores it to patch. (Not implemented.)
enum upserror ups_create(struct mem source, struct mem target, struct mem * patch);
//Frees the memory returned in the output parameters of the above. Do not call it twice on the same
// input, nor on anything you got from anywhere else. ups_free is guaranteed to be equivalent to
// calling stdlib.h's free() on mem.ptr.
void ups_free(struct mem mem);

View File

@ -1,10 +1,7 @@
#include "libups.h"
#include <stdint.h>//uint8_t, uint32_t
#include <stdlib.h>//malloc, realloc, free
#include <string.h>//memcpy, memset
#include "arlib/crc32.h"
#include "patch.h"
namespace patch { namespace ups {
//TODO: HEAVY cleanups needed here
static uint32_t read32(uint8_t * ptr)
{
uint32_t out;
@ -16,14 +13,19 @@ static uint32_t read32(uint8_t * ptr)
}
#define error(which) do { error=which; goto exit; } while(0)
#define assert_sum(a,b) do { if (SIZE_MAX-(a)<(b)) error(ups_too_big); } while(0)
#define assert_shift(a,b) do { if (SIZE_MAX>>(b)<(a)) error(ups_too_big); } while(0)
enum upserror ups_apply(struct mem patch, struct mem in, struct mem * out)
#define assert_sum(a,b) do { if (SIZE_MAX-(a)<(b)) error(e_too_big); } while(0)
#define assert_shift(a,b) do { if (SIZE_MAX>>(b)<(a)) error(e_too_big); } while(0)
result apply(const file& patch_, const file& source_, file& target_)
{
enum upserror error;
if (patch_.size()<4+2+12) return e_broken;
struct mem patch = patch_.read();
struct mem in = source_.read();
struct mem out_;
struct mem * out = &out_;
result error;
out->len=0;
out->ptr=NULL;
if (patch.len<4+2+12) return ups_broken;
if (true)
{
@ -54,10 +56,10 @@ enum upserror ups_apply(struct mem patch, struct mem in, struct mem * out)
uint8_t * patchat=patch.ptr;
uint8_t * patchend=patch.ptr+patch.len-12;
if (readpatch8()!='U') error(ups_broken);
if (readpatch8()!='P') error(ups_broken);
if (readpatch8()!='S') error(ups_broken);
if (readpatch8()!='1') error(ups_broken);
if (readpatch8()!='U') error(e_broken);
if (readpatch8()!='P') error(e_broken);
if (readpatch8()!='S') error(e_broken);
if (readpatch8()!='1') error(e_broken);
size_t inlen;
size_t outlen;
@ -70,7 +72,7 @@ enum upserror ups_apply(struct mem patch, struct mem in, struct mem * out)
outlen=tmp;
backwards=true;
}
if (inlen!=in.len) error(ups_not_this);
if (inlen!=in.len) error(e_not_this);
out->len=outlen;
out->ptr=(uint8_t*)malloc(outlen);
@ -107,7 +109,7 @@ enum upserror ups_apply(struct mem patch, struct mem in, struct mem * out)
}
while (tmp);
}
if (patchat!=patchend) error(ups_broken);
if (patchat!=patchend) error(e_broken);
while (outat<outend) writeout8(0);
while (inat<inend) (void)readin8();
@ -115,53 +117,47 @@ enum upserror ups_apply(struct mem patch, struct mem in, struct mem * out)
uint32_t crc_out_expected=read32(patchat+4);
uint32_t crc_patch_expected=read32(patchat+8);
uint32_t crc_in=crc32(in.ptr, in.len);
uint32_t crc_out=crc32(out->ptr, out->len);
uint32_t crc_patch=crc32(patch.ptr, patch.len-4);
uint32_t crc_in=crc32(in.v());
uint32_t crc_out=crc32(out->v());
uint32_t crc_patch=crc32(patch.v().slice(0, patch.len-4));
if (inlen==outlen)
{
if ((crc_in!=crc_in_expected || crc_out!=crc_out_expected) && (crc_in!=crc_out_expected || crc_out!=crc_in_expected)) error(ups_not_this);
if ((crc_in!=crc_in_expected || crc_out!=crc_out_expected) && (crc_in!=crc_out_expected || crc_out!=crc_in_expected)) error(e_not_this);
}
else
{
if (!backwards)
{
if (crc_in!=crc_in_expected) error(ups_not_this);
if (crc_out!=crc_out_expected) error(ups_not_this);
if (crc_in!=crc_in_expected) error(e_not_this);
if (crc_out!=crc_out_expected) error(e_not_this);
}
else
{
if (crc_in!=crc_out_expected) error(ups_not_this);
if (crc_out!=crc_in_expected) error(ups_not_this);
if (crc_in!=crc_out_expected) error(e_not_this);
if (crc_out!=crc_in_expected) error(e_not_this);
}
}
if (crc_patch!=crc_patch_expected) error(ups_broken);
return ups_ok;
if (crc_patch!=crc_patch_expected) error(e_broken);
target_.write(out->v());
free(out->ptr);
free(patch.ptr);
return e_ok;
#undef read8
#undef decodeto
#undef write8
}
exit:
free(patch.ptr);
free(out->ptr);
out->len=0;
out->ptr=NULL;
return error;
}
enum upserror ups_create(struct mem sourcemem, struct mem targetmem, struct mem * patchmem)
{
patchmem->ptr=NULL;
patchmem->len=0;
return ups_broken;//unimplemented, just pick a random error
}
void ups_free(struct mem mem)
{
free(mem.ptr);
}
#if 0
//Sorry, no undocumented features here. The only thing that can change an UPS patch is swapping the two sizes and checksums, and I don't create anyways.
#endif
}}