#include "patch.h" 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_.read(); struct mem in = source_.read(); struct mem out_; struct mem * out = &out_; 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)<len=outlen; out->ptr=(uint8_t*)malloc(outlen); memset(out->ptr, 0, outlen); //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 (patchat0) { uint8_t out; if (inat>=inend) out=0; else out=readin8(); if (outat=inend) out=0; else out=readin8(); if (outatv()); 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(e_not_this); } else { if (!backwards) { 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(e_not_this); if (crc_out!=crc_in_expected) error(e_not_this); } } 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; } #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 }}