1 // VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
2 // Copyright (C) 1999-2003 Forgotten
3 // Copyright (C) 2004-2006 Forgotten and the VBA development team
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2, or(at your option)
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
43 #define _stricmp strcasecmp
46 extern int systemColorDepth
;
47 extern int systemRedShift
;
48 extern int systemGreenShift
;
49 extern int systemBlueShift
;
51 extern u16 systemColorMap16
[0x10000];
52 extern u32 systemColorMap32
[0x10000];
54 static int (ZEXPORT
*utilGzWriteFunc
)(gzFile
, const voidp
, unsigned int) = NULL
;
55 static int (ZEXPORT
*utilGzReadFunc
)(gzFile
, voidp
, unsigned int) = NULL
;
56 static int (ZEXPORT
*utilGzCloseFunc
)(gzFile
) = NULL
;
58 bool utilWritePNGFile(const char *fileName
, int w
, int h
, u8
*pix
)
60 u8 writeBuffer
[512 * 3];
62 FILE *fp
= fopen(fileName
,"wb");
65 systemMessage(MSG_ERROR_CREATING_FILE
, N_("Error creating file %s"), fileName
);
69 png_structp png_ptr
= png_create_write_struct(PNG_LIBPNG_VER_STRING
,
78 png_infop info_ptr
= png_create_info_struct(png_ptr
);
81 png_destroy_write_struct(&png_ptr
,NULL
);
86 if(setjmp(png_jmpbuf(png_ptr
))) {
87 png_destroy_write_struct(&png_ptr
,NULL
);
92 png_init_io(png_ptr
,fp
);
101 PNG_COMPRESSION_TYPE_DEFAULT
,
102 PNG_FILTER_TYPE_DEFAULT
);
104 png_write_info(png_ptr
,info_ptr
);
111 switch(systemColorDepth
) {
114 u16
*p
= (u16
*)(pix
+(w
+2)*2); // skip first black line
115 for(int y
= 0; y
< sizeY
; y
++) {
116 for(int x
= 0; x
< sizeX
; x
++) {
119 *b
++ = ((v
>> systemRedShift
) & 0x001f) << 3; // R
120 *b
++ = ((v
>> systemGreenShift
) & 0x001f) << 3; // G
121 *b
++ = ((v
>> systemBlueShift
) & 0x01f) << 3; // B
123 p
++; // skip black pixel for filters
124 p
++; // skip black pixel for filters
125 png_write_row(png_ptr
,writeBuffer
);
133 u8
*pixU8
= (u8
*)pix
;
134 for(int y
= 0; y
< sizeY
; y
++) {
135 for(int x
= 0; x
< sizeX
; x
++) {
136 if(systemRedShift
< systemBlueShift
) {
137 *b
++ = *pixU8
++; // R
138 *b
++ = *pixU8
++; // G
139 *b
++ = *pixU8
++; // B
142 int green
= *pixU8
++;
150 png_write_row(png_ptr
,writeBuffer
);
158 u32
*pixU32
= (u32
*)(pix
+4*(w
+1));
159 for(int y
= 0; y
< sizeY
; y
++) {
160 for(int x
= 0; x
< sizeX
; x
++) {
163 *b
++ = ((v
>> systemRedShift
) & 0x001f) << 3; // R
164 *b
++ = ((v
>> systemGreenShift
) & 0x001f) << 3; // G
165 *b
++ = ((v
>> systemBlueShift
) & 0x001f) << 3; // B
169 png_write_row(png_ptr
,writeBuffer
);
177 png_write_end(png_ptr
, info_ptr
);
179 png_destroy_write_struct(&png_ptr
, &info_ptr
);
186 void utilPutDword(u8
*p
, u32 value
)
189 *p
++ = (value
>> 8) & 255;
190 *p
++ = (value
>> 16) & 255;
191 *p
= (value
>> 24) & 255;
194 void utilPutWord(u8
*p
, u16 value
)
197 *p
= (value
>> 8) & 255;
200 void utilWriteBMP(char *buf
, int w
, int h
, u8
*pix
)
207 switch(systemColorDepth
) {
210 u16
*p
= (u16
*)(pix
+(w
+2)*(h
)*2); // skip first black line
211 for(int y
= 0; y
< sizeY
; y
++) {
212 for(int x
= 0; x
< sizeX
; x
++) {
215 *b
++ = ((v
>> systemBlueShift
) & 0x01f) << 3; // B
216 *b
++ = ((v
>> systemGreenShift
) & 0x001f) << 3; // G
217 *b
++ = ((v
>> systemRedShift
) & 0x001f) << 3; // R
219 p
++; // skip black pixel for filters
220 p
++; // skip black pixel for filters
227 u8
*pixU8
= (u8
*)pix
+3*w
*(h
-1);
228 for(int y
= 0; y
< sizeY
; y
++) {
229 for(int x
= 0; x
< sizeX
; x
++) {
230 if(systemRedShift
> systemBlueShift
) {
231 *b
++ = *pixU8
++; // B
232 *b
++ = *pixU8
++; // G
233 *b
++ = *pixU8
++; // R
236 int green
= *pixU8
++;
250 u32
*pixU32
= (u32
*)(pix
+4*(w
+1)*(h
));
251 for(int y
= 0; y
< sizeY
; y
++) {
252 for(int x
= 0; x
< sizeX
; x
++) {
255 *b
++ = ((v
>> systemBlueShift
) & 0x001f) << 3; // B
256 *b
++ = ((v
>> systemGreenShift
) & 0x001f) << 3; // G
257 *b
++ = ((v
>> systemRedShift
) & 0x001f) << 3; // R
267 bool utilWriteBMPFile(const char *fileName
, int w
, int h
, u8
*pix
)
269 u8 writeBuffer
[512 * 3];
271 FILE *fp
= fopen(fileName
,"wb");
274 systemMessage(MSG_ERROR_CREATING_FILE
, N_("Error creating file %s"), fileName
);
293 u8 importantcolors
[4];
296 memset(&bmpheader
, 0, sizeof(bmpheader
));
298 bmpheader
.ident
[0] = 'B';
299 bmpheader
.ident
[1] = 'M';
301 u32 fsz
= sizeof(bmpheader
) + w
*h
*3;
302 utilPutDword(bmpheader
.filesize
, fsz
);
303 utilPutDword(bmpheader
.dataoffset
, 0x36);
304 utilPutDword(bmpheader
.headersize
, 0x28);
305 utilPutDword(bmpheader
.width
, w
);
306 utilPutDword(bmpheader
.height
, h
);
307 utilPutDword(bmpheader
.planes
, 1);
308 utilPutDword(bmpheader
.bitsperpixel
, 24);
309 utilPutDword(bmpheader
.datasize
, 3*w
*h
);
311 fwrite(&bmpheader
, 1, sizeof(bmpheader
), fp
);
318 switch(systemColorDepth
) {
321 u16
*p
= (u16
*)(pix
+(w
+2)*(h
)*2); // skip first black line
322 for(int y
= 0; y
< sizeY
; y
++) {
323 for(int x
= 0; x
< sizeX
; x
++) {
326 *b
++ = ((v
>> systemBlueShift
) & 0x01f) << 3; // B
327 *b
++ = ((v
>> systemGreenShift
) & 0x001f) << 3; // G
328 *b
++ = ((v
>> systemRedShift
) & 0x001f) << 3; // R
330 p
++; // skip black pixel for filters
331 p
++; // skip black pixel for filters
333 fwrite(writeBuffer
, 1, 3*w
, fp
);
341 u8
*pixU8
= (u8
*)pix
+3*w
*(h
-1);
342 for(int y
= 0; y
< sizeY
; y
++) {
343 for(int x
= 0; x
< sizeX
; x
++) {
344 if(systemRedShift
> systemBlueShift
) {
345 *b
++ = *pixU8
++; // B
346 *b
++ = *pixU8
++; // G
347 *b
++ = *pixU8
++; // R
350 int green
= *pixU8
++;
359 fwrite(writeBuffer
, 1, 3*w
, fp
);
367 u32
*pixU32
= (u32
*)(pix
+4*(w
+1)*(h
));
368 for(int y
= 0; y
< sizeY
; y
++) {
369 for(int x
= 0; x
< sizeX
; x
++) {
372 *b
++ = ((v
>> systemBlueShift
) & 0x001f) << 3; // B
373 *b
++ = ((v
>> systemGreenShift
) & 0x001f) << 3; // G
374 *b
++ = ((v
>> systemRedShift
) & 0x001f) << 3; // R
379 fwrite(writeBuffer
, 1, 3*w
, fp
);
392 static int utilReadInt2(FILE *f
)
405 static int utilReadInt3(FILE *f
)
422 void utilApplyIPS(const char *ips
, u8
**r
, int *s
)
424 // from the IPS spec at http://zerosoft.zophar.net/ips.htm
425 FILE *f
= fopen(ips
, "rb");
430 if(fgetc(f
) == 'P' &&
440 offset
= utilReadInt3(f
);
441 // if offset == EOF, end of patch
442 if(offset
== 0x454f46)
445 len
= utilReadInt2(f
);
447 // len == 0, RLE block
448 len
= utilReadInt2(f
);
456 // check if we need to reallocate our ROM
457 if((offset
+ len
) >= size
) {
459 rom
= (u8
*)realloc(rom
, size
);
464 // normal block, just read the data
465 if(fread(&rom
[offset
], 1, len
, f
) != (size_t)len
)
468 // fill the region with the given byte
479 extern bool cpuIsMultiBoot
;
481 bool utilIsGBAImage(const char * file
)
483 cpuIsMultiBoot
= false;
484 if(strlen(file
) > 4) {
485 const char * p
= strrchr(file
,'.');
488 if(_stricmp(p
, ".gba") == 0)
490 if(_stricmp(p
, ".agb") == 0)
492 if(_stricmp(p
, ".bin") == 0)
494 if(_stricmp(p
, ".elf") == 0)
496 if(_stricmp(p
, ".mb") == 0) {
497 cpuIsMultiBoot
= true;
506 bool utilIsGBImage(const char * file
)
508 if(strlen(file
) > 4) {
509 const char * p
= strrchr(file
,'.');
512 if(_stricmp(p
, ".gb") == 0)
514 if(_stricmp(p
, ".gbc") == 0)
516 if(_stricmp(p
, ".cgb") == 0)
518 if(_stricmp(p
, ".sgb") == 0)
526 bool utilIsZipFile(const char *file
)
528 if(strlen(file
) > 4) {
529 const char * p
= strrchr(file
,'.');
532 if(_stricmp(p
, ".zip") == 0)
541 bool utilIsRarFile(const char *file
)
543 if(strlen(file
) > 4) {
544 char * p
= strrchr(file
,'.');
547 if(_stricmp(p
, ".rar") == 0)
556 bool utilIsGzipFile(const char *file
)
558 if(strlen(file
) > 3) {
559 const char * p
= strrchr(file
,'.');
562 if(_stricmp(p
, ".gz") == 0)
564 if(_stricmp(p
, ".z") == 0)
572 void utilGetBaseName(const char *file
, char *buffer
)
574 strcpy(buffer
, file
);
576 if(utilIsGzipFile(file
)) {
577 char *p
= strrchr(buffer
, '.');
584 IMAGE_TYPE
utilFindType(const char *file
)
588 if(utilIsZipFile(file
)) {
589 unzFile unz
= unzOpen(file
);
592 systemMessage(MSG_CANNOT_OPEN_FILE
, N_("Cannot open file %s"), file
);
593 return IMAGE_UNKNOWN
;
596 int r
= unzGoToFirstFile(unz
);
600 systemMessage(MSG_BAD_ZIP_FILE
, N_("Bad ZIP file %s"), file
);
601 return IMAGE_UNKNOWN
;
604 IMAGE_TYPE found
= IMAGE_UNKNOWN
;
609 r
= unzGetCurrentFileInfo(unz
,
620 systemMessage(MSG_BAD_ZIP_FILE
, N_("Bad ZIP file %s"), file
);
621 return IMAGE_UNKNOWN
;
624 if(utilIsGBAImage(buffer
)) {
629 if(utilIsGBImage(buffer
)) {
634 r
= unzGoToNextFile(unz
);
641 if(found
== IMAGE_UNKNOWN
) {
642 systemMessage(MSG_NO_IMAGE_ON_ZIP
,
643 N_("No image found on ZIP file %s"), file
);
648 } else if(utilIsRarFile(file
)) {
649 IMAGE_TYPE found
= IMAGE_UNKNOWN
;
651 ArchiveList_struct
*rarList
= NULL
;
652 if(urarlib_list((void *)file
, (ArchiveList_struct
*)&rarList
)) {
653 ArchiveList_struct
*p
= rarList
;
656 if(utilIsGBAImage(p
->item
.Name
)) {
661 if(utilIsGBImage(p
->item
.Name
)) {
668 urarlib_freelist(rarList
);
673 if(utilIsGzipFile(file
))
674 utilGetBaseName(file
, buffer
);
676 strcpy(buffer
, file
);
678 if(utilIsGBAImage(buffer
))
680 if(utilIsGBImage(buffer
))
683 return IMAGE_UNKNOWN
;
686 static int utilGetSize(int size
)
694 static u8
*utilLoadFromZip(const char *file
,
695 bool (*accept
)(const char *),
701 unzFile unz
= unzOpen(file
);
704 systemMessage(MSG_CANNOT_OPEN_FILE
, N_("Cannot open file %s"), file
);
707 int r
= unzGoToFirstFile(unz
);
711 systemMessage(MSG_BAD_ZIP_FILE
, N_("Bad ZIP file %s"), file
);
720 r
= unzGetCurrentFileInfo(unz
,
731 systemMessage(MSG_BAD_ZIP_FILE
, N_("Bad ZIP file %s"), file
);
740 r
= unzGoToNextFile(unz
);
748 systemMessage(MSG_NO_IMAGE_ON_ZIP
,
749 N_("No image found on ZIP file %s"), file
);
753 int fileSize
= info
.uncompressed_size
;
756 r
= unzOpenCurrentFile(unz
);
760 systemMessage(MSG_ERROR_OPENING_IMAGE
, N_("Error opening image %s"), buffer
);
767 image
= (u8
*)malloc(utilGetSize(*size
));
769 unzCloseCurrentFile(unz
);
771 systemMessage(MSG_OUT_OF_MEMORY
, N_("Failed to allocate memory for %s"),
777 int read
= fileSize
<= *size
? fileSize
: *size
;
778 r
= unzReadCurrentFile(unz
,
782 unzCloseCurrentFile(unz
);
786 systemMessage(MSG_ERROR_READING_IMAGE
,
787 N_("Error reading image %s"), buffer
);
798 static u8
*utilLoadGzipFile(const char *file
,
799 bool (*accept
)(const char *),
803 FILE *f
= fopen(file
, "rb");
806 systemMessage(MSG_ERROR_OPENING_IMAGE
, N_("Error opening image %s"), file
);
810 fseek(f
, -4, SEEK_END
);
811 int fileSize
= fgetc(f
) | (fgetc(f
) << 8) | (fgetc(f
) << 16) | (fgetc(f
) << 24);
816 gzFile gz
= gzopen(file
, "rb");
819 // should not happen, but who knows?
820 systemMessage(MSG_ERROR_OPENING_IMAGE
, N_("Error opening image %s"), file
);
827 image
= (u8
*)malloc(utilGetSize(*size
));
829 systemMessage(MSG_OUT_OF_MEMORY
, N_("Failed to allocate memory for %s"),
836 int read
= fileSize
<= *size
? fileSize
: *size
;
837 int r
= gzread(gz
, image
, read
);
841 systemMessage(MSG_ERROR_READING_IMAGE
,
842 N_("Error reading image %s"), file
);
854 static u8
*utilLoadRarFile(const char *file
,
855 bool (*accept
)(const char *),
861 ArchiveList_struct
*rarList
= NULL
;
862 if(urarlib_list((void *)file
, (ArchiveList_struct
*)&rarList
)) {
863 ArchiveList_struct
*p
= rarList
;
867 if(accept(p
->item
.Name
)) {
868 strcpy(buffer
, p
->item
.Name
);
876 unsigned long lsize
= 0;
877 *size
= p
->item
.UnpSize
;
878 int r
= urarlib_get((void *)&memory
, &lsize
, buffer
, (void *)file
, "");
880 systemMessage(MSG_ERROR_READING_IMAGE
,
881 N_("Error reading image %s"), buffer
);
882 urarlib_freelist(rarList
);
885 u8
*image
= (u8
*)memory
;
887 memcpy(image
, data
, *size
);
889 urarlib_freelist(rarList
);
892 systemMessage(MSG_NO_IMAGE_ON_ZIP
,
893 N_("No image found on RAR file %s"), file
);
894 urarlib_freelist(rarList
);
902 u8
*utilLoad(const char *file
,
903 bool (*accept
)(const char *),
907 if(utilIsZipFile(file
)) {
908 return utilLoadFromZip(file
, accept
, data
, size
);
910 if(utilIsGzipFile(file
)) {
911 return utilLoadGzipFile(file
, accept
, data
, size
);
914 if(utilIsRarFile(file
)) {
915 return utilLoadRarFile(file
, accept
, data
, size
);
921 FILE *f
= fopen(file
, "rb");
924 systemMessage(MSG_ERROR_OPENING_IMAGE
, N_("Error opening image %s"), file
);
929 int fileSize
= ftell(f
);
935 image
= (u8
*)malloc(utilGetSize(*size
));
937 systemMessage(MSG_OUT_OF_MEMORY
, N_("Failed to allocate memory for %s"),
944 size_t read
= fileSize
<= *size
? fileSize
: *size
;
945 size_t r
= fread(image
, 1, read
, f
);
949 systemMessage(MSG_ERROR_READING_IMAGE
,
950 N_("Error reading image %s"), file
);
961 void utilWriteInt(gzFile gzFile
, int i
)
963 utilGzWrite(gzFile
, &i
, sizeof(int));
966 int utilReadInt(gzFile gzFile
)
969 utilGzRead(gzFile
, &i
, sizeof(int));
973 void utilReadData(gzFile gzFile
, variable_desc
* data
)
975 while(data
->address
) {
976 utilGzRead(gzFile
, data
->address
, data
->size
);
981 void utilWriteData(gzFile gzFile
, variable_desc
*data
)
983 while(data
->address
) {
984 utilGzWrite(gzFile
, data
->address
, data
->size
);
989 gzFile
utilGzOpen(const char *file
, const char *mode
)
991 utilGzWriteFunc
= (int (ZEXPORT
*)(gzFile
,void * const, unsigned int))gzwrite
;
992 utilGzReadFunc
= gzread
;
993 utilGzCloseFunc
= gzclose
;
995 return gzopen(file
, mode
);
998 gzFile
utilMemGzOpen(char *memory
, int available
, char *mode
)
1000 utilGzWriteFunc
= memgzwrite
;
1001 utilGzReadFunc
= memgzread
;
1002 utilGzCloseFunc
= memgzclose
;
1004 return memgzopen(memory
, available
, mode
);
1007 int utilGzWrite(gzFile file
, const voidp buffer
, unsigned int len
)
1009 return utilGzWriteFunc(file
, buffer
, len
);
1012 int utilGzRead(gzFile file
, voidp buffer
, unsigned int len
)
1014 return utilGzReadFunc(file
, buffer
, len
);
1017 int utilGzClose(gzFile file
)
1019 return utilGzCloseFunc(file
);
1022 long utilGzMemTell(gzFile file
)
1024 return memtell(file
);
1027 void utilGBAFindSave(const u8
*data
, const int size
)
1029 u32
*p
= (u32
*)data
;
1030 u32
*end
= (u32
*)(data
+ size
);
1032 int flashSize
= 0x10000;
1033 bool rtcFound
= false;
1036 u32 d
= READ32LE(p
);
1038 if(d
== 0x52504545) {
1039 if(memcmp(p
, "EEPROM_", 7) == 0) {
1043 } else if (d
== 0x4D415253) {
1044 if(memcmp(p
, "SRAM_", 5) == 0) {
1048 } else if (d
== 0x53414C46) {
1049 if(memcmp(p
, "FLASH1M_", 8) == 0) {
1052 flashSize
= 0x20000;
1054 } else if(memcmp(p
, "FLASH", 5) == 0) {
1057 flashSize
= 0x10000;
1060 } else if (d
== 0x52494953) {
1061 if(memcmp(p
, "SIIRTC_V", 8) == 0)
1066 // if no matches found, then set it to NONE
1070 rtcEnable(rtcFound
);
1071 cpuSaveType
= saveType
;
1072 flashSetSize(flashSize
);
1075 void utilUpdateSystemColorMaps()
1077 switch(systemColorDepth
) {
1080 for(int i
= 0; i
< 0x10000; i
++) {
1081 systemColorMap16
[i
] = ((i
& 0x1f) << systemRedShift
) |
1082 (((i
& 0x3e0) >> 5) << systemGreenShift
) |
1083 (((i
& 0x7c00) >> 10) << systemBlueShift
);
1090 for(int i
= 0; i
< 0x10000; i
++) {
1091 systemColorMap32
[i
] = ((i
& 0x1f) << systemRedShift
) |
1092 (((i
& 0x3e0) >> 5) << systemGreenShift
) |
1093 (((i
& 0x7c00) >> 10) << systemBlueShift
);