mirror of
https://github.com/Alcaro/Flips.git
synced 2026-09-04 08:44:33 -05:00
Clean up UPS handler
This commit is contained in:
125
patch/ups.cpp
125
patch/ups.cpp
@@ -2,124 +2,84 @@
|
||||
|
||||
namespace patch { namespace ups {
|
||||
//TODO: HEAVY cleanups needed here
|
||||
static uint32_t read32(uint8_t * ptr)
|
||||
{
|
||||
uint32_t out;
|
||||
out =ptr[0];
|
||||
out|=ptr[1]<<8;
|
||||
out|=ptr[2]<<16;
|
||||
out|=ptr[3]<<24;
|
||||
return out;
|
||||
}
|
||||
|
||||
#define error(which) do { error=which; goto exit; } while(0)
|
||||
#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_)
|
||||
{
|
||||
if (patch_.size()<4+2+12) return e_broken;
|
||||
|
||||
struct mem patch = patch_.mmap();
|
||||
struct mem in = source_.mmap();
|
||||
struct mem out_;
|
||||
struct mem * out = &out_;
|
||||
arrayview<byte> patchmem = patch_.mmap();
|
||||
memstream patch = patchmem;
|
||||
arrayview<byte> inmem = source_.mmap();
|
||||
memstream in = inmem;
|
||||
|
||||
result error;
|
||||
out->len=0;
|
||||
out->ptr=NULL;
|
||||
|
||||
if (true)
|
||||
{
|
||||
#define readpatch8() (*(patchat++))
|
||||
#define readin8() (*(inat++))
|
||||
#define writeout8(byte) (*(outat++)=byte)
|
||||
|
||||
#define decodeto(var) \
|
||||
do { \
|
||||
var=0; \
|
||||
unsigned int shift=0; \
|
||||
while (true) \
|
||||
{ \
|
||||
uint8_t next=readpatch8(); \
|
||||
assert_shift(next&0x7F, shift); \
|
||||
size_t addthis=(next&0x7F)<<shift; \
|
||||
assert_sum(var, addthis); \
|
||||
var+=addthis; \
|
||||
if (next&0x80) break; \
|
||||
shift+=7; \
|
||||
assert_sum(var, 1U<<shift); \
|
||||
var+=1<<shift; \
|
||||
} \
|
||||
safeint<size_t> ret = patch.bpsnum(); \
|
||||
if (!ret.valid()) error(e_too_big); \
|
||||
var = ret.val(); \
|
||||
} while(false)
|
||||
|
||||
bool backwards=false;
|
||||
|
||||
uint8_t * patchat=patch.ptr;
|
||||
uint8_t * patchend=patch.ptr+patch.len-12;
|
||||
|
||||
if (readpatch8()!='U') error(e_broken);
|
||||
if (readpatch8()!='P') error(e_broken);
|
||||
if (readpatch8()!='S') error(e_broken);
|
||||
if (readpatch8()!='1') error(e_broken);
|
||||
if (patch.u8()!='U') error(e_broken);
|
||||
if (patch.u8()!='P') error(e_broken);
|
||||
if (patch.u8()!='S') error(e_broken);
|
||||
if (patch.u8()!='1') error(e_broken);
|
||||
|
||||
size_t inlen;
|
||||
size_t outlen;
|
||||
decodeto(inlen);
|
||||
decodeto(outlen);
|
||||
if (inlen!=in.len)
|
||||
if (inlen!=in.size())
|
||||
{
|
||||
size_t tmp=inlen;
|
||||
inlen=outlen;
|
||||
outlen=tmp;
|
||||
backwards=true;
|
||||
}
|
||||
if (inlen!=in.len) error(e_not_this);
|
||||
if (inlen!=in.size()) error(e_not_this);
|
||||
|
||||
out->len=outlen;
|
||||
out->ptr=(uint8_t*)malloc(outlen);
|
||||
memset(out->ptr, 0, outlen);
|
||||
array<byte> outmem;
|
||||
outmem.resize(outlen);
|
||||
membufwriter out = outmem;
|
||||
|
||||
//uint8_t * instart=in.ptr;
|
||||
uint8_t * inat=in.ptr;
|
||||
uint8_t * inend=in.ptr+in.len;
|
||||
|
||||
//uint8_t * outstart=out->ptr;
|
||||
uint8_t * outat=out->ptr;
|
||||
uint8_t * outend=out->ptr+out->len;
|
||||
|
||||
while (patchat<patchend)
|
||||
while (patch.remaining() > 12)
|
||||
{
|
||||
size_t skip;
|
||||
decodeto(skip);
|
||||
size_t skip_fast = min(skip, outlen-out.size(), in.remaining());
|
||||
out.write(in.bytes(skip_fast));
|
||||
skip -= skip_fast;
|
||||
while (skip>0)
|
||||
{
|
||||
uint8_t out;
|
||||
if (inat>=inend) out=0;
|
||||
else out=readin8();
|
||||
if (outat<outend) writeout8(out);
|
||||
uint8_t outb = in.u8_or(0);
|
||||
if (out.size()<outlen) out.write(outb);
|
||||
skip--;
|
||||
}
|
||||
uint8_t tmp;
|
||||
do
|
||||
{
|
||||
tmp=readpatch8();
|
||||
uint8_t out;
|
||||
if (inat>=inend) out=0;
|
||||
else out=readin8();
|
||||
if (outat<outend) writeout8(out^tmp);
|
||||
tmp=patch.u8();
|
||||
uint8_t outb = in.u8_or(0);
|
||||
if (out.size()<outlen) out.write(outb^tmp);
|
||||
else if (outb != 0) error(e_broken);
|
||||
}
|
||||
while (tmp);
|
||||
}
|
||||
if (patchat!=patchend) error(e_broken);
|
||||
while (outat<outend) writeout8(0);
|
||||
while (inat<inend) (void)readin8();
|
||||
if (patch.remaining()!=12) error(e_broken);
|
||||
|
||||
uint32_t crc_in_expected=read32(patchat);
|
||||
uint32_t crc_out_expected=read32(patchat+4);
|
||||
uint32_t crc_patch_expected=read32(patchat+8);
|
||||
uint32_t crc_in=crc32(inmem);
|
||||
uint32_t crc_out=crc32(outmem);
|
||||
uint32_t crc_patch=crc32(patchmem.slice(0, patchmem.size()-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));
|
||||
uint32_t crc_in_expected=patch.u32();
|
||||
uint32_t crc_out_expected=patch.u32();
|
||||
uint32_t crc_patch_expected=patch.u32();
|
||||
|
||||
if (inlen==outlen)
|
||||
{
|
||||
@@ -144,23 +104,16 @@ result apply(const file& patch_, const file& source_, file& target_)
|
||||
}
|
||||
if (crc_patch!=crc_patch_expected) error(e_broken);
|
||||
|
||||
target_.write(out->v());
|
||||
free(out->ptr);
|
||||
patch_.unmap(patch.v());
|
||||
source_.unmap(in.v());
|
||||
patch_.unmap(patchmem);
|
||||
source_.unmap(inmem);
|
||||
target_.write(outmem);
|
||||
return e_ok;
|
||||
#undef read8
|
||||
#undef decodeto
|
||||
#undef write8
|
||||
}
|
||||
|
||||
exit:
|
||||
|
||||
free(out->ptr);
|
||||
patch_.unmap(patch.v());
|
||||
source_.unmap(in.v());
|
||||
out->len=0;
|
||||
out->ptr=NULL;
|
||||
patch_.unmap(patchmem);
|
||||
source_.unmap(inmem);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user