view src/common/Util.cpp @ 450:f04d6368049e

simplified notes
author Robert McIntyre <rlm@mit.edu>
date Thu, 03 May 2012 06:42:58 -0500
parents f94fa48624d0
children a6d060a64246
line wrap: on
line source
1 #include <cstdio>
2 #include <cstdlib>
3 #include <cstring>
4 #include <zlib.h>
6 extern "C" {
7 #include <png.h>
8 }
10 #if 0
11 #include "unrarlib.h"
12 #endif
14 #include "unzip.h"
16 #include "../NLS.h"
17 #include "System.h"
18 #include "Util.h"
19 #include "../gba/Flash.h"
20 #include "../gba/RTC.h"
22 extern "C" {
23 #include "memgzio.h"
24 }
26 #ifndef _MSC_VER
27 #define _stricmp strcasecmp
28 #endif // ! _MSC_VER
30 extern int32 cpuSaveType;
32 extern int systemColorDepth;
33 extern int systemRedShift;
34 extern int systemGreenShift;
35 extern int systemBlueShift;
37 extern u16 systemColorMap16[0x10000];
38 extern u32 systemColorMap32[0x10000];
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;
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 }
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 }
62 void utilPutWord(u8 *p, u16 value)
63 {
64 *p++ = value & 255;
65 *p = (value >> 8) & 255;
66 }
68 void utilWriteBMP(u8 *b, int w, int h, int dstDepth, u8 *pix)
69 {
70 int sizeX = w;
71 int sizeY = h;
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++;
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++;
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++;
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 }
143 bool utilWriteBMPFile(const char *fileName, int w, int h, u8 *pix)
144 {
145 u8 writeBuffer[256 * 3];
147 FILE *fp = fopen(fileName, "wb");
149 if (!fp)
150 {
151 systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), fileName);
152 return false;
153 }
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));
176 bmpheader.ident[0] = 'B';
177 bmpheader.ident[1] = 'M';
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);
189 fwrite(&bmpheader, 1, sizeof(bmpheader), fp);
191 #if 0
192 // FIXME: need sufficient buffer
193 utilWriteBMP(writeBuffer, w, h, systemColorDepth, pix);
194 #else
195 u8 *b = writeBuffer;
197 int sizeX = w;
198 int sizeY = h;
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++;
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);
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++;
243 *b++ = blue;
244 *b++ = green;
245 *b++ = red;
246 }
247 }
248 pixU8 -= 2 * 3 * w;
249 fwrite(writeBuffer, 1, 3 * w, fp);
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++;
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);
271 fwrite(writeBuffer, 1, 3 * w, fp);
273 b = writeBuffer;
274 }
275 break;
276 }
277 }
278 #endif
280 fclose(fp);
282 return true;
283 }
285 bool utilWritePNGFile(const char *fileName, int w, int h, u8 *pix)
286 {
287 u8 writeBuffer[256 * 3];
289 FILE *fp = fopen(fileName, "wb");
291 if (!fp)
292 {
293 systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), fileName);
294 return false;
295 }
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 }
307 png_infop info_ptr = png_create_info_struct(png_ptr);
309 if (!info_ptr)
310 {
311 png_destroy_write_struct(&png_ptr, NULL);
312 fclose(fp);
313 return false;
314 }
316 if (setjmp(png_jmpbuf(png_ptr)))
317 {
318 png_destroy_write_struct(&png_ptr, NULL);
319 fclose(fp);
320 return false;
321 }
323 png_init_io(png_ptr, fp);
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);
335 png_write_info(png_ptr, info_ptr);
337 u8 *b = writeBuffer;
339 int sizeX = w;
340 int sizeY = h;
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++;
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);
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++;
384 *b++ = red;
385 *b++ = green;
386 *b++ = blue;
387 }
388 }
389 png_write_row(png_ptr, writeBuffer);
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++;
404 *b++ = ((v >> systemRedShift) & 0x001f) << 3; // R
405 *b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G
406 *b++ = ((v >> systemBlueShift) & 0x001f) << 3; // B
407 }
408 pixU32++;
410 png_write_row(png_ptr, writeBuffer);
412 b = writeBuffer;
413 }
414 break;
415 }
416 }
418 png_write_end(png_ptr, info_ptr);
420 png_destroy_write_struct(&png_ptr, &info_ptr);
422 fclose(fp);
424 return true;
425 }
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 }
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 }
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 }
523 extern bool8 cpuIsMultiBoot;
525 bool utilIsGBAImage(const char *file)
526 {
527 cpuIsMultiBoot = false;
528 if (strlen(file) > 4)
529 {
530 const char *p = strrchr(file, '.');
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 }
550 return false;
551 }
553 bool utilIsGBImage(const char *file)
554 {
555 if (strlen(file) > 4)
556 {
557 const char *p = strrchr(file, '.');
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 }
572 return false;
573 }
575 bool utilIsGBABios(const char *file)
576 {
577 if (strlen(file) > 4)
578 {
579 const char *p = strrchr(file, '.');
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 }
596 return false;
597 }
599 bool utilIsGBBios(const char *file)
600 {
601 if (strlen(file) > 4)
602 {
603 const char *p = strrchr(file, '.');
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 }
618 return false;
619 }
621 bool utilIsELF(const char *file)
622 {
623 if (strlen(file) > 4)
624 {
625 const char *p = strrchr(file, '.');
627 if (p != NULL)
628 {
629 if (_stricmp(p, ".elf") == 0)
630 return true;
631 }
632 }
633 return false;
634 }
636 bool utilIsZipFile(const char *file)
637 {
638 if (strlen(file) > 4)
639 {
640 const char *p = strrchr(file, '.');
642 if (p != NULL)
643 {
644 if (_stricmp(p, ".zip") == 0)
645 return true;
646 }
647 }
649 return false;
650 }
652 #if 0
653 bool utilIsRarFile(const char *file)
654 {
655 if (strlen(file) > 4)
656 {
657 char *p = strrchr(file, '.');
659 if (p != NULL)
660 {
661 if (_stricmp(p, ".rar") == 0)
662 return true;
663 }
664 }
666 return false;
667 }
669 #endif
671 bool utilIsGzipFile(const char *file)
672 {
673 if (strlen(file) > 3)
674 {
675 const char *p = strrchr(file, '.');
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 }
686 return false;
687 }
689 void utilGetBaseName(const char *file, char *buffer)
690 {
691 strcpy(buffer, file);
693 if (utilIsGzipFile(file))
694 {
695 char *p = strrchr(buffer, '.');
697 if (p)
698 *p = 0;
699 }
700 }
702 IMAGE_TYPE utilFindType(const char *file)
703 {
704 char buffer[2048];
706 if (utilIsZipFile(file))
707 {
708 unzFile unz = unzOpen(file);
710 if (unz == NULL)
711 {
712 systemMessage(MSG_CANNOT_OPEN_FILE, N_("Cannot open file %s"), file);
713 return IMAGE_UNKNOWN;
714 }
716 int r = unzGoToFirstFile(unz);
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 }
725 IMAGE_TYPE found = IMAGE_UNKNOWN;
727 unz_file_info info;
729 while (true)
730 {
731 r = unzGetCurrentFileInfo(unz,
732 &info,
733 buffer,
734 sizeof(buffer),
735 NULL,
736 0,
737 NULL,
738 0);
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 }
747 if (utilIsGBAImage(buffer))
748 {
749 found = IMAGE_GBA;
750 break;
751 }
753 if (utilIsGBImage(buffer))
754 {
755 found = IMAGE_GB;
756 break;
757 }
759 r = unzGoToNextFile(unz);
761 if (r != UNZ_OK)
762 break;
763 }
764 unzClose(unz);
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;
779 ArchiveList_struct *rarList = NULL;
780 if (urarlib_list((void *)file, (ArchiveList_struct *)&rarList))
781 {
782 ArchiveList_struct *p = rarList;
784 while (p)
785 {
786 if (utilIsGBAImage(p->item.Name))
787 {
788 found = IMAGE_GBA;
789 break;
790 }
792 if (utilIsGBImage(p->item.Name))
793 {
794 found = IMAGE_GB;
795 break;
796 }
797 p = p->next;
798 }
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);
812 if (utilIsGBAImage(buffer))
813 return IMAGE_GBA;
814 if (utilIsGBImage(buffer))
815 return IMAGE_GB;
816 }
817 return IMAGE_UNKNOWN;
818 }
820 static int utilGetSize(int size)
821 {
822 int res = 1;
823 while (res < size)
824 res <<= 1;
825 return res;
826 }
828 static u8 *utilLoadFromZip(const char *file,
829 bool (*accept)(const char *),
830 u8 *data,
831 int &size)
832 {
833 char buffer[2048];
835 unzFile unz = unzOpen(file);
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);
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 }
851 bool found = false;
853 unz_file_info info;
855 while (true)
856 {
857 r = unzGetCurrentFileInfo(unz,
858 &info,
859 buffer,
860 sizeof(buffer),
861 NULL,
862 0,
863 NULL,
864 0);
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 }
873 if (accept(buffer))
874 {
875 found = true;
876 break;
877 }
879 r = unzGoToNextFile(unz);
881 if (r != UNZ_OK)
882 break;
883 }
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 }
893 int fileSize = info.uncompressed_size;
894 if (size == 0)
895 size = fileSize;
896 r = unzOpenCurrentFile(unz);
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 }
905 u8 *image = data;
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);
925 unzCloseCurrentFile(unz);
926 unzClose(unz);
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 }
937 size = fileSize;
939 return image;
940 }
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");
949 if (f == NULL)
950 {
951 systemMessage(MSG_ERROR_OPENING_IMAGE, N_("Error opening image %s"), file);
952 return NULL;
953 }
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;
961 gzFile gz = gzopen(file, "rb");
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 }
970 u8 *image = data;
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);
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 }
997 size = fileSize;
999 return image;
1002 #if 0
1003 static u8 *utilLoadRarFile(const char *file,
1004 bool (*accept)(const char *),
1005 u8 *data,
1006 int &size)
1008 char buffer[2048];
1010 ArchiveList_struct *rarList = NULL;
1011 if (urarlib_list((void *)file, (ArchiveList_struct *)&rarList))
1013 ArchiveList_struct *p = rarList;
1015 bool found = false;
1016 while (p)
1018 if (accept(p->item.Name))
1020 strcpy(buffer, p->item.Name);
1021 found = true;
1022 break;
1024 p = p->next;
1026 if (found)
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)
1034 systemMessage(MSG_ERROR_READING_IMAGE,
1035 N_("Error reading image %s"), buffer);
1036 urarlib_freelist(rarList);
1037 return NULL;
1039 u8 *image = (u8 *)memory;
1040 if (data != NULL)
1042 memcpy(image, data, size);
1044 urarlib_freelist(rarList);
1045 return image;
1047 systemMessage(MSG_NO_IMAGE_ON_ZIP,
1048 N_("No image found on RAR file %s"), file);
1049 urarlib_freelist(rarList);
1050 return NULL;
1052 // nothing found
1053 return NULL;
1056 #endif
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)
1064 if (utilIsZipFile(file))
1066 return utilLoadFromZip(file, accept, data, size);
1068 if (utilIsGzipFile(file))
1070 return utilLoadGzipFile(file, accept, data, size);
1072 #if 0
1073 if (utilIsRarFile(file))
1075 return utilLoadRarFile(file, accept, data, size);
1077 #endif
1079 u8 *image = data;
1081 FILE *f = fopen(file, "rb");
1083 if (!f)
1085 systemMessage(MSG_ERROR_OPENING_IMAGE, N_("Error opening image %s"), file);
1086 return NULL;
1089 fseek(f, 0, SEEK_END);
1090 int fileSize = ftell(f);
1091 fseek(f, 0, SEEK_SET);
1092 if (size == 0)
1093 size = fileSize;
1095 if (image == NULL)
1097 image = (u8 *)malloc(utilGetSize(size));
1098 if (image == NULL)
1100 systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"),
1101 "data");
1102 fclose(f);
1103 return NULL;
1105 size = fileSize;
1107 int read = fileSize <= size ? fileSize : size;
1108 int r = fread(image, 1, read, f);
1109 fclose(f);
1111 if (r != (int)read)
1113 systemMessage(MSG_ERROR_READING_IMAGE,
1114 N_("Error reading image %s"), file);
1115 if (data == NULL)
1116 free(image);
1117 return NULL;
1120 size = fileSize;
1122 return image;
1125 void utilWriteInt(gzFile gzFile, int32 i)
1127 utilGzWrite(gzFile, &i, sizeof(int32));
1130 int32 utilReadInt(gzFile gzFile)
1132 int32 i = 0;
1133 utilGzRead(gzFile, &i, sizeof(int32));
1134 return i;
1137 void utilReadData(gzFile gzFile, variable_desc *data)
1139 while (data->address)
1141 utilGzRead(gzFile, data->address, data->size);
1142 data++;
1146 void utilWriteData(gzFile gzFile, variable_desc *data)
1148 while (data->address)
1150 utilGzWrite(gzFile, data->address, data->size);
1151 data++;
1155 gzFile utilGzOpen(const char *file, const char *mode)
1157 utilGzWriteFunc = gzWrite;
1158 utilGzReadFunc = gzread;
1159 utilGzCloseFunc = gzclose;
1160 utilGzSeekFunc = gzseek;
1161 utilGzTellFunc = gztell;
1163 return gzopen(file, mode);
1166 gzFile utilGzReopen(int id, const char *mode)
1168 utilGzWriteFunc = gzWrite;
1169 utilGzReadFunc = gzread;
1170 utilGzCloseFunc = gzclose;
1171 utilGzSeekFunc = gzseek;
1172 utilGzTellFunc = gztell;
1174 return gzdopen(id, mode);
1177 gzFile utilMemGzOpen(char *memory, int available, char *mode)
1179 utilGzWriteFunc = memgzwrite;
1180 utilGzReadFunc = memgzread;
1181 utilGzCloseFunc = memgzclose;
1182 utilGzSeekFunc = NULL; // FIXME: not implemented...
1183 utilGzTellFunc = memtell;
1185 return memgzopen(memory, available, mode);
1188 int utilGzWrite(gzFile file, voidp buffer, unsigned int len)
1190 return utilGzWriteFunc(file, buffer, len);
1193 int utilGzRead(gzFile file, voidp buffer, unsigned int len)
1195 return utilGzReadFunc(file, buffer, len);
1198 int utilGzClose(gzFile file)
1200 return utilGzCloseFunc(file);
1203 z_off_t utilGzSeek(gzFile file, z_off_t offset, int whence)
1205 return utilGzSeekFunc(file, offset, whence);
1208 z_off_t utilGzTell(gzFile file)
1210 return utilGzTellFunc(file);
1213 void utilGBAFindSave(const u8 *data, const int size)
1215 u32 *p = (u32 *)data;
1216 u32 *end = (u32 *)(data + size);
1217 int saveType = 0;
1218 int flashSize = 0x10000;
1219 bool rtcFound = false;
1221 while (p < end)
1223 u32 d = READ32LE(p);
1225 if (d == 0x52504545)
1227 if (memcmp(p, "EEPROM_", 7) == 0)
1229 if (saveType == 0)
1230 saveType = 1;
1233 else if (d == 0x4D415253)
1235 if (memcmp(p, "SRAM_", 5) == 0)
1237 if (saveType == 0)
1238 saveType = 2;
1241 else if (d == 0x53414C46)
1243 if (memcmp(p, "FLASH1M_", 8) == 0)
1245 if (saveType == 0)
1247 saveType = 3;
1248 flashSize = 0x20000;
1251 else if (memcmp(p, "FLASH", 5) == 0)
1253 if (saveType == 0)
1255 saveType = 3;
1256 flashSize = 0x10000;
1260 else if (d == 0x52494953)
1262 if (memcmp(p, "SIIRTC_V", 8) == 0)
1263 rtcFound = true;
1265 p++;
1267 // if no matches found, then set it to NONE
1268 if (saveType == 0)
1270 saveType = 5;
1272 rtcEnable(rtcFound);
1273 cpuSaveType = saveType;
1274 flashSetSize(flashSize);
1277 void utilUpdateSystemColorMaps()
1279 switch (systemColorDepth)
1281 case 16:
1283 for (int i = 0; i < 0x10000; i++)
1285 systemColorMap16[i] = ((i & 0x1f) << systemRedShift) |
1286 (((i & 0x3e0) >> 5) << systemGreenShift) |
1287 (((i & 0x7c00) >> 10) << systemBlueShift);
1289 break;
1291 case 24:
1292 case 32:
1294 for (int i = 0; i < 0x10000; i++)
1296 systemColorMap32[i] = ((i & 0x1f) << systemRedShift) |
1297 (((i & 0x3e0) >> 5) << systemGreenShift) |
1298 (((i & 0x7c00) >> 10) << systemBlueShift);
1300 break;
1305 //// BIOS stuff
1306 // systemType uses the same enum values as gbEmulatorType does
1308 bool utilLoadBIOS(u8 *bios, const char *biosFileName, int systemType)
1310 if (bios == NULL || strlen(biosFileName) == 0)
1311 return false;
1313 if (systemType == 4)
1315 int biosSize = 0x4000;
1316 if (utilLoad(biosFileName, utilIsGBABios, bios, biosSize))
1318 if (biosSize == 0x4000)
1319 return true;
1322 else
1324 int biosSize = 0x100;
1325 if (utilLoad(biosFileName, utilIsGBBios, bios, biosSize))
1327 if (biosSize == 0x100)
1328 return true;
1332 return false;
1335 bool utilCheckBIOS(const char *biosFileName, int systemType)
1337 if (strlen(biosFileName) == 0)
1338 return false;
1340 u8 * tempBIOS = (u8 *)malloc(systemType == 4 ? 0x4000 : 0x100);
1341 bool result = utilLoadBIOS(tempBIOS, biosFileName, systemType);
1342 free(tempBIOS);
1344 return result;
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)
1351 u32 biosChecksum = 0;
1352 if (bios)
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++;
1360 while ((biosChecksum >> 16) & 0xFFFF)
1361 biosChecksum = (biosChecksum &0xFFFF) + ((biosChecksum >> 16) & 0xFFFF);
1363 return biosChecksum & 0xFFFF;
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)
1369 u32 biosChecksum = 0;
1370 if (bios)
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++;
1378 return biosChecksum & 0xFFFF;
1380 #endif
1382 // returns the checksum of the BIOS file
1383 u16 utilCalcBIOSFileChecksum(const char *biosFileName, int systemType)
1385 if (strlen(biosFileName) == 0)
1386 return 0;
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)
1394 biosChecksum = utilCalcBIOSChecksum(tempBIOS, systemType);
1396 free(tempBIOS);
1398 return biosChecksum;