PageRenderTime 28ms CodeModel.GetById 32ms RepoModel.GetById 0ms app.codeStats 0ms

/emu-ex-plus-alpha/GBA.emu/src/vbam/common/Patch.cpp

https://gitlab.com/fengluo/gba4ios
C++ | 441 lines | 365 code | 64 blank | 12 comment | 146 complexity | e706ffd7885125d929746ed361c54080 MD5 | raw file
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <zlib.h>
  5. #include "Patch.h"
  6. #define fseeko64 fseek
  7. #define ftello64 ftell
  8. static int readInt2(FILE *f)
  9. {
  10. int res = 0;
  11. int c = fgetc(f);
  12. if(c == EOF)
  13. return -1;
  14. res = c;
  15. c = fgetc(f);
  16. if(c == EOF)
  17. return -1;
  18. return c + (res<<8);
  19. }
  20. static int readInt3(FILE *f)
  21. {
  22. int res = 0;
  23. int c = fgetc(f);
  24. if(c == EOF)
  25. return -1;
  26. res = c;
  27. c = fgetc(f);
  28. if(c == EOF)
  29. return -1;
  30. res = c + (res<<8);
  31. c = fgetc(f);
  32. if(c == EOF)
  33. return -1;
  34. return c + (res<<8);
  35. }
  36. static s64 readInt4(FILE *f)
  37. {
  38. s64 tmp, res = 0;
  39. int c;
  40. for (int i = 0; i < 4; i++) {
  41. c = fgetc(f);
  42. if (c == EOF)
  43. return -1;
  44. tmp = c;
  45. res = res + (tmp << (i*8));
  46. }
  47. return res;
  48. }
  49. static s64 readInt8(FILE *f)
  50. {
  51. s64 tmp, res = 0;
  52. int c;
  53. for (int i = 0; i < 8; i++) {
  54. c = fgetc(f);
  55. if (c == EOF)
  56. return -1;
  57. tmp = c;
  58. res = res + (tmp << (i*8));
  59. }
  60. return res;
  61. }
  62. static s64 readVarPtr(FILE *f)
  63. {
  64. s64 offset = 0, shift = 1;
  65. for (;;) {
  66. int c = fgetc(f);
  67. if (c == EOF) return 0;
  68. offset += (c & 0x7F) * shift;
  69. if (c & 0x80) break;
  70. shift <<= 7;
  71. offset += shift;
  72. }
  73. return offset;
  74. }
  75. #ifndef MIN
  76. #define MIN(a,b) (((a)<(b))?(a):(b))
  77. #endif
  78. static uLong computePatchCRC(FILE *f, unsigned int size)
  79. {
  80. Bytef buf[4096];
  81. size_t readed;
  82. uLong crc = crc32(0L, Z_NULL, 0);
  83. do {
  84. readed = fread(buf, 1, MIN(size, sizeof(buf)), f);
  85. crc = crc32(crc, buf, readed);
  86. size -= readed;
  87. } while (readed > 0);
  88. return crc;
  89. }
  90. bool patchApplyIPS(const char *patchname, u8 **r, int *s)
  91. {
  92. // from the IPS spec at http://zerosoft.zophar.net/ips.htm
  93. FILE *f = fopen(patchname, "rb");
  94. if(!f)
  95. return false;
  96. bool result = false;
  97. u8 *rom = *r;
  98. int size = *s;
  99. if(fgetc(f) == 'P' &&
  100. fgetc(f) == 'A' &&
  101. fgetc(f) == 'T' &&
  102. fgetc(f) == 'C' &&
  103. fgetc(f) == 'H') {
  104. int b;
  105. int offset;
  106. int len;
  107. result = true;
  108. for(;;) {
  109. // read offset
  110. offset = readInt3(f);
  111. // if offset == EOF, end of patch
  112. if(offset == 0x454f46 || offset == -1)
  113. break;
  114. // read length
  115. len = readInt2(f);
  116. if(!len) {
  117. // len == 0, RLE block
  118. len = readInt2(f);
  119. // byte to fill
  120. int c = fgetc(f);
  121. if(c == -1)
  122. break;
  123. b = (u8)c;
  124. } else
  125. b= -1;
  126. // check if we need to reallocate our ROM
  127. if((offset + len) >= size) {
  128. size *= 2;
  129. //rom = (u8 *)realloc(rom, size);
  130. *r = rom;
  131. *s = size;
  132. }
  133. if(b == -1) {
  134. // normal block, just read the data
  135. if(fread(&rom[offset], 1, len, f) != (size_t)len)
  136. break;
  137. } else {
  138. // fill the region with the given byte
  139. while(len--) {
  140. rom[offset++] = b;
  141. }
  142. }
  143. }
  144. }
  145. // close the file
  146. fclose(f);
  147. return result;
  148. }
  149. bool patchApplyUPS(const char *patchname, u8 **rom, int *size)
  150. {
  151. s64 srcCRC, dstCRC, patchCRC;
  152. FILE *f = fopen(patchname, "rb");
  153. if (!f)
  154. return false;
  155. fseeko64(f, 0, SEEK_END);
  156. off_t patchSize = ftello64(f);
  157. if (patchSize < 20) {
  158. fclose(f);
  159. return false;
  160. }
  161. fseeko64(f, 0, SEEK_SET);
  162. if(fgetc(f) != 'U' || fgetc(f) != 'P' || fgetc(f) != 'S' || fgetc(f) != '1') {
  163. fclose(f);
  164. return false;
  165. }
  166. fseeko64(f, -12, SEEK_END);
  167. srcCRC = readInt4(f);
  168. dstCRC = readInt4(f);
  169. patchCRC = readInt4(f);
  170. if (srcCRC == -1 || dstCRC == -1 || patchCRC == -1) {
  171. fclose(f);
  172. return false;
  173. }
  174. fseeko64(f, 0, SEEK_SET);
  175. u32 crc = computePatchCRC(f, patchSize-4);
  176. if (crc != patchCRC) {
  177. fclose(f);
  178. return false;
  179. }
  180. crc = crc32(0L, Z_NULL, 0);
  181. crc = crc32(crc, *rom, *size);
  182. fseeko64(f, 4, SEEK_SET);
  183. s64 dataSize;
  184. s64 srcSize = readVarPtr(f);
  185. s64 dstSize = readVarPtr(f);
  186. if (crc == srcCRC) {
  187. if (srcSize != *size) {
  188. fclose(f);
  189. return false;
  190. }
  191. dataSize = dstSize;
  192. } else if (crc == dstCRC) {
  193. if (dstSize != *size) {
  194. fclose(f);
  195. return false;
  196. }
  197. dataSize = srcSize;
  198. } else {
  199. fclose(f);
  200. return false;
  201. }
  202. if (dataSize > *size) {
  203. // *rom = (u8*)realloc(*rom, dataSize);
  204. memset(*rom + *size, 0, dataSize - *size);
  205. *size = dataSize;
  206. }
  207. s64 relative = 0;
  208. u8 *mem;
  209. while(ftello64(f) < patchSize - 12) {
  210. relative += readVarPtr(f);
  211. if (relative > dataSize) continue;
  212. mem = *rom + relative;
  213. for(s64 i = relative; i < dataSize; i++) {
  214. int x = fgetc(f);
  215. relative++;
  216. if (!x) break;
  217. if (i < dataSize) {
  218. *mem++ ^= x;
  219. }
  220. }
  221. }
  222. fclose(f);
  223. return true;
  224. }
  225. static int ppfVersion(FILE *f)
  226. {
  227. fseeko64(f, 0, SEEK_SET);
  228. if (fgetc(f) != 'P' || fgetc(f) != 'P' || fgetc(f) != 'F')
  229. return 0;
  230. switch(fgetc(f)){
  231. case '1': return 1;
  232. case '2': return 2;
  233. case '3': return 3;
  234. default: return 0;
  235. }
  236. }
  237. static int ppfFileIdLen(FILE *f, int version)
  238. {
  239. if (version == 2) {
  240. fseeko64(f, -8, SEEK_END);
  241. } else {
  242. fseeko64(f, -6, SEEK_END);
  243. }
  244. if (fgetc(f) != '.' || fgetc(f) != 'D' || fgetc(f) != 'I' || fgetc(f) != 'Z')
  245. return 0;
  246. return (version == 2) ? readInt4(f) : readInt2(f);
  247. }
  248. static bool patchApplyPPF1(FILE *f, u8 **rom, int *size)
  249. {
  250. fseek(f, 0, SEEK_END);
  251. int count = ftell(f);
  252. if (count < 56)
  253. return false;
  254. count -= 56;
  255. fseek(f, 56, SEEK_SET);
  256. u8 *mem = *rom;
  257. while (count > 0) {
  258. int offset = readInt4(f);
  259. if (offset == -1)
  260. break;
  261. int len = fgetc(f);
  262. if (len == EOF)
  263. break;
  264. if (offset+len > *size)
  265. break;
  266. if (fread(&mem[offset], 1, len, f) != (size_t)len)
  267. break;
  268. count -= 4 + 1 + len;
  269. }
  270. return (count == 0);
  271. }
  272. static bool patchApplyPPF2(FILE *f, u8 **rom, int *size)
  273. {
  274. fseek(f, 0, SEEK_END);
  275. int count = ftell(f);
  276. if (count < 56+4+1024)
  277. return false;
  278. count -= 56+4+1024;
  279. fseek(f, 56, SEEK_SET);
  280. int datalen = readInt4(f);
  281. if (datalen != *size)
  282. return false;
  283. u8 *mem = *rom;
  284. u8 block[1024];
  285. fread(&block, 1, 1024, f);
  286. if (memcmp(&mem[0x9320], &block, 1024) != 0)
  287. return false;
  288. int idlen = ppfFileIdLen(f, 2);
  289. if (idlen > 0)
  290. count -= 16 + 16 + idlen;
  291. fseek(f, 56+4+1024, SEEK_SET);
  292. while (count > 0) {
  293. int offset = readInt4(f);
  294. if (offset == -1)
  295. break;
  296. int len = fgetc(f);
  297. if (len == EOF)
  298. break;
  299. if (offset+len > *size)
  300. break;
  301. if (fread(&mem[offset], 1, len, f) != (size_t)len)
  302. break;
  303. count -= 4 + 1 + len;
  304. }
  305. return (count == 0);
  306. }
  307. static bool patchApplyPPF3(FILE *f, u8 **rom, int *size)
  308. {
  309. fseek(f, 0, SEEK_END);
  310. int count = ftell(f);
  311. if (count < 56+4+1024)
  312. return false;
  313. count -= 56+4;
  314. fseek(f, 56, SEEK_SET);
  315. int imagetype = fgetc(f);
  316. int blockcheck = fgetc(f);
  317. int undo = fgetc(f);
  318. fgetc(f);
  319. u8 *mem = *rom;
  320. if (blockcheck) {
  321. u8 block[1024];
  322. fread(&block, 1, 1024, f);
  323. if (memcmp(&mem[(imagetype == 0) ? 0x9320 : 0x80A0], &block, 1024) != 0)
  324. return false;
  325. count -= 1024;
  326. }
  327. int idlen = ppfFileIdLen(f, 2);
  328. if (idlen > 0)
  329. count -= 16 + 16 + idlen;
  330. fseek(f, 56+4+(blockcheck ? 1024 : 0), SEEK_SET);
  331. while (count > 0) {
  332. off_t offset = readInt8(f);
  333. if (offset == -1)
  334. break;
  335. int len = fgetc(f);
  336. if (len == EOF)
  337. break;
  338. if (offset+len > *size)
  339. break;
  340. if (fread(&mem[offset], 1, len, f) != (size_t)len)
  341. break;
  342. if (undo) fseeko64(f, len, SEEK_CUR);
  343. count -= 8 + 1 + len;
  344. if (undo) count -= len;
  345. }
  346. return (count == 0);
  347. }
  348. bool patchApplyPPF(const char *patchname, u8 **rom, int *size)
  349. {
  350. FILE *f = fopen(patchname, "rb");
  351. if (!f)
  352. return false;
  353. bool res = false;
  354. int version = ppfVersion(f);
  355. switch (version) {
  356. case 1: res = patchApplyPPF1(f, rom, size); break;
  357. case 2: res = patchApplyPPF2(f, rom, size); break;
  358. case 3: res = patchApplyPPF3(f, rom, size); break;
  359. }
  360. fclose(f);
  361. return res;
  362. }
  363. bool applyPatch(const char *patchname, u8 **rom, int *size)
  364. {
  365. if (strlen(patchname) < 5)
  366. return false;
  367. const char * p = strrchr(patchname, '.');
  368. if (p == NULL)
  369. return false;
  370. if (strcasecmp(p, ".ips") == 0)
  371. return patchApplyIPS(patchname, rom, size);
  372. if (strcasecmp(p, ".ups") == 0)
  373. return patchApplyUPS(patchname, rom, size);
  374. if (strcasecmp(p, ".ppf") == 0)
  375. return patchApplyPPF(patchname, rom, size);
  376. return false;
  377. }