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.
47 #define _stricmp strcasecmp
50 extern int systemColorDepth
;
51 extern int systemRedShift
;
52 extern int systemGreenShift
;
53 extern int systemBlueShift
;
55 extern u16 systemColorMap16
[0x10000];
56 extern u32 systemColorMap32
[0x10000];
58 static int (ZEXPORT
*utilGzWriteFunc
)(gzFile
, const voidp
, unsigned int) = NULL
;
59 static int (ZEXPORT
*utilGzReadFunc
)(gzFile
, voidp
, unsigned int) = NULL
;
60 static int (ZEXPORT
*utilGzCloseFunc
)(gzFile
) = NULL
;
62 bool utilWritePNGFile(const char *fileName
, int w
, int h
, u8
*pix
)
64 u8 writeBuffer
[512 * 3];
66 FILE *fp
= fopen(fileName
,"wb");
69 systemMessage(MSG_ERROR_CREATING_FILE
, N_("Error creating file %s"), fileName
);
73 png_structp png_ptr
= png_create_write_struct(PNG_LIBPNG_VER_STRING
,
82 png_infop info_ptr
= png_create_info_struct(png_ptr
);
85 png_destroy_write_struct(&png_ptr
,NULL
);
90 if(setjmp(png_jmpbuf(png_ptr
))) {
91 png_destroy_write_struct(&png_ptr
,NULL
);
96 png_init_io(png_ptr
,fp
);
105 PNG_COMPRESSION_TYPE_DEFAULT
,
106 PNG_FILTER_TYPE_DEFAULT
);
108 png_write_info(png_ptr
,info_ptr
);
115 switch(systemColorDepth
) {
118 u16
*p
= (u16
*)(pix
+(w
+2)*2); // skip first black line
119 for(int y
= 0; y
< sizeY
; y
++) {
120 for(int x
= 0; x
< sizeX
; x
++) {
123 *b
++ = ((v
>> systemRedShift
) & 0x001f) << 3; // R
124 *b
++ = ((v
>> systemGreenShift
) & 0x001f) << 3; // G
125 *b
++ = ((v
>> systemBlueShift
) & 0x01f) << 3; // B
127 p
++; // skip black pixel for filters
128 p
++; // skip black pixel for filters
129 png_write_row(png_ptr
,writeBuffer
);
137 u8
*pixU8
= (u8
*)pix
;
138 for(int y
= 0; y
< sizeY
; y
++) {
139 for(int x
= 0; x
< sizeX
; x
++) {
140 if(systemRedShift
< systemBlueShift
) {
141 *b
++ = *pixU8
++; // R
142 *b
++ = *pixU8
++; // G
143 *b
++ = *pixU8
++; // B
146 int green
= *pixU8
++;
154 png_write_row(png_ptr
,writeBuffer
);
162 u32
*pixU32
= (u32
*)(pix
+4*(w
+1));
163 for(int y
= 0; y
< sizeY
; y
++) {
164 for(int x
= 0; x
< sizeX
; x
++) {
167 *b
++ = ((v
>> systemRedShift
) & 0x001f) << 3; // R
168 *b
++ = ((v
>> systemGreenShift
) & 0x001f) << 3; // G
169 *b
++ = ((v
>> systemBlueShift
) & 0x001f) << 3; // B
173 png_write_row(png_ptr
,writeBuffer
);
181 png_write_end(png_ptr
, info_ptr
);
183 png_destroy_write_struct(&png_ptr
, &info_ptr
);
190 void utilPutDword(u8
*p
, u32 value
)
193 *p
++ = (value
>> 8) & 255;
194 *p
++ = (value
>> 16) & 255;
195 *p
= (value
>> 24) & 255;
198 void utilPutWord(u8
*p
, u16 value
)
201 *p
= (value
>> 8) & 255;
204 void utilWriteBMP(char *buf
, int w
, int h
, u8
*pix
)
211 switch(systemColorDepth
) {
214 u16
*p
= (u16
*)(pix
+(w
+2)*(h
)*2); // skip first black line
215 for(int y
= 0; y
< sizeY
; y
++) {
216 for(int x
= 0; x
< sizeX
; x
++) {
219 *b
++ = ((v
>> systemBlueShift
) & 0x01f) << 3; // B
220 *b
++ = ((v
>> systemGreenShift
) & 0x001f) << 3; // G
221 *b
++ = ((v
>> systemRedShift
) & 0x001f) << 3; // R
223 p
++; // skip black pixel for filters
224 p
++; // skip black pixel for filters
231 u8
*pixU8
= (u8
*)pix
+3*w
*(h
-1);
232 for(int y
= 0; y
< sizeY
; y
++) {
233 for(int x
= 0; x
< sizeX
; x
++) {
234 if(systemRedShift
> systemBlueShift
) {
235 *b
++ = *pixU8
++; // B
236 *b
++ = *pixU8
++; // G
237 *b
++ = *pixU8
++; // R
240 int green
= *pixU8
++;
254 u32
*pixU32
= (u32
*)(pix
+4*(w
+1)*(h
));
255 for(int y
= 0; y
< sizeY
; y
++) {
256 for(int x
= 0; x
< sizeX
; x
++) {
259 *b
++ = ((v
>> systemBlueShift
) & 0x001f) << 3; // B
260 *b
++ = ((v
>> systemGreenShift
) & 0x001f) << 3; // G
261 *b
++ = ((v
>> systemRedShift
) & 0x001f) << 3; // R
271 bool utilWriteBMPFile(const char *fileName
, int w
, int h
, u8
*pix
)
273 u8 writeBuffer
[512 * 3];
275 FILE *fp
= fopen(fileName
,"wb");
278 systemMessage(MSG_ERROR_CREATING_FILE
, N_("Error creating file %s"), fileName
);
297 u8 importantcolors
[4];
300 memset(&bmpheader
, 0, sizeof(bmpheader
));
302 bmpheader
.ident
[0] = 'B';
303 bmpheader
.ident
[1] = 'M';
305 u32 fsz
= sizeof(bmpheader
) + w
*h
*3;
306 utilPutDword(bmpheader
.filesize
, fsz
);
307 utilPutDword(bmpheader
.dataoffset
, 0x36);
308 utilPutDword(bmpheader
.headersize
, 0x28);
309 utilPutDword(bmpheader
.width
, w
);
310 utilPutDword(bmpheader
.height
, h
);
311 utilPutDword(bmpheader
.planes
, 1);
312 utilPutDword(bmpheader
.bitsperpixel
, 24);
313 utilPutDword(bmpheader
.datasize
, 3*w
*h
);
315 fwrite(&bmpheader
, 1, sizeof(bmpheader
), fp
);
322 switch(systemColorDepth
) {
325 u16
*p
= (u16
*)(pix
+(w
+2)*(h
)*2); // skip first black line
326 for(int y
= 0; y
< sizeY
; y
++) {
327 for(int x
= 0; x
< sizeX
; x
++) {
330 *b
++ = ((v
>> systemBlueShift
) & 0x01f) << 3; // B
331 *b
++ = ((v
>> systemGreenShift
) & 0x001f) << 3; // G
332 *b
++ = ((v
>> systemRedShift
) & 0x001f) << 3; // R
334 p
++; // skip black pixel for filters
335 p
++; // skip black pixel for filters
337 fwrite(writeBuffer
, 1, 3*w
, fp
);
345 u8
*pixU8
= (u8
*)pix
+3*w
*(h
-1);
346 for(int y
= 0; y
< sizeY
; y
++) {
347 for(int x
= 0; x
< sizeX
; x
++) {
348 if(systemRedShift
> systemBlueShift
) {
349 *b
++ = *pixU8
++; // B
350 *b
++ = *pixU8
++; // G
351 *b
++ = *pixU8
++; // R
354 int green
= *pixU8
++;
363 fwrite(writeBuffer
, 1, 3*w
, fp
);
371 u32
*pixU32
= (u32
*)(pix
+4*(w
+1)*(h
));
372 for(int y
= 0; y
< sizeY
; y
++) {
373 for(int x
= 0; x
< sizeX
; x
++) {
376 *b
++ = ((v
>> systemBlueShift
) & 0x001f) << 3; // B
377 *b
++ = ((v
>> systemGreenShift
) & 0x001f) << 3; // G
378 *b
++ = ((v
>> systemRedShift
) & 0x001f) << 3; // R
383 fwrite(writeBuffer
, 1, 3*w
, fp
);
396 static int utilReadInt2(FILE *f
)
409 static int utilReadInt3(FILE *f
)
426 void utilApplyIPS(const char *ips
, u8
**r
, int *s
)
428 // from the IPS spec at http://zerosoft.zophar.net/ips.htm
429 FILE *f
= fopen(ips
, "rb");
434 if(fgetc(f
) == 'P' &&
444 offset
= utilReadInt3(f
);
445 // if offset == EOF, end of patch
446 if(offset
== 0x454f46)
449 len
= utilReadInt2(f
);
451 // len == 0, RLE block
452 len
= utilReadInt2(f
);
460 // check if we need to reallocate our ROM
461 if((offset
+ len
) >= size
) {
463 rom
= (u8
*)realloc(rom
, size
);
468 // normal block, just read the data
469 if(fread(&rom
[offset
], 1, len
, f
) != (size_t)len
)
472 // fill the region with the given byte
483 extern bool cpuIsMultiBoot
;
485 bool utilIsGBAImage(const char * file
)
487 cpuIsMultiBoot
= false;
488 if(strlen(file
) > 4) {
489 const char * p
= strrchr(file
,'.');
492 if(_stricmp(p
, ".gba") == 0)
494 if(_stricmp(p
, ".agb") == 0)
496 if(_stricmp(p
, ".bin") == 0)
498 if(_stricmp(p
, ".elf") == 0)
500 if(_stricmp(p
, ".mb") == 0) {
501 cpuIsMultiBoot
= true;
510 bool utilIsGBImage(const char * file
)
512 if(strlen(file
) > 4) {
513 const char * p
= strrchr(file
,'.');
516 if(_stricmp(p
, ".gb") == 0)
518 if(_stricmp(p
, ".gbc") == 0)
520 if(_stricmp(p
, ".cgb") == 0)
522 if(_stricmp(p
, ".sgb") == 0)
530 bool utilIsZipFile(const char *file
)
532 if(strlen(file
) > 4) {
533 const char * p
= strrchr(file
,'.');
536 if(_stricmp(p
, ".zip") == 0)
545 bool utilIsRarFile(const char *file
)
547 if(strlen(file
) > 4) {
548 char * p
= strrchr(file
,'.');
551 if(_stricmp(p
, ".rar") == 0)
560 bool utilIsGzipFile(const char *file
)
562 if(strlen(file
) > 3) {
563 const char * p
= strrchr(file
,'.');
566 if(_stricmp(p
, ".gz") == 0)
568 if(_stricmp(p
, ".z") == 0)
576 void utilGetBaseName(const char *file
, char *buffer
)
578 strcpy(buffer
, file
);
580 if(utilIsGzipFile(file
)) {
581 char *p
= strrchr(buffer
, '.');
588 IMAGE_TYPE
utilFindType(const char *file
)
592 if(utilIsZipFile(file
)) {
593 unzFile unz
= unzOpen(file
);
596 systemMessage(MSG_CANNOT_OPEN_FILE
, N_("Cannot open file %s"), file
);
597 return IMAGE_UNKNOWN
;
600 int r
= unzGoToFirstFile(unz
);
604 systemMessage(MSG_BAD_ZIP_FILE
, N_("Bad ZIP file %s"), file
);
605 return IMAGE_UNKNOWN
;
608 IMAGE_TYPE found
= IMAGE_UNKNOWN
;
613 r
= unzGetCurrentFileInfo(unz
,
624 systemMessage(MSG_BAD_ZIP_FILE
, N_("Bad ZIP file %s"), file
);
625 return IMAGE_UNKNOWN
;
628 if(utilIsGBAImage(buffer
)) {
633 if(utilIsGBImage(buffer
)) {
638 r
= unzGoToNextFile(unz
);
645 if(found
== IMAGE_UNKNOWN
) {
646 systemMessage(MSG_NO_IMAGE_ON_ZIP
,
647 N_("No image found on ZIP file %s"), file
);
652 } else if(utilIsRarFile(file
)) {
653 IMAGE_TYPE found
= IMAGE_UNKNOWN
;
655 ArchiveList_struct
*rarList
= NULL
;
656 if(urarlib_list((void *)file
, (ArchiveList_struct
*)&rarList
)) {
657 ArchiveList_struct
*p
= rarList
;
660 if(utilIsGBAImage(p
->item
.Name
)) {
665 if(utilIsGBImage(p
->item
.Name
)) {
672 urarlib_freelist(rarList
);
677 if(utilIsGzipFile(file
))
678 utilGetBaseName(file
, buffer
);
680 strcpy(buffer
, file
);
682 if(utilIsGBAImage(buffer
))
684 if(utilIsGBImage(buffer
))
687 return IMAGE_UNKNOWN
;
690 static int utilGetSize(int size
)
698 static u8
*utilLoadFromZip(const char *file
,
699 bool (*accept
)(const char *),
705 unzFile unz
= unzOpen(file
);
708 systemMessage(MSG_CANNOT_OPEN_FILE
, N_("Cannot open file %s"), file
);
711 int r
= unzGoToFirstFile(unz
);
715 systemMessage(MSG_BAD_ZIP_FILE
, N_("Bad ZIP file %s"), file
);
724 r
= unzGetCurrentFileInfo(unz
,
735 systemMessage(MSG_BAD_ZIP_FILE
, N_("Bad ZIP file %s"), file
);
744 r
= unzGoToNextFile(unz
);
752 systemMessage(MSG_NO_IMAGE_ON_ZIP
,
753 N_("No image found on ZIP file %s"), file
);
757 int fileSize
= info
.uncompressed_size
;
760 r
= unzOpenCurrentFile(unz
);
764 systemMessage(MSG_ERROR_OPENING_IMAGE
, N_("Error opening image %s"), buffer
);
771 image
= (u8
*)malloc(utilGetSize(size
));
773 unzCloseCurrentFile(unz
);
775 systemMessage(MSG_OUT_OF_MEMORY
, N_("Failed to allocate memory for %s"),
781 int read
= fileSize
<= size
? fileSize
: size
;
782 r
= unzReadCurrentFile(unz
,
786 unzCloseCurrentFile(unz
);
790 systemMessage(MSG_ERROR_READING_IMAGE
,
791 N_("Error reading image %s"), buffer
);
802 static u8
*utilLoadGzipFile(const char *file
,
803 bool (*accept
)(const char *),
807 FILE *f
= fopen(file
, "rb");
810 systemMessage(MSG_ERROR_OPENING_IMAGE
, N_("Error opening image %s"), file
);
814 fseek(f
, -4, SEEK_END
);
815 int fileSize
= fgetc(f
) | (fgetc(f
) << 8) | (fgetc(f
) << 16) | (fgetc(f
) << 24);
820 gzFile gz
= gzopen(file
, "rb");
823 // should not happen, but who knows?
824 systemMessage(MSG_ERROR_OPENING_IMAGE
, N_("Error opening image %s"), file
);
831 image
= (u8
*)malloc(utilGetSize(size
));
833 systemMessage(MSG_OUT_OF_MEMORY
, N_("Failed to allocate memory for %s"),
840 int read
= fileSize
<= size
? fileSize
: size
;
841 int r
= gzread(gz
, image
, read
);
845 systemMessage(MSG_ERROR_READING_IMAGE
,
846 N_("Error reading image %s"), file
);
858 static u8
*utilLoadRarFile(const char *file
,
859 bool (*accept
)(const char *),
865 ArchiveList_struct
*rarList
= NULL
;
866 if(urarlib_list((void *)file
, (ArchiveList_struct
*)&rarList
)) {
867 ArchiveList_struct
*p
= rarList
;
871 if(accept(p
->item
.Name
)) {
872 strcpy(buffer
, p
->item
.Name
);
880 unsigned long lsize
= 0;
881 size
= p
->item
.UnpSize
;
882 int r
= urarlib_get((void *)&memory
, &lsize
, buffer
, (void *)file
, "");
884 systemMessage(MSG_ERROR_READING_IMAGE
,
885 N_("Error reading image %s"), buffer
);
886 urarlib_freelist(rarList
);
889 u8
*image
= (u8
*)memory
;
891 memcpy(image
, data
, size
);
893 urarlib_freelist(rarList
);
896 systemMessage(MSG_NO_IMAGE_ON_ZIP
,
897 N_("No image found on RAR file %s"), file
);
898 urarlib_freelist(rarList
);
906 u8
*utilLoad(const char *file
,
907 bool (*accept
)(const char *),
911 if(utilIsZipFile(file
)) {
912 return utilLoadFromZip(file
, accept
, data
, size
);
914 if(utilIsGzipFile(file
)) {
915 return utilLoadGzipFile(file
, accept
, data
, size
);
918 if(utilIsRarFile(file
)) {
919 return utilLoadRarFile(file
, accept
, data
, size
);
925 FILE *f
= fopen(file
, "rb");
928 systemMessage(MSG_ERROR_OPENING_IMAGE
, N_("Error opening image %s"), file
);
933 int fileSize
= ftell(f
);
939 image
= (u8
*)malloc(utilGetSize(size
));
941 systemMessage(MSG_OUT_OF_MEMORY
, N_("Failed to allocate memory for %s"),
948 size_t read
= fileSize
<= size
? fileSize
: size
;
949 size_t r
= fread(image
, 1, read
, f
);
953 systemMessage(MSG_ERROR_READING_IMAGE
,
954 N_("Error reading image %s"), file
);
965 void utilWriteInt(gzFile gzFile
, int i
)
967 utilGzWrite(gzFile
, &i
, sizeof(int));
970 int utilReadInt(gzFile gzFile
)
973 utilGzRead(gzFile
, &i
, sizeof(int));
977 void utilReadData(gzFile gzFile
, variable_desc
* data
)
979 while(data
->address
) {
980 utilGzRead(gzFile
, data
->address
, data
->size
);
985 void utilWriteData(gzFile gzFile
, variable_desc
*data
)
987 while(data
->address
) {
988 utilGzWrite(gzFile
, data
->address
, data
->size
);
993 gzFile
utilGzOpen(const char *file
, const char *mode
)
995 utilGzWriteFunc
= (int (ZEXPORT
*)(gzFile
,void * const, unsigned int))gzwrite
;
996 utilGzReadFunc
= gzread
;
997 utilGzCloseFunc
= gzclose
;
999 return gzopen(file
, mode
);
1002 gzFile
utilMemGzOpen(char *memory
, int available
, char *mode
)
1004 utilGzWriteFunc
= memgzwrite
;
1005 utilGzReadFunc
= memgzread
;
1006 utilGzCloseFunc
= memgzclose
;
1008 return memgzopen(memory
, available
, mode
);
1011 int utilGzWrite(gzFile file
, const voidp buffer
, unsigned int len
)
1013 return utilGzWriteFunc(file
, buffer
, len
);
1016 int utilGzRead(gzFile file
, voidp buffer
, unsigned int len
)
1018 return utilGzReadFunc(file
, buffer
, len
);
1021 int utilGzClose(gzFile file
)
1023 return utilGzCloseFunc(file
);
1026 long utilGzMemTell(gzFile file
)
1028 return memtell(file
);
1031 void utilGBAFindSave(const u8
*data
, const int size
)
1033 u32
*p
= (u32
*)data
;
1034 u32
*end
= (u32
*)(data
+ size
);
1036 int flashSize
= 0x10000;
1037 bool rtcFound
= false;
1040 u32 d
= READ32LE(p
);
1042 if(d
== 0x52504545) {
1043 if(memcmp(p
, "EEPROM_", 7) == 0) {
1047 } else if (d
== 0x4D415253) {
1048 if(memcmp(p
, "SRAM_", 5) == 0) {
1052 } else if (d
== 0x53414C46) {
1053 if(memcmp(p
, "FLASH1M_", 8) == 0) {
1056 flashSize
= 0x20000;
1058 } else if(memcmp(p
, "FLASH", 5) == 0) {
1061 flashSize
= 0x10000;
1064 } else if (d
== 0x52494953) {
1065 if(memcmp(p
, "SIIRTC_V", 8) == 0)
1070 // if no matches found, then set it to NONE
1074 rtcEnable(rtcFound
);
1075 cpuSaveType
= saveType
;
1076 flashSetSize(flashSize
);
1079 void utilUpdateSystemColorMaps()
1081 switch(systemColorDepth
) {
1084 for(int i
= 0; i
< 0x10000; i
++) {
1085 systemColorMap16
[i
] = ((i
& 0x1f) << systemRedShift
) |
1086 (((i
& 0x3e0) >> 5) << systemGreenShift
) |
1087 (((i
& 0x7c00) >> 10) << systemBlueShift
);
1094 for(int i
= 0; i
< 0x10000; i
++) {
1095 systemColorMap32
[i
] = ((i
& 0x1f) << systemRedShift
) |
1096 (((i
& 0x3e0) >> 5) << systemGreenShift
) |
1097 (((i
& 0x7c00) >> 10) << systemBlueShift
);