Mercurial > vba-clojure
comparison src/common/Util.cpp @ 19:5e8e5083da94
brought in common and gba, fixed problems with outdated Makefile.am files in both of these packages
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Sun, 04 Mar 2012 14:33:52 -0600 |
parents | f9f4f1b99eed |
children | f94fa48624d0 |
comparison
equal
deleted
inserted
replaced
18:ac56489c2ca6 | 19:5e8e5083da94 |
---|---|
1 #include <cstdio> | |
2 #include <cstdlib> | |
3 #include <cstring> | |
4 #include <zlib.h> | |
5 | |
6 extern "C" { | |
7 #include <png.h> | |
8 } | |
9 | |
10 #if 0 | |
11 #include "unrarlib.h" | |
12 #endif | |
13 | |
14 #include "unzip.h" | |
15 | |
16 #include "../NLS.h" | |
17 #include "System.h" | |
18 #include "Util.h" | |
19 #include "../gba/Flash.h" | |
20 #include "../gba/RTC.h" | |
21 | |
22 extern "C" { | |
23 #include "memgzio.h" | |
24 } | |
25 | |
26 #ifndef _MSC_VER | |
27 #define _stricmp strcasecmp | |
28 #endif // ! _MSC_VER | |
29 | |
30 extern int32 cpuSaveType; | |
31 | |
32 extern int systemColorDepth; | |
33 extern int systemRedShift; | |
34 extern int systemGreenShift; | |
35 extern int systemBlueShift; | |
36 | |
37 extern u16 systemColorMap16[0x10000]; | |
38 extern u32 systemColorMap32[0x10000]; | |
39 | |
40 static int (ZEXPORT *utilGzWriteFunc)(gzFile, voidp, unsigned int) = NULL; | |
41 static int (ZEXPORT *utilGzReadFunc)(gzFile, voidp, unsigned int) = NULL; | |
42 static int (ZEXPORT *utilGzCloseFunc)(gzFile) = NULL; | |
43 static z_off_t (ZEXPORT *utilGzSeekFunc)(gzFile, z_off_t, int) = NULL; | |
44 static z_off_t (ZEXPORT *utilGzTellFunc)(gzFile) = NULL; | |
45 | |
46 //Kludge to get it to compile in Linux, GCC cannot convert | |
47 //gzwrite function pointer to the type of utilGzWriteFunc | |
48 //due to void* and const void* differences | |
49 //--Felipe | |
50 int gzWrite(gzFile file, void* buf, unsigned len){ | |
51 return gzwrite(file,buf,len); | |
52 } | |
53 | |
54 void utilPutDword(u8 *p, u32 value) | |
55 { | |
56 *p++ = value & 255; | |
57 *p++ = (value >> 8) & 255; | |
58 *p++ = (value >> 16) & 255; | |
59 *p = (value >> 24) & 255; | |
60 } | |
61 | |
62 void utilPutWord(u8 *p, u16 value) | |
63 { | |
64 *p++ = value & 255; | |
65 *p = (value >> 8) & 255; | |
66 } | |
67 | |
68 void utilWriteBMP(u8 *b, int w, int h, int dstDepth, u8 *pix) | |
69 { | |
70 int sizeX = w; | |
71 int sizeY = h; | |
72 | |
73 switch (dstDepth > 0 ? dstDepth : systemColorDepth) | |
74 { | |
75 case 16: | |
76 { | |
77 u16 *p = (u16 *)(pix + (w + 2) * (h) * 2); // skip first black line | |
78 for (int y = 0; y < sizeY; y++) | |
79 { | |
80 for (int x = 0; x < sizeX; x++) | |
81 { | |
82 u16 v = *p++; | |
83 | |
84 *b++ = ((v >> systemBlueShift) & 0x01f) << 3; // B | |
85 *b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G | |
86 *b++ = ((v >> systemRedShift) & 0x001f) << 3; // R | |
87 } | |
88 p++; // skip black pixel for filters | |
89 p++; // skip black pixel for filters | |
90 p -= 2 * (w + 2); | |
91 } | |
92 break; | |
93 } | |
94 case 24: | |
95 { | |
96 u8 *pixU8 = (u8 *)pix + 3 * w * (h - 1); | |
97 for (int y = 0; y < sizeY; y++) | |
98 { | |
99 for (int x = 0; x < sizeX; x++) | |
100 { | |
101 if (systemRedShift > systemBlueShift) | |
102 { | |
103 *b++ = *pixU8++; // B | |
104 *b++ = *pixU8++; // G | |
105 *b++ = *pixU8++; // R | |
106 } | |
107 else | |
108 { | |
109 int red = *pixU8++; | |
110 int green = *pixU8++; | |
111 int blue = *pixU8++; | |
112 | |
113 *b++ = blue; | |
114 *b++ = green; | |
115 *b++ = red; | |
116 } | |
117 } | |
118 pixU8 -= 2 * 3 * w; | |
119 } | |
120 break; | |
121 } | |
122 case 32: | |
123 { | |
124 u32 *pixU32 = (u32 *)(pix + 4 * (w + 1) * (h)); | |
125 for (int y = 0; y < sizeY; y++) | |
126 { | |
127 for (int x = 0; x < sizeX; x++) | |
128 { | |
129 u32 v = *pixU32++; | |
130 | |
131 *b++ = ((v >> systemBlueShift) & 0x001f) << 3; // B | |
132 *b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G | |
133 *b++ = ((v >> systemRedShift) & 0x001f) << 3; // R | |
134 } | |
135 pixU32++; | |
136 pixU32 -= 2 * (w + 1); | |
137 } | |
138 break; | |
139 } | |
140 } | |
141 } | |
142 | |
143 bool utilWriteBMPFile(const char *fileName, int w, int h, u8 *pix) | |
144 { | |
145 u8 writeBuffer[256 * 3]; | |
146 | |
147 FILE *fp = fopen(fileName, "wb"); | |
148 | |
149 if (!fp) | |
150 { | |
151 systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), fileName); | |
152 return false; | |
153 } | |
154 | |
155 struct | |
156 { | |
157 u8 ident[2]; | |
158 u8 filesize[4]; | |
159 u8 reserved[4]; | |
160 u8 dataoffset[4]; | |
161 u8 headersize[4]; | |
162 u8 width[4]; | |
163 u8 height[4]; | |
164 u8 planes[2]; | |
165 u8 bitsperpixel[2]; | |
166 u8 compression[4]; | |
167 u8 datasize[4]; | |
168 u8 hres[4]; | |
169 u8 vres[4]; | |
170 u8 colors[4]; | |
171 u8 importantcolors[4]; | |
172 // u8 pad[2]; | |
173 } bmpheader; | |
174 memset(&bmpheader, 0, sizeof(bmpheader)); | |
175 | |
176 bmpheader.ident[0] = 'B'; | |
177 bmpheader.ident[1] = 'M'; | |
178 | |
179 u32 fsz = sizeof(bmpheader) + w * h * 3; | |
180 utilPutDword(bmpheader.filesize, fsz); | |
181 utilPutDword(bmpheader.dataoffset, 0x36); | |
182 utilPutDword(bmpheader.headersize, 0x28); | |
183 utilPutDword(bmpheader.width, w); | |
184 utilPutDword(bmpheader.height, h); | |
185 utilPutDword(bmpheader.planes, 1); | |
186 utilPutDword(bmpheader.bitsperpixel, 24); | |
187 utilPutDword(bmpheader.datasize, 3 * w * h); | |
188 | |
189 fwrite(&bmpheader, 1, sizeof(bmpheader), fp); | |
190 | |
191 #if 0 | |
192 // FIXME: need sufficient buffer | |
193 utilWriteBMP(writeBuffer, w, h, systemColorDepth, pix); | |
194 #else | |
195 u8 *b = writeBuffer; | |
196 | |
197 int sizeX = w; | |
198 int sizeY = h; | |
199 | |
200 switch (systemColorDepth) | |
201 { | |
202 case 16: | |
203 { | |
204 u16 *p = (u16 *)(pix + (w + 2) * (h) * 2); // skip first black line | |
205 for (int y = 0; y < sizeY; y++) | |
206 { | |
207 for (int x = 0; x < sizeX; x++) | |
208 { | |
209 u16 v = *p++; | |
210 | |
211 *b++ = ((v >> systemBlueShift) & 0x01f) << 3; // B | |
212 *b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G | |
213 *b++ = ((v >> systemRedShift) & 0x001f) << 3; // R | |
214 } | |
215 p++; // skip black pixel for filters | |
216 p++; // skip black pixel for filters | |
217 p -= 2 * (w + 2); | |
218 fwrite(writeBuffer, 1, 3 * w, fp); | |
219 | |
220 b = writeBuffer; | |
221 } | |
222 break; | |
223 } | |
224 case 24: | |
225 { | |
226 u8 *pixU8 = (u8 *)pix + 3 * w * (h - 1); | |
227 for (int y = 0; y < sizeY; y++) | |
228 { | |
229 for (int x = 0; x < sizeX; x++) | |
230 { | |
231 if (systemRedShift > systemBlueShift) | |
232 { | |
233 *b++ = *pixU8++; // B | |
234 *b++ = *pixU8++; // G | |
235 *b++ = *pixU8++; // R | |
236 } | |
237 else | |
238 { | |
239 int red = *pixU8++; | |
240 int green = *pixU8++; | |
241 int blue = *pixU8++; | |
242 | |
243 *b++ = blue; | |
244 *b++ = green; | |
245 *b++ = red; | |
246 } | |
247 } | |
248 pixU8 -= 2 * 3 * w; | |
249 fwrite(writeBuffer, 1, 3 * w, fp); | |
250 | |
251 b = writeBuffer; | |
252 } | |
253 break; | |
254 } | |
255 case 32: | |
256 { | |
257 u32 *pixU32 = (u32 *)(pix + 4 * (w + 1) * (h)); | |
258 for (int y = 0; y < sizeY; y++) | |
259 { | |
260 for (int x = 0; x < sizeX; x++) | |
261 { | |
262 u32 v = *pixU32++; | |
263 | |
264 *b++ = ((v >> systemBlueShift) & 0x001f) << 3; // B | |
265 *b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G | |
266 *b++ = ((v >> systemRedShift) & 0x001f) << 3; // R | |
267 } | |
268 pixU32++; | |
269 pixU32 -= 2 * (w + 1); | |
270 | |
271 fwrite(writeBuffer, 1, 3 * w, fp); | |
272 | |
273 b = writeBuffer; | |
274 } | |
275 break; | |
276 } | |
277 } | |
278 #endif | |
279 | |
280 fclose(fp); | |
281 | |
282 return true; | |
283 } | |
284 | |
285 bool utilWritePNGFile(const char *fileName, int w, int h, u8 *pix) | |
286 { | |
287 u8 writeBuffer[256 * 3]; | |
288 | |
289 FILE *fp = fopen(fileName, "wb"); | |
290 | |
291 if (!fp) | |
292 { | |
293 systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), fileName); | |
294 return false; | |
295 } | |
296 | |
297 png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, | |
298 NULL, | |
299 NULL, | |
300 NULL); | |
301 if (!png_ptr) | |
302 { | |
303 fclose(fp); | |
304 return false; | |
305 } | |
306 | |
307 png_infop info_ptr = png_create_info_struct(png_ptr); | |
308 | |
309 if (!info_ptr) | |
310 { | |
311 png_destroy_write_struct(&png_ptr, NULL); | |
312 fclose(fp); | |
313 return false; | |
314 } | |
315 | |
316 if (setjmp(png_ptr->jmpbuf)) | |
317 { | |
318 png_destroy_write_struct(&png_ptr, NULL); | |
319 fclose(fp); | |
320 return false; | |
321 } | |
322 | |
323 png_init_io(png_ptr, fp); | |
324 | |
325 png_set_IHDR(png_ptr, | |
326 info_ptr, | |
327 w, | |
328 h, | |
329 8, | |
330 PNG_COLOR_TYPE_RGB, | |
331 PNG_INTERLACE_NONE, | |
332 PNG_COMPRESSION_TYPE_DEFAULT, | |
333 PNG_FILTER_TYPE_DEFAULT); | |
334 | |
335 png_write_info(png_ptr, info_ptr); | |
336 | |
337 u8 *b = writeBuffer; | |
338 | |
339 int sizeX = w; | |
340 int sizeY = h; | |
341 | |
342 switch (systemColorDepth) | |
343 { | |
344 case 16: | |
345 { | |
346 u16 *p = (u16 *)(pix + (w + 2) * 2); // skip first black line | |
347 for (int y = 0; y < sizeY; y++) | |
348 { | |
349 for (int x = 0; x < sizeX; x++) | |
350 { | |
351 u16 v = *p++; | |
352 | |
353 *b++ = ((v >> systemRedShift) & 0x001f) << 3; // R | |
354 *b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G | |
355 *b++ = ((v >> systemBlueShift) & 0x01f) << 3; // B | |
356 } | |
357 p++; // skip black pixel for filters | |
358 p++; // skip black pixel for filters | |
359 png_write_row(png_ptr, writeBuffer); | |
360 | |
361 b = writeBuffer; | |
362 } | |
363 break; | |
364 } | |
365 case 24: | |
366 { | |
367 u8 *pixU8 = (u8 *)pix; | |
368 for (int y = 0; y < sizeY; y++) | |
369 { | |
370 for (int x = 0; x < sizeX; x++) | |
371 { | |
372 if (systemRedShift < systemBlueShift) | |
373 { | |
374 *b++ = *pixU8++; // R | |
375 *b++ = *pixU8++; // G | |
376 *b++ = *pixU8++; // B | |
377 } | |
378 else | |
379 { | |
380 int blue = *pixU8++; | |
381 int green = *pixU8++; | |
382 int red = *pixU8++; | |
383 | |
384 *b++ = red; | |
385 *b++ = green; | |
386 *b++ = blue; | |
387 } | |
388 } | |
389 png_write_row(png_ptr, writeBuffer); | |
390 | |
391 b = writeBuffer; | |
392 } | |
393 break; | |
394 } | |
395 case 32: | |
396 { | |
397 u32 *pixU32 = (u32 *)(pix + 4 * (w + 1)); | |
398 for (int y = 0; y < sizeY; y++) | |
399 { | |
400 for (int x = 0; x < sizeX; x++) | |
401 { | |
402 u32 v = *pixU32++; | |
403 | |
404 *b++ = ((v >> systemRedShift) & 0x001f) << 3; // R | |
405 *b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G | |
406 *b++ = ((v >> systemBlueShift) & 0x001f) << 3; // B | |
407 } | |
408 pixU32++; | |
409 | |
410 png_write_row(png_ptr, writeBuffer); | |
411 | |
412 b = writeBuffer; | |
413 } | |
414 break; | |
415 } | |
416 } | |
417 | |
418 png_write_end(png_ptr, info_ptr); | |
419 | |
420 png_destroy_write_struct(&png_ptr, &info_ptr); | |
421 | |
422 fclose(fp); | |
423 | |
424 return true; | |
425 } | |
426 | |
427 static int utilReadInt2(FILE *f) | |
428 { | |
429 int res = 0; | |
430 int c = fgetc(f); | |
431 if (c == EOF) | |
432 return -1; | |
433 res = c; | |
434 c = fgetc(f); | |
435 if (c == EOF) | |
436 return -1; | |
437 return c + (res << 8); | |
438 } | |
439 | |
440 static int utilReadInt3(FILE *f) | |
441 { | |
442 int res = 0; | |
443 int c = fgetc(f); | |
444 if (c == EOF) | |
445 return -1; | |
446 res = c; | |
447 c = fgetc(f); | |
448 if (c == EOF) | |
449 return -1; | |
450 res = c + (res << 8); | |
451 c = fgetc(f); | |
452 if (c == EOF) | |
453 return -1; | |
454 return c + (res << 8); | |
455 } | |
456 | |
457 void utilApplyIPS(const char *ips, u8 * *r, int *s) | |
458 { | |
459 // from the IPS spec at http://zerosoft.zophar.net/ips.htm | |
460 FILE *f = fopen(ips, "rb"); | |
461 if (!f) | |
462 return; | |
463 u8 *rom = *r; | |
464 int size = *s; | |
465 if (fgetc(f) == 'P' && | |
466 fgetc(f) == 'A' && | |
467 fgetc(f) == 'T' && | |
468 fgetc(f) == 'C' && | |
469 fgetc(f) == 'H') | |
470 { | |
471 int b; | |
472 int offset; | |
473 int len; | |
474 for (;; ) | |
475 { | |
476 // read offset | |
477 offset = utilReadInt3(f); | |
478 // if offset == EOF, end of patch | |
479 if (offset == 0x454f46) | |
480 break; | |
481 // read length | |
482 len = utilReadInt2(f); | |
483 if (!len) | |
484 { | |
485 // len == 0, RLE block | |
486 len = utilReadInt2(f); | |
487 // byte to fill | |
488 int c = fgetc(f); | |
489 if (c == -1) | |
490 break; | |
491 b = (u8)c; | |
492 } | |
493 else | |
494 b = -1; | |
495 // check if we need to reallocate our ROM | |
496 if ((offset + len) >= size) | |
497 { | |
498 size *= 2; | |
499 rom = (u8 *)realloc(rom, size); | |
500 *r = rom; | |
501 *s = size; | |
502 } | |
503 if (b == -1) | |
504 { | |
505 // normal block, just read the data | |
506 if (fread(&rom[offset], 1, len, f) != (size_t)len) | |
507 break; | |
508 } | |
509 else | |
510 { | |
511 // fill the region with the given byte | |
512 while (len--) | |
513 { | |
514 rom[offset++] = b; | |
515 } | |
516 } | |
517 } | |
518 } | |
519 // close the file | |
520 fclose(f); | |
521 } | |
522 | |
523 extern bool8 cpuIsMultiBoot; | |
524 | |
525 bool utilIsGBAImage(const char *file) | |
526 { | |
527 cpuIsMultiBoot = false; | |
528 if (strlen(file) > 4) | |
529 { | |
530 const char *p = strrchr(file, '.'); | |
531 | |
532 if (p != NULL) | |
533 { | |
534 if (_stricmp(p, ".gba") == 0) | |
535 return true; | |
536 if (_stricmp(p, ".agb") == 0) | |
537 return true; | |
538 if (_stricmp(p, ".bin") == 0) | |
539 return true; | |
540 if (_stricmp(p, ".elf") == 0) | |
541 return true; | |
542 if (_stricmp(p, ".mb") == 0) | |
543 { | |
544 cpuIsMultiBoot = true; | |
545 return true; | |
546 } | |
547 } | |
548 } | |
549 | |
550 return false; | |
551 } | |
552 | |
553 bool utilIsGBImage(const char *file) | |
554 { | |
555 if (strlen(file) > 4) | |
556 { | |
557 const char *p = strrchr(file, '.'); | |
558 | |
559 if (p != NULL) | |
560 { | |
561 if (_stricmp(p, ".gb") == 0) | |
562 return true; | |
563 if (_stricmp(p, ".gbc") == 0) | |
564 return true; | |
565 if (_stricmp(p, ".cgb") == 0) | |
566 return true; | |
567 if (_stricmp(p, ".sgb") == 0) | |
568 return true; | |
569 } | |
570 } | |
571 | |
572 return false; | |
573 } | |
574 | |
575 bool utilIsGBABios(const char *file) | |
576 { | |
577 if (strlen(file) > 4) | |
578 { | |
579 const char *p = strrchr(file, '.'); | |
580 | |
581 if (p != NULL) | |
582 { | |
583 if (_stricmp(p, ".gba") == 0) | |
584 return true; | |
585 if (_stricmp(p, ".agb") == 0) | |
586 return true; | |
587 if (_stricmp(p, ".bin") == 0) | |
588 return true; | |
589 if (_stricmp(p, ".bios") == 0) | |
590 return true; | |
591 if (_stricmp(p, ".rom") == 0) | |
592 return true; | |
593 } | |
594 } | |
595 | |
596 return false; | |
597 } | |
598 | |
599 bool utilIsGBBios(const char *file) | |
600 { | |
601 if (strlen(file) > 4) | |
602 { | |
603 const char *p = strrchr(file, '.'); | |
604 | |
605 if (p != NULL) | |
606 { | |
607 if (_stricmp(p, ".gb") == 0) | |
608 return true; | |
609 if (_stricmp(p, ".bin") == 0) | |
610 return true; | |
611 if (_stricmp(p, ".bios") == 0) | |
612 return true; | |
613 if (_stricmp(p, ".rom") == 0) | |
614 return true; | |
615 } | |
616 } | |
617 | |
618 return false; | |
619 } | |
620 | |
621 bool utilIsELF(const char *file) | |
622 { | |
623 if (strlen(file) > 4) | |
624 { | |
625 const char *p = strrchr(file, '.'); | |
626 | |
627 if (p != NULL) | |
628 { | |
629 if (_stricmp(p, ".elf") == 0) | |
630 return true; | |
631 } | |
632 } | |
633 return false; | |
634 } | |
635 | |
636 bool utilIsZipFile(const char *file) | |
637 { | |
638 if (strlen(file) > 4) | |
639 { | |
640 const char *p = strrchr(file, '.'); | |
641 | |
642 if (p != NULL) | |
643 { | |
644 if (_stricmp(p, ".zip") == 0) | |
645 return true; | |
646 } | |
647 } | |
648 | |
649 return false; | |
650 } | |
651 | |
652 #if 0 | |
653 bool utilIsRarFile(const char *file) | |
654 { | |
655 if (strlen(file) > 4) | |
656 { | |
657 char *p = strrchr(file, '.'); | |
658 | |
659 if (p != NULL) | |
660 { | |
661 if (_stricmp(p, ".rar") == 0) | |
662 return true; | |
663 } | |
664 } | |
665 | |
666 return false; | |
667 } | |
668 | |
669 #endif | |
670 | |
671 bool utilIsGzipFile(const char *file) | |
672 { | |
673 if (strlen(file) > 3) | |
674 { | |
675 const char *p = strrchr(file, '.'); | |
676 | |
677 if (p != NULL) | |
678 { | |
679 if (_stricmp(p, ".gz") == 0) | |
680 return true; | |
681 if (_stricmp(p, ".z") == 0) | |
682 return true; | |
683 } | |
684 } | |
685 | |
686 return false; | |
687 } | |
688 | |
689 void utilGetBaseName(const char *file, char *buffer) | |
690 { | |
691 strcpy(buffer, file); | |
692 | |
693 if (utilIsGzipFile(file)) | |
694 { | |
695 char *p = strrchr(buffer, '.'); | |
696 | |
697 if (p) | |
698 *p = 0; | |
699 } | |
700 } | |
701 | |
702 IMAGE_TYPE utilFindType(const char *file) | |
703 { | |
704 char buffer[2048]; | |
705 | |
706 if (utilIsZipFile(file)) | |
707 { | |
708 unzFile unz = unzOpen(file); | |
709 | |
710 if (unz == NULL) | |
711 { | |
712 systemMessage(MSG_CANNOT_OPEN_FILE, N_("Cannot open file %s"), file); | |
713 return IMAGE_UNKNOWN; | |
714 } | |
715 | |
716 int r = unzGoToFirstFile(unz); | |
717 | |
718 if (r != UNZ_OK) | |
719 { | |
720 unzClose(unz); | |
721 systemMessage(MSG_BAD_ZIP_FILE, N_("Bad ZIP file %s"), file); | |
722 return IMAGE_UNKNOWN; | |
723 } | |
724 | |
725 IMAGE_TYPE found = IMAGE_UNKNOWN; | |
726 | |
727 unz_file_info info; | |
728 | |
729 while (true) | |
730 { | |
731 r = unzGetCurrentFileInfo(unz, | |
732 &info, | |
733 buffer, | |
734 sizeof(buffer), | |
735 NULL, | |
736 0, | |
737 NULL, | |
738 0); | |
739 | |
740 if (r != UNZ_OK) | |
741 { | |
742 unzClose(unz); | |
743 systemMessage(MSG_BAD_ZIP_FILE, N_("Bad ZIP file %s"), file); | |
744 return IMAGE_UNKNOWN; | |
745 } | |
746 | |
747 if (utilIsGBAImage(buffer)) | |
748 { | |
749 found = IMAGE_GBA; | |
750 break; | |
751 } | |
752 | |
753 if (utilIsGBImage(buffer)) | |
754 { | |
755 found = IMAGE_GB; | |
756 break; | |
757 } | |
758 | |
759 r = unzGoToNextFile(unz); | |
760 | |
761 if (r != UNZ_OK) | |
762 break; | |
763 } | |
764 unzClose(unz); | |
765 | |
766 if (found == IMAGE_UNKNOWN) | |
767 { | |
768 systemMessage(MSG_NO_IMAGE_ON_ZIP, | |
769 N_("No image found on ZIP file %s"), file); | |
770 return found; | |
771 } | |
772 return found; | |
773 #if 0 | |
774 } | |
775 else if (utilIsRarFile(file)) | |
776 { | |
777 IMAGE_TYPE found = IMAGE_UNKNOWN; | |
778 | |
779 ArchiveList_struct *rarList = NULL; | |
780 if (urarlib_list((void *)file, (ArchiveList_struct *)&rarList)) | |
781 { | |
782 ArchiveList_struct *p = rarList; | |
783 | |
784 while (p) | |
785 { | |
786 if (utilIsGBAImage(p->item.Name)) | |
787 { | |
788 found = IMAGE_GBA; | |
789 break; | |
790 } | |
791 | |
792 if (utilIsGBImage(p->item.Name)) | |
793 { | |
794 found = IMAGE_GB; | |
795 break; | |
796 } | |
797 p = p->next; | |
798 } | |
799 | |
800 urarlib_freelist(rarList); | |
801 } | |
802 return found; | |
803 #endif | |
804 } | |
805 else | |
806 { | |
807 if (utilIsGzipFile(file)) | |
808 utilGetBaseName(file, buffer); | |
809 else | |
810 strcpy(buffer, file); | |
811 | |
812 if (utilIsGBAImage(buffer)) | |
813 return IMAGE_GBA; | |
814 if (utilIsGBImage(buffer)) | |
815 return IMAGE_GB; | |
816 } | |
817 return IMAGE_UNKNOWN; | |
818 } | |
819 | |
820 static int utilGetSize(int size) | |
821 { | |
822 int res = 1; | |
823 while (res < size) | |
824 res <<= 1; | |
825 return res; | |
826 } | |
827 | |
828 static u8 *utilLoadFromZip(const char *file, | |
829 bool (*accept)(const char *), | |
830 u8 *data, | |
831 int &size) | |
832 { | |
833 char buffer[2048]; | |
834 | |
835 unzFile unz = unzOpen(file); | |
836 | |
837 if (unz == NULL) | |
838 { | |
839 systemMessage(MSG_CANNOT_OPEN_FILE, N_("Cannot open file %s"), file); | |
840 return NULL; | |
841 } | |
842 int r = unzGoToFirstFile(unz); | |
843 | |
844 if (r != UNZ_OK) | |
845 { | |
846 unzClose(unz); | |
847 systemMessage(MSG_BAD_ZIP_FILE, N_("Bad ZIP file %s"), file); | |
848 return NULL; | |
849 } | |
850 | |
851 bool found = false; | |
852 | |
853 unz_file_info info; | |
854 | |
855 while (true) | |
856 { | |
857 r = unzGetCurrentFileInfo(unz, | |
858 &info, | |
859 buffer, | |
860 sizeof(buffer), | |
861 NULL, | |
862 0, | |
863 NULL, | |
864 0); | |
865 | |
866 if (r != UNZ_OK) | |
867 { | |
868 unzClose(unz); | |
869 systemMessage(MSG_BAD_ZIP_FILE, N_("Bad ZIP file %s"), file); | |
870 return NULL; | |
871 } | |
872 | |
873 if (accept(buffer)) | |
874 { | |
875 found = true; | |
876 break; | |
877 } | |
878 | |
879 r = unzGoToNextFile(unz); | |
880 | |
881 if (r != UNZ_OK) | |
882 break; | |
883 } | |
884 | |
885 if (!found) | |
886 { | |
887 unzClose(unz); | |
888 systemMessage(MSG_NO_IMAGE_ON_ZIP, | |
889 N_("No image found on ZIP file %s"), file); | |
890 return NULL; | |
891 } | |
892 | |
893 int fileSize = info.uncompressed_size; | |
894 if (size == 0) | |
895 size = fileSize; | |
896 r = unzOpenCurrentFile(unz); | |
897 | |
898 if (r != UNZ_OK) | |
899 { | |
900 unzClose(unz); | |
901 systemMessage(MSG_ERROR_OPENING_IMAGE, N_("Error opening image %s"), buffer); | |
902 return NULL; | |
903 } | |
904 | |
905 u8 *image = data; | |
906 | |
907 if (image == NULL) | |
908 { | |
909 image = (u8 *)malloc(utilGetSize(size)); | |
910 if (image == NULL) | |
911 { | |
912 unzCloseCurrentFile(unz); | |
913 unzClose(unz); | |
914 systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), | |
915 "data"); | |
916 return NULL; | |
917 } | |
918 size = fileSize; | |
919 } | |
920 int read = fileSize <= size ? fileSize : size; | |
921 r = unzReadCurrentFile(unz, | |
922 image, | |
923 read); | |
924 | |
925 unzCloseCurrentFile(unz); | |
926 unzClose(unz); | |
927 | |
928 if (r != (int)read) | |
929 { | |
930 systemMessage(MSG_ERROR_READING_IMAGE, | |
931 N_("Error reading image %s"), buffer); | |
932 if (data == NULL) | |
933 free(image); | |
934 return NULL; | |
935 } | |
936 | |
937 size = fileSize; | |
938 | |
939 return image; | |
940 } | |
941 | |
942 static u8 *utilLoadGzipFile(const char *file, | |
943 bool (*accept)(const char *), | |
944 u8 *data, | |
945 int &size) | |
946 { | |
947 FILE *f = fopen(file, "rb"); | |
948 | |
949 if (f == NULL) | |
950 { | |
951 systemMessage(MSG_ERROR_OPENING_IMAGE, N_("Error opening image %s"), file); | |
952 return NULL; | |
953 } | |
954 | |
955 fseek(f, -4, SEEK_END); | |
956 int fileSize = fgetc(f) | (fgetc(f) << 8) | (fgetc(f) << 16) | (fgetc(f) << 24); | |
957 fclose(f); | |
958 if (size == 0) | |
959 size = fileSize; | |
960 | |
961 gzFile gz = gzopen(file, "rb"); | |
962 | |
963 if (gz == NULL) | |
964 { | |
965 // should not happen, but who knows? | |
966 systemMessage(MSG_ERROR_OPENING_IMAGE, N_("Error opening image %s"), file); | |
967 return NULL; | |
968 } | |
969 | |
970 u8 *image = data; | |
971 | |
972 if (image == NULL) | |
973 { | |
974 image = (u8 *)malloc(utilGetSize(size)); | |
975 if (image == NULL) | |
976 { | |
977 systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), | |
978 "data"); | |
979 fclose(f); | |
980 return NULL; | |
981 } | |
982 size = fileSize; | |
983 } | |
984 int read = fileSize <= size ? fileSize : size; | |
985 int r = gzread(gz, image, read); | |
986 gzclose(gz); | |
987 | |
988 if (r != (int)read) | |
989 { | |
990 systemMessage(MSG_ERROR_READING_IMAGE, | |
991 N_("Error reading image %s"), file); | |
992 if (data == NULL) | |
993 free(image); | |
994 return NULL; | |
995 } | |
996 | |
997 size = fileSize; | |
998 | |
999 return image; | |
1000 } | |
1001 | |
1002 #if 0 | |
1003 static u8 *utilLoadRarFile(const char *file, | |
1004 bool (*accept)(const char *), | |
1005 u8 *data, | |
1006 int &size) | |
1007 { | |
1008 char buffer[2048]; | |
1009 | |
1010 ArchiveList_struct *rarList = NULL; | |
1011 if (urarlib_list((void *)file, (ArchiveList_struct *)&rarList)) | |
1012 { | |
1013 ArchiveList_struct *p = rarList; | |
1014 | |
1015 bool found = false; | |
1016 while (p) | |
1017 { | |
1018 if (accept(p->item.Name)) | |
1019 { | |
1020 strcpy(buffer, p->item.Name); | |
1021 found = true; | |
1022 break; | |
1023 } | |
1024 p = p->next; | |
1025 } | |
1026 if (found) | |
1027 { | |
1028 void *memory = NULL; | |
1029 unsigned long lsize = 0; | |
1030 size = p->item.UnpSize; | |
1031 int r = urarlib_get((void *)&memory, &lsize, buffer, (void *)file, ""); | |
1032 if (!r) | |
1033 { | |
1034 systemMessage(MSG_ERROR_READING_IMAGE, | |
1035 N_("Error reading image %s"), buffer); | |
1036 urarlib_freelist(rarList); | |
1037 return NULL; | |
1038 } | |
1039 u8 *image = (u8 *)memory; | |
1040 if (data != NULL) | |
1041 { | |
1042 memcpy(image, data, size); | |
1043 } | |
1044 urarlib_freelist(rarList); | |
1045 return image; | |
1046 } | |
1047 systemMessage(MSG_NO_IMAGE_ON_ZIP, | |
1048 N_("No image found on RAR file %s"), file); | |
1049 urarlib_freelist(rarList); | |
1050 return NULL; | |
1051 } | |
1052 // nothing found | |
1053 return NULL; | |
1054 } | |
1055 | |
1056 #endif | |
1057 | |
1058 // the caller is responsible for caling free(return value) to release the memory | |
1059 u8 *utilLoad(const char *file, | |
1060 bool (*accept)(const char *), | |
1061 u8 *data, | |
1062 int &size) | |
1063 { | |
1064 if (utilIsZipFile(file)) | |
1065 { | |
1066 return utilLoadFromZip(file, accept, data, size); | |
1067 } | |
1068 if (utilIsGzipFile(file)) | |
1069 { | |
1070 return utilLoadGzipFile(file, accept, data, size); | |
1071 } | |
1072 #if 0 | |
1073 if (utilIsRarFile(file)) | |
1074 { | |
1075 return utilLoadRarFile(file, accept, data, size); | |
1076 } | |
1077 #endif | |
1078 | |
1079 u8 *image = data; | |
1080 | |
1081 FILE *f = fopen(file, "rb"); | |
1082 | |
1083 if (!f) | |
1084 { | |
1085 systemMessage(MSG_ERROR_OPENING_IMAGE, N_("Error opening image %s"), file); | |
1086 return NULL; | |
1087 } | |
1088 | |
1089 fseek(f, 0, SEEK_END); | |
1090 int fileSize = ftell(f); | |
1091 fseek(f, 0, SEEK_SET); | |
1092 if (size == 0) | |
1093 size = fileSize; | |
1094 | |
1095 if (image == NULL) | |
1096 { | |
1097 image = (u8 *)malloc(utilGetSize(size)); | |
1098 if (image == NULL) | |
1099 { | |
1100 systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), | |
1101 "data"); | |
1102 fclose(f); | |
1103 return NULL; | |
1104 } | |
1105 size = fileSize; | |
1106 } | |
1107 int read = fileSize <= size ? fileSize : size; | |
1108 int r = fread(image, 1, read, f); | |
1109 fclose(f); | |
1110 | |
1111 if (r != (int)read) | |
1112 { | |
1113 systemMessage(MSG_ERROR_READING_IMAGE, | |
1114 N_("Error reading image %s"), file); | |
1115 if (data == NULL) | |
1116 free(image); | |
1117 return NULL; | |
1118 } | |
1119 | |
1120 size = fileSize; | |
1121 | |
1122 return image; | |
1123 } | |
1124 | |
1125 void utilWriteInt(gzFile gzFile, int32 i) | |
1126 { | |
1127 utilGzWrite(gzFile, &i, sizeof(int32)); | |
1128 } | |
1129 | |
1130 int32 utilReadInt(gzFile gzFile) | |
1131 { | |
1132 int32 i = 0; | |
1133 utilGzRead(gzFile, &i, sizeof(int32)); | |
1134 return i; | |
1135 } | |
1136 | |
1137 void utilReadData(gzFile gzFile, variable_desc *data) | |
1138 { | |
1139 while (data->address) | |
1140 { | |
1141 utilGzRead(gzFile, data->address, data->size); | |
1142 data++; | |
1143 } | |
1144 } | |
1145 | |
1146 void utilWriteData(gzFile gzFile, variable_desc *data) | |
1147 { | |
1148 while (data->address) | |
1149 { | |
1150 utilGzWrite(gzFile, data->address, data->size); | |
1151 data++; | |
1152 } | |
1153 } | |
1154 | |
1155 gzFile utilGzOpen(const char *file, const char *mode) | |
1156 { | |
1157 utilGzWriteFunc = gzWrite; | |
1158 utilGzReadFunc = gzread; | |
1159 utilGzCloseFunc = gzclose; | |
1160 utilGzSeekFunc = gzseek; | |
1161 utilGzTellFunc = gztell; | |
1162 | |
1163 return gzopen(file, mode); | |
1164 } | |
1165 | |
1166 gzFile utilGzReopen(int id, const char *mode) | |
1167 { | |
1168 utilGzWriteFunc = gzWrite; | |
1169 utilGzReadFunc = gzread; | |
1170 utilGzCloseFunc = gzclose; | |
1171 utilGzSeekFunc = gzseek; | |
1172 utilGzTellFunc = gztell; | |
1173 | |
1174 return gzdopen(id, mode); | |
1175 } | |
1176 | |
1177 gzFile utilMemGzOpen(char *memory, int available, char *mode) | |
1178 { | |
1179 utilGzWriteFunc = memgzwrite; | |
1180 utilGzReadFunc = memgzread; | |
1181 utilGzCloseFunc = memgzclose; | |
1182 utilGzSeekFunc = NULL; // FIXME: not implemented... | |
1183 utilGzTellFunc = memtell; | |
1184 | |
1185 return memgzopen(memory, available, mode); | |
1186 } | |
1187 | |
1188 int utilGzWrite(gzFile file, voidp buffer, unsigned int len) | |
1189 { | |
1190 return utilGzWriteFunc(file, buffer, len); | |
1191 } | |
1192 | |
1193 int utilGzRead(gzFile file, voidp buffer, unsigned int len) | |
1194 { | |
1195 return utilGzReadFunc(file, buffer, len); | |
1196 } | |
1197 | |
1198 int utilGzClose(gzFile file) | |
1199 { | |
1200 return utilGzCloseFunc(file); | |
1201 } | |
1202 | |
1203 z_off_t utilGzSeek(gzFile file, z_off_t offset, int whence) | |
1204 { | |
1205 return utilGzSeekFunc(file, offset, whence); | |
1206 } | |
1207 | |
1208 z_off_t utilGzTell(gzFile file) | |
1209 { | |
1210 return utilGzTellFunc(file); | |
1211 } | |
1212 | |
1213 void utilGBAFindSave(const u8 *data, const int size) | |
1214 { | |
1215 u32 *p = (u32 *)data; | |
1216 u32 *end = (u32 *)(data + size); | |
1217 int saveType = 0; | |
1218 int flashSize = 0x10000; | |
1219 bool rtcFound = false; | |
1220 | |
1221 while (p < end) | |
1222 { | |
1223 u32 d = READ32LE(p); | |
1224 | |
1225 if (d == 0x52504545) | |
1226 { | |
1227 if (memcmp(p, "EEPROM_", 7) == 0) | |
1228 { | |
1229 if (saveType == 0) | |
1230 saveType = 1; | |
1231 } | |
1232 } | |
1233 else if (d == 0x4D415253) | |
1234 { | |
1235 if (memcmp(p, "SRAM_", 5) == 0) | |
1236 { | |
1237 if (saveType == 0) | |
1238 saveType = 2; | |
1239 } | |
1240 } | |
1241 else if (d == 0x53414C46) | |
1242 { | |
1243 if (memcmp(p, "FLASH1M_", 8) == 0) | |
1244 { | |
1245 if (saveType == 0) | |
1246 { | |
1247 saveType = 3; | |
1248 flashSize = 0x20000; | |
1249 } | |
1250 } | |
1251 else if (memcmp(p, "FLASH", 5) == 0) | |
1252 { | |
1253 if (saveType == 0) | |
1254 { | |
1255 saveType = 3; | |
1256 flashSize = 0x10000; | |
1257 } | |
1258 } | |
1259 } | |
1260 else if (d == 0x52494953) | |
1261 { | |
1262 if (memcmp(p, "SIIRTC_V", 8) == 0) | |
1263 rtcFound = true; | |
1264 } | |
1265 p++; | |
1266 } | |
1267 // if no matches found, then set it to NONE | |
1268 if (saveType == 0) | |
1269 { | |
1270 saveType = 5; | |
1271 } | |
1272 rtcEnable(rtcFound); | |
1273 cpuSaveType = saveType; | |
1274 flashSetSize(flashSize); | |
1275 } | |
1276 | |
1277 void utilUpdateSystemColorMaps() | |
1278 { | |
1279 switch (systemColorDepth) | |
1280 { | |
1281 case 16: | |
1282 { | |
1283 for (int i = 0; i < 0x10000; i++) | |
1284 { | |
1285 systemColorMap16[i] = ((i & 0x1f) << systemRedShift) | | |
1286 (((i & 0x3e0) >> 5) << systemGreenShift) | | |
1287 (((i & 0x7c00) >> 10) << systemBlueShift); | |
1288 } | |
1289 break; | |
1290 } | |
1291 case 24: | |
1292 case 32: | |
1293 { | |
1294 for (int i = 0; i < 0x10000; i++) | |
1295 { | |
1296 systemColorMap32[i] = ((i & 0x1f) << systemRedShift) | | |
1297 (((i & 0x3e0) >> 5) << systemGreenShift) | | |
1298 (((i & 0x7c00) >> 10) << systemBlueShift); | |
1299 } | |
1300 break; | |
1301 } | |
1302 } | |
1303 } | |
1304 | |
1305 //// BIOS stuff | |
1306 // systemType uses the same enum values as gbEmulatorType does | |
1307 | |
1308 bool utilLoadBIOS(u8 *bios, const char *biosFileName, int systemType) | |
1309 { | |
1310 if (bios == NULL || strlen(biosFileName) == 0) | |
1311 return false; | |
1312 | |
1313 if (systemType == 4) | |
1314 { | |
1315 int biosSize = 0x4000; | |
1316 if (utilLoad(biosFileName, utilIsGBABios, bios, biosSize)) | |
1317 { | |
1318 if (biosSize == 0x4000) | |
1319 return true; | |
1320 } | |
1321 } | |
1322 else | |
1323 { | |
1324 int biosSize = 0x100; | |
1325 if (utilLoad(biosFileName, utilIsGBBios, bios, biosSize)) | |
1326 { | |
1327 if (biosSize == 0x100) | |
1328 return true; | |
1329 } | |
1330 } | |
1331 | |
1332 return false; | |
1333 } | |
1334 | |
1335 bool utilCheckBIOS(const char *biosFileName, int systemType) | |
1336 { | |
1337 if (strlen(biosFileName) == 0) | |
1338 return false; | |
1339 | |
1340 u8 * tempBIOS = (u8 *)malloc(systemType == 4 ? 0x4000 : 0x100); | |
1341 bool result = utilLoadBIOS(tempBIOS, biosFileName, systemType); | |
1342 free(tempBIOS); | |
1343 | |
1344 return result; | |
1345 } | |
1346 | |
1347 #if 0 | |
1348 // returns the checksum of the BIOS that will be loaded after the next restart | |
1349 u16 utilCalcBIOSChecksum(const u8 *bios, int systemType) | |
1350 { | |
1351 u32 biosChecksum = 0; | |
1352 if (bios) | |
1353 { | |
1354 int biosSize = (systemType == 4 ? 0x4000 : 0x100); | |
1355 const u16 *data = reinterpret_cast<const u16 *>(bios); | |
1356 for (int i = biosSize; i > 0; i -= 2) | |
1357 biosChecksum += *data++; | |
1358 } | |
1359 | |
1360 while ((biosChecksum >> 16) & 0xFFFF) | |
1361 biosChecksum = (biosChecksum &0xFFFF) + ((biosChecksum >> 16) & 0xFFFF); | |
1362 | |
1363 return biosChecksum & 0xFFFF; | |
1364 } | |
1365 #else | |
1366 // returns the checksum of the BIOS that will be loaded after the next restart | |
1367 u16 utilCalcBIOSChecksum(const u8 *bios, int systemType) | |
1368 { | |
1369 u32 biosChecksum = 0; | |
1370 if (bios) | |
1371 { | |
1372 int biosSize = (systemType == 4 ? 0x4000 : 0x100); | |
1373 const u32 *data = reinterpret_cast<const u32 *>(bios); | |
1374 for (int i = biosSize; i > 0; i -= 4) | |
1375 biosChecksum += *data++; | |
1376 } | |
1377 | |
1378 return biosChecksum & 0xFFFF; | |
1379 } | |
1380 #endif | |
1381 | |
1382 // returns the checksum of the BIOS file | |
1383 u16 utilCalcBIOSFileChecksum(const char *biosFileName, int systemType) | |
1384 { | |
1385 if (strlen(biosFileName) == 0) | |
1386 return 0; | |
1387 | |
1388 u16 biosChecksum = 0; | |
1389 const int biosSize = (systemType == 4 ? 0x4000 : 0x100); | |
1390 u8 * tempBIOS = (u8 *)malloc(biosSize); | |
1391 bool hasBIOS = utilLoadBIOS(tempBIOS, biosFileName, systemType); | |
1392 if (hasBIOS) | |
1393 { | |
1394 biosChecksum = utilCalcBIOSChecksum(tempBIOS, systemType); | |
1395 } | |
1396 free(tempBIOS); | |
1397 | |
1398 return biosChecksum; | |
1399 } | |
1400 |