PageRenderTime 114ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/VisualBoyAdvance/vbanext/src/common/Patch.cpp

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