//Module name: libups //Author: Alcaro //Date: April 4, 2013 //Licence: GPL v3.0 or higher #include "libups.h" #ifndef __cplusplus #include //bool; if this file does not exist (hi msvc), remove it and uncomment the following three lines. //#define bool int //#define true 1 //#define false 0 #endif #include //uint8_t, uint32_t #include //malloc, realloc, free #include //memcpy, memset #include "crc32.h" 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(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) { enum upserror error; out->len=0; out->ptr=NULL; if (patch.len<4+2+12) return ups_broken; 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 (outatptr, out->len); uint32_t crc_patch=crc32(patch.ptr, 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); } else { if (!backwards) { if (crc_in!=crc_in_expected) error(ups_not_this); if (crc_out!=crc_out_expected) error(ups_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_patch!=crc_patch_expected) error(ups_broken); return ups_ok; #undef read8 #undef decodeto #undef write8 } exit: 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