1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <string>
5 
6 #ifndef _WIN32
7 #include <unistd.h>
8 #include <sys/stat.h>
9 #else // _WIN32
10 #include <io.h>
11 #include <direct.h>
12 #endif // _WIN32
13 
14 #include <zlib.h>
15 
16 #ifndef NO_PNG
17 extern "C" {
18 #include <png.h>
19 }
20 #endif
21 
22 #include "System.h"
23 #include "NLS.h"
24 #include "Util.h"
25 #include "gba/Flash.h"
26 #include "gba/GBA.h"
27 #include "gba/Globals.h"
28 #include "gba/RTC.h"
29 #include "common/Port.h"
30 
31 #include "fex/fex.h"
32 
33 extern "C" {
34 #include "common/memgzio.h"
35 }
36 
37 #include "gba/gbafilter.h"
38 #include "gb/gbGlobals.h"
39 
40 #ifndef _MSC_VER
41 #define _stricmp strcasecmp
42 #endif // ! _MSC_VER
43 
44 extern int systemColorDepth;
45 extern int systemRedShift;
46 extern int systemGreenShift;
47 extern int systemBlueShift;
48 
49 extern u16 systemColorMap16[0x10000];
50 extern u32 systemColorMap32[0x10000];
51 
52 static int (ZEXPORT *utilGzWriteFunc)(gzFile, const voidp, unsigned int) = NULL;
53 static int (ZEXPORT *utilGzReadFunc)(gzFile, voidp, unsigned int) = NULL;
54 static int (ZEXPORT *utilGzCloseFunc)(gzFile) = NULL;
55 static z_off_t (ZEXPORT *utilGzSeekFunc)(gzFile, z_off_t, int) = NULL;
56 
FileExists(const char * filename)57 bool FileExists(const char *filename)
58 {
59 #ifdef _WIN32
60 	return (_access(filename, 0) != -1);
61 #else
62 	struct stat buffer;
63 	return (stat(filename, &buffer) == 0);
64 #endif
65 }
66 
utilReadScreenPixels(u8 * dest,int w,int h)67 void utilReadScreenPixels(u8* dest, int w, int h)
68 {
69 	u8* b = dest;
70 	int sizeX = w;
71 	int sizeY = h;
72 	switch (systemColorDepth) {
73 	case 16:
74 	{
75 		u16 *p = (u16 *) (pix + (w + 2) * 2); // skip first black line
76 		for (int y = 0; y < sizeY; y++) {
77 			for (int x = 0; x < sizeX; x++) {
78 				u16 v = *p++;
79 
80 				*b++ = ((v >> systemRedShift) & 0x001f) << 3; // R
81 				*b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G
82 				*b++ = ((v >> systemBlueShift) & 0x01f) << 3; // B
83 			}
84 			p++; // skip black pixel for filters
85 			p++; // skip black pixel for filters
86 		}
87 	}
88 		break;
89 	case 24:
90 	{
91 		u8 *pixU8 = (u8 *) pix;
92 		for (int y = 0; y < sizeY; y++) {
93 			for (int x = 0; x < sizeX; x++) {
94 				if (systemRedShift < systemBlueShift) {
95 					*b++ = *pixU8++; // R
96 					*b++ = *pixU8++; // G
97 					*b++ = *pixU8++; // B
98 				}
99 				else {
100 					int blue = *pixU8++;
101 					int green = *pixU8++;
102 					int red = *pixU8++;
103 
104 					*b++ = red;
105 					*b++ = green;
106 					*b++ = blue;
107 				}
108 			}
109 		}
110 	}
111 		break;
112 	case 32:
113 	{
114 		u32 *pixU32 = (u32 *) (pix + 4 * (w + 1));
115 		for (int y = 0; y < sizeY; y++) {
116 			for (int x = 0; x < sizeX; x++) {
117 				u32 v = *pixU32++;
118 				*b++ = ((v >> systemBlueShift) & 0x001f) << 3; // B
119 				*b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G
120 				*b++ = ((v >> systemRedShift) & 0x001f) << 3; // R
121 			}
122 			pixU32++;
123 		}
124 	}
125 		break;
126 	}
127 }
128 
utilWritePNGFile(const char * fileName,int w,int h,u8 * pix)129 bool utilWritePNGFile(const char *fileName, int w, int h, u8 *pix)
130 {
131 #ifndef NO_PNG
132   u8 writeBuffer[512 * 3];
133 
134   FILE *fp = fopen(fileName,"wb");
135 
136   if(!fp) {
137     systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), fileName);
138     return false;
139   }
140 
141   png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
142                                                 NULL,
143                                                 NULL,
144                                                 NULL);
145   if(!png_ptr) {
146     fclose(fp);
147     return false;
148   }
149 
150   png_infop info_ptr = png_create_info_struct(png_ptr);
151 
152   if(!info_ptr) {
153     png_destroy_write_struct(&png_ptr,NULL);
154     fclose(fp);
155     return false;
156   }
157 
158   if(setjmp(png_jmpbuf(png_ptr))) {
159     png_destroy_write_struct(&png_ptr,NULL);
160     fclose(fp);
161     return false;
162   }
163 
164   png_init_io(png_ptr,fp);
165 
166   png_set_IHDR(png_ptr,
167                info_ptr,
168                w,
169                h,
170                8,
171                PNG_COLOR_TYPE_RGB,
172                PNG_INTERLACE_NONE,
173                PNG_COMPRESSION_TYPE_DEFAULT,
174                PNG_FILTER_TYPE_DEFAULT);
175 
176   png_write_info(png_ptr,info_ptr);
177 
178   u8 *b = writeBuffer;
179 
180   int sizeX = w;
181   int sizeY = h;
182 
183   switch(systemColorDepth) {
184   case 16:
185     {
186       u16 *p = (u16 *)(pix+(w+2)*2); // skip first black line
187       for(int y = 0; y < sizeY; y++) {
188          for(int x = 0; x < sizeX; x++) {
189           u16 v = *p++;
190 
191           *b++ = ((v >> systemRedShift) & 0x001f) << 3; // R
192           *b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G
193           *b++ = ((v >> systemBlueShift) & 0x01f) << 3; // B
194         }
195         p++; // skip black pixel for filters
196         p++; // skip black pixel for filters
197         png_write_row(png_ptr,writeBuffer);
198 
199         b = writeBuffer;
200       }
201     }
202     break;
203   case 24:
204     {
205       u8 *pixU8 = (u8 *)pix;
206       for(int y = 0; y < sizeY; y++) {
207         for(int x = 0; x < sizeX; x++) {
208           if(systemRedShift < systemBlueShift) {
209             *b++ = *pixU8++; // R
210             *b++ = *pixU8++; // G
211             *b++ = *pixU8++; // B
212           } else {
213             int blue = *pixU8++;
214             int green = *pixU8++;
215             int red = *pixU8++;
216 
217             *b++ = red;
218             *b++ = green;
219             *b++ = blue;
220           }
221         }
222         png_write_row(png_ptr,writeBuffer);
223 
224         b = writeBuffer;
225       }
226     }
227     break;
228   case 32:
229     {
230       u32 *pixU32 = (u32 *)(pix+4*(w+1));
231       for(int y = 0; y < sizeY; y++) {
232         for(int x = 0; x < sizeX; x++) {
233           u32 v = *pixU32++;
234 
235           *b++ = ((v >> systemRedShift) & 0x001f) << 3; // R
236           *b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G
237           *b++ = ((v >> systemBlueShift) & 0x001f) << 3; // B
238         }
239         pixU32++;
240 
241         png_write_row(png_ptr,writeBuffer);
242 
243         b = writeBuffer;
244       }
245     }
246     break;
247   }
248 
249   png_write_end(png_ptr, info_ptr);
250 
251   png_destroy_write_struct(&png_ptr, &info_ptr);
252 
253   fclose(fp);
254 
255   return true;
256 #else
257   return false;
258 #endif
259 }
260 
utilPutDword(u8 * p,u32 value)261 void utilPutDword(u8 *p, u32 value)
262 {
263   *p++ = value & 255;
264   *p++ = (value >> 8) & 255;
265   *p++ = (value >> 16) & 255;
266   *p = (value >> 24) & 255;
267 }
268 
utilPutWord(u8 * p,u16 value)269 void utilPutWord(u8 *p, u16 value)
270 {
271   *p++ = value & 255;
272   *p = (value >> 8) & 255;
273 }
274 
utilWriteBMPFile(const char * fileName,int w,int h,u8 * pix)275 bool utilWriteBMPFile(const char *fileName, int w, int h, u8 *pix)
276 {
277   u8 writeBuffer[512 * 3];
278 
279   FILE *fp = fopen(fileName,"wb");
280 
281   if(!fp) {
282     systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), fileName);
283     return false;
284   }
285 
286   struct {
287     u8 ident[2];
288     u8 filesize[4];
289     u8 reserved[4];
290     u8 dataoffset[4];
291     u8 headersize[4];
292     u8 width[4];
293     u8 height[4];
294     u8 planes[2];
295     u8 bitsperpixel[2];
296     u8 compression[4];
297     u8 datasize[4];
298     u8 hres[4];
299     u8 vres[4];
300     u8 colors[4];
301     u8 importantcolors[4];
302     //    u8 pad[2];
303   } bmpheader;
304   memset(&bmpheader, 0, sizeof(bmpheader));
305 
306   bmpheader.ident[0] = 'B';
307   bmpheader.ident[1] = 'M';
308 
309   u32 fsz = sizeof(bmpheader) + w*h*3;
310   utilPutDword(bmpheader.filesize, fsz);
311   utilPutDword(bmpheader.dataoffset, 0x36);
312   utilPutDword(bmpheader.headersize, 0x28);
313   utilPutDword(bmpheader.width, w);
314   utilPutDword(bmpheader.height, h);
315   utilPutDword(bmpheader.planes, 1);
316   utilPutDword(bmpheader.bitsperpixel, 24);
317   utilPutDword(bmpheader.datasize, 3*w*h);
318 
319   fwrite(&bmpheader, 1, sizeof(bmpheader), fp);
320 
321   u8 *b = writeBuffer;
322 
323   int sizeX = w;
324   int sizeY = h;
325 
326   switch(systemColorDepth) {
327   case 16:
328     {
329       u16 *p = (u16 *)(pix+(w+2)*(h)*2); // skip first black line
330       for(int y = 0; y < sizeY; y++) {
331         for(int x = 0; x < sizeX; x++) {
332           u16 v = *p++;
333 
334           *b++ = ((v >> systemBlueShift) & 0x01f) << 3; // B
335           *b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G
336           *b++ = ((v >> systemRedShift) & 0x001f) << 3; // R
337         }
338         p++; // skip black pixel for filters
339         p++; // skip black pixel for filters
340         p -= 2*(w+2);
341         fwrite(writeBuffer, 1, 3*w, fp);
342 
343         b = writeBuffer;
344       }
345     }
346     break;
347   case 24:
348     {
349       u8 *pixU8 = (u8 *)pix+3*w*(h-1);
350       for(int y = 0; y < sizeY; y++) {
351         for(int x = 0; x < sizeX; x++) {
352           if(systemRedShift > systemBlueShift) {
353             *b++ = *pixU8++; // B
354             *b++ = *pixU8++; // G
355             *b++ = *pixU8++; // R
356           } else {
357             int red = *pixU8++;
358             int green = *pixU8++;
359             int blue = *pixU8++;
360 
361             *b++ = blue;
362             *b++ = green;
363             *b++ = red;
364           }
365         }
366         pixU8 -= 2*3*w;
367         fwrite(writeBuffer, 1, 3*w, fp);
368 
369         b = writeBuffer;
370       }
371     }
372     break;
373   case 32:
374     {
375       u32 *pixU32 = (u32 *)(pix+4*(w+1)*(h));
376       for(int y = 0; y < sizeY; y++) {
377         for(int x = 0; x < sizeX; x++) {
378           u32 v = *pixU32++;
379 
380           *b++ = ((v >> systemBlueShift) & 0x001f) << 3; // B
381           *b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G
382           *b++ = ((v >> systemRedShift) & 0x001f) << 3; // R
383         }
384         pixU32++;
385         pixU32 -= 2*(w+1);
386 
387         fwrite(writeBuffer, 1, 3*w, fp);
388 
389         b = writeBuffer;
390       }
391     }
392     break;
393   }
394 
395   fclose(fp);
396 
397   return true;
398 }
399 
400 extern bool cpuIsMultiBoot;
401 
utilIsGBAImage(const char * file)402 bool utilIsGBAImage(const char * file)
403 {
404   cpuIsMultiBoot = false;
405   if(strlen(file) > 4) {
406     const char * p = strrchr(file,'.');
407 
408     if(p != NULL) {
409       if((_stricmp(p, ".agb") == 0) ||
410          (_stricmp(p, ".gba") == 0) ||
411          (_stricmp(p, ".bin") == 0) ||
412          (_stricmp(p, ".elf") == 0))
413         return true;
414       if(_stricmp(p, ".mb") == 0) {
415         cpuIsMultiBoot = true;
416         return true;
417       }
418     }
419   }
420 
421   return false;
422 }
423 
utilIsGBImage(const char * file)424 bool utilIsGBImage(const char * file)
425 {
426   if(strlen(file) > 4) {
427     const char * p = strrchr(file,'.');
428 
429     if(p != NULL) {
430       if((_stricmp(p, ".dmg") == 0) ||
431          (_stricmp(p, ".gb") == 0) ||
432          (_stricmp(p, ".gbc") == 0) ||
433          (_stricmp(p, ".cgb") == 0) ||
434          (_stricmp(p, ".sgb") == 0))
435         return true;
436     }
437   }
438 
439   return false;
440 }
441 
utilIsGzipFile(const char * file)442 bool utilIsGzipFile(const char *file)
443 {
444   if(strlen(file) > 3) {
445     const char * p = strrchr(file,'.');
446 
447     if(p != NULL) {
448       if(_stricmp(p, ".gz") == 0)
449         return true;
450       if(_stricmp(p, ".z") == 0)
451         return true;
452     }
453   }
454 
455   return false;
456 }
457 
458 // strip .gz or .z off end
utilStripDoubleExtension(const char * file,char * buffer)459 void utilStripDoubleExtension(const char *file, char *buffer)
460 {
461   if(buffer != file) // allows conversion in place
462     strcpy(buffer, file);
463 
464   if(utilIsGzipFile(file)) {
465     char *p = strrchr(buffer, '.');
466 
467     if(p)
468       *p = 0;
469   }
470 }
471 
472 // Opens and scans archive using accept(). Returns fex_t if found.
473 // If error or not found, displays message and returns NULL.
scan_arc(const char * file,bool (* accept)(const char *),char (& buffer)[2048])474 static fex_t* scan_arc(const char *file, bool (*accept)(const char *),
475 		char (&buffer) [2048] )
476 {
477 	fex_t* fe;
478 	fex_err_t err = fex_open( &fe, file );
479 	if(!fe)
480 	{
481 		systemMessage(MSG_CANNOT_OPEN_FILE, N_("Cannot open file %s: %s"), file, err);
482 		return NULL;
483 	}
484 
485 	// Scan filenames
486 	bool found=false;
487 	while(!fex_done(fe)) {
488 		strncpy(buffer,fex_name(fe),sizeof buffer);
489 		buffer [sizeof buffer-1] = '\0';
490 
491 		utilStripDoubleExtension(buffer, buffer);
492 
493 		if(accept(buffer)) {
494 			found = true;
495 			break;
496 		}
497 
498 		fex_err_t err = fex_next(fe);
499 		if(err) {
500 			systemMessage(MSG_BAD_ZIP_FILE, N_("Cannot read archive %s: %s"), file, err);
501 			fex_close(fe);
502 			return NULL;
503 		}
504 	}
505 
506 	if(!found) {
507 		systemMessage(MSG_NO_IMAGE_ON_ZIP,
508 									N_("No image found in file %s"), file);
509 		fex_close(fe);
510 		return NULL;
511 	}
512 	return fe;
513 }
514 
utilIsImage(const char * file)515 static bool utilIsImage(const char *file)
516 {
517 	return utilIsGBAImage(file) || utilIsGBImage(file);
518 }
519 
520 #ifdef WIN32
521 #include <windows.h>
522 #endif
523 
524 IMAGE_TYPE utilFindType(const char *file, char (&buffer)[2048]);
525 
utilFindType(const char * file)526 IMAGE_TYPE utilFindType(const char *file)
527 {
528 	char buffer [2048];
529 	return utilFindType(file, buffer);
530 }
531 
utilFindType(const char * file,char (& buffer)[2048])532 IMAGE_TYPE utilFindType(const char *file, char (&buffer)[2048])
533 {
534 #ifdef WIN32
535 	DWORD dwNum = MultiByteToWideChar (CP_ACP, 0, file, -1, NULL, 0);
536 	wchar_t *pwText;
537 	pwText = new wchar_t[dwNum];
538 	if(!pwText)
539 	{
540 		return IMAGE_UNKNOWN;
541 	}
542 	MultiByteToWideChar (CP_ACP, 0, file, -1, pwText, dwNum );
543 	char* file_conv = fex_wide_to_path( pwText);
544 //	if ( !utilIsImage( file_conv ) ) // TODO: utilIsArchive() instead?
545 //	{
546 		fex_t* fe = scan_arc(file_conv,utilIsImage,buffer);
547 		if(!fe)
548 			return IMAGE_UNKNOWN;
549 		fex_close(fe);
550 		file = buffer;
551 //	}
552 	free(file_conv);
553 #else
554 //	if ( !utilIsImage( file ) ) // TODO: utilIsArchive() instead?
555 //	{
556 		fex_t* fe = scan_arc(file,utilIsImage,buffer);
557 		if(!fe)
558 			return IMAGE_UNKNOWN;
559 		fex_close(fe);
560 		file = buffer;
561 //	}
562 #endif
563 	return utilIsGBAImage(file) ? IMAGE_GBA : IMAGE_GB;
564 }
565 
utilGetSize(int size)566 static int utilGetSize(int size)
567 {
568   int res = 1;
569   while(res < size)
570     res <<= 1;
571   return res;
572 }
573 
utilLoad(const char * file,bool (* accept)(const char *),u8 * data,int & size)574 u8 *utilLoad(const char *file,
575              bool (*accept)(const char *),
576              u8 *data,
577              int &size)
578 {
579 	// find image file
580 	char buffer [2048];
581 #ifdef WIN32
582 	DWORD dwNum = MultiByteToWideChar (CP_ACP, 0, file, -1, NULL, 0);
583 	wchar_t *pwText;
584 	pwText = new wchar_t[dwNum];
585 	if(!pwText)
586 	{
587 		return NULL;
588 	}
589 	MultiByteToWideChar (CP_ACP, 0, file, -1, pwText, dwNum );
590 	char* file_conv = fex_wide_to_path( pwText);
591 	delete []pwText;
592 	fex_t *fe = scan_arc(file_conv,accept,buffer);
593 	if(!fe)
594 		return NULL;
595 	free(file_conv);
596 #else
597 	fex_t *fe = scan_arc(file,accept,buffer);
598 	if(!fe)
599 		return NULL;
600 #endif
601 	// Allocate space for image
602 	fex_err_t err = fex_stat(fe);
603 	int fileSize = fex_size(fe);
604 	if(size == 0)
605 		size = fileSize;
606 
607 	u8 *image = data;
608 
609 	if(image == NULL) {
610 		// allocate buffer memory if none was passed to the function
611 		image = (u8 *)malloc(utilGetSize(size));
612 		if(image == NULL) {
613 			fex_close(fe);
614 			systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"),
615 										"data");
616 			return NULL;
617 		}
618 		size = fileSize;
619 	}
620 
621 	// Read image
622 	int read = fileSize <= size ? fileSize : size; // do not read beyond file
623 	err = fex_read(fe, image, read);
624 	fex_close(fe);
625 	if(err) {
626 		systemMessage(MSG_ERROR_READING_IMAGE,
627 									N_("Error reading image from %s: %s"), buffer, err);
628 		if(data == NULL)
629 			free(image);
630 		return NULL;
631 	}
632 
633 	size = fileSize;
634 
635 	return image;
636 }
637 
replaceAll(std::string & str,const std::string & from,const std::string & to)638 void replaceAll(std::string& str, const std::string& from, const std::string& to) {
639 	if (from.empty())
640 		return;
641 	size_t start_pos = 0;
642 	while ((start_pos = str.find(from, start_pos)) != std::string::npos) {
643 		str.replace(start_pos, from.length(), to);
644 		start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx'
645 	}
646 }
647 
utilExtract(const char * filepath,const char * filename)648 void utilExtract(const char* filepath, const char* filename)
649 {
650 	fex_t* fex;
651 	std::string archive_name(filepath);
652 	archive_name.append(filename);
653 
654 	fex_open(&fex, archive_name.c_str());
655 	while (!fex_done(fex))
656 	{
657 		std::string extracted_filename(filepath);
658 		extracted_filename.append(fex_name(fex));
659 #ifdef WIN32
660 		replaceAll(extracted_filename, "/", "\\");
661 #endif
662 
663 		std::string new_dir(filepath);
664 		new_dir.append(fex_name(fex));
665 #ifdef WIN32
666 		replaceAll(new_dir, "/", "\\");
667 #endif
668 		new_dir = new_dir.substr(0, new_dir.find_last_of("\\"));
669 		if (!FileExists(new_dir.c_str()))
670 			mkdir(new_dir.c_str()
671 #ifndef WIN32
672 			,0777
673 #endif
674 			);
675 
676 		if (FileExists(extracted_filename.c_str()))
677 		{
678 			std::string new_name(filepath);
679 			new_name.append("old-");
680 			new_name.append(fex_name(fex));
681 #ifdef WIN32
682 			replaceAll(new_name, "/", "\\");
683 #endif
684 			remove(new_name.c_str());
685 			rename(extracted_filename.c_str(), new_name.c_str());
686 		}
687 
688 		FILE *extracted_file = fopen(extracted_filename.c_str(), "wb");
689 		const void* p;
690 		fex_data(fex, &p);
691 		fwrite(p, fex_size(fex), 1, extracted_file);
692 		fclose(extracted_file);
693 		fex_next(fex);
694 	}
695 	fex_close(fex);
696 
697 }
698 
utilWriteInt(gzFile gzFile,int i)699 void utilWriteInt(gzFile gzFile, int i)
700 {
701   utilGzWrite(gzFile, &i, sizeof(int));
702 }
703 
utilReadInt(gzFile gzFile)704 int utilReadInt(gzFile gzFile)
705 {
706   int i = 0;
707   utilGzRead(gzFile, &i, sizeof(int));
708   return i;
709 }
710 
utilReadData(gzFile gzFile,variable_desc * data)711 void utilReadData(gzFile gzFile, variable_desc* data)
712 {
713   while(data->address) {
714     utilGzRead(gzFile, data->address, data->size);
715     data++;
716   }
717 }
718 
utilReadDataSkip(gzFile gzFile,variable_desc * data)719 void utilReadDataSkip(gzFile gzFile, variable_desc* data)
720 {
721   while(data->address) {
722     utilGzSeek(gzFile, data->size, SEEK_CUR);
723     data++;
724   }
725 }
726 
utilWriteData(gzFile gzFile,variable_desc * data)727 void utilWriteData(gzFile gzFile, variable_desc *data)
728 {
729   while(data->address) {
730     utilGzWrite(gzFile, data->address, data->size);
731     data++;
732   }
733 }
734 
utilGzOpen(const char * file,const char * mode)735 gzFile utilGzOpen(const char *file, const char *mode)
736 {
737   utilGzWriteFunc = (int (ZEXPORT *)(gzFile, void * const, unsigned int))gzwrite;
738   utilGzReadFunc = gzread;
739   utilGzCloseFunc = gzclose;
740   utilGzSeekFunc = gzseek;
741 
742   return gzopen(file, mode);
743 }
744 
utilMemGzOpen(char * memory,int available,const char * mode)745 gzFile utilMemGzOpen(char *memory, int available, const char *mode)
746 {
747   utilGzWriteFunc = memgzwrite;
748   utilGzReadFunc = memgzread;
749   utilGzCloseFunc = memgzclose;
750   utilGzSeekFunc = memgzseek;
751 
752   return memgzopen(memory, available, mode);
753 }
754 
utilGzWrite(gzFile file,const voidp buffer,unsigned int len)755 int utilGzWrite(gzFile file, const voidp buffer, unsigned int len)
756 {
757   return utilGzWriteFunc(file, buffer, len);
758 }
759 
utilGzRead(gzFile file,voidp buffer,unsigned int len)760 int utilGzRead(gzFile file, voidp buffer, unsigned int len)
761 {
762   return utilGzReadFunc(file, buffer, len);
763 }
764 
utilGzClose(gzFile file)765 int utilGzClose(gzFile file)
766 {
767   return utilGzCloseFunc(file);
768 }
769 
utilGzSeek(gzFile file,z_off_t offset,int whence)770 z_off_t utilGzSeek(gzFile file, z_off_t offset, int whence)
771 {
772 	return utilGzSeekFunc(file, offset, whence);
773 }
774 
utilGzMemTell(gzFile file)775 long utilGzMemTell(gzFile file)
776 {
777   return memtell(file);
778 }
779 
utilGBAFindSave(const int size)780 void utilGBAFindSave(const int size)
781 {
782   u32 *p = (u32 *)&rom[0];
783   u32 *end = (u32 *)(&rom[0] + size);
784   int detectedSaveType = 0;
785   int flashSize = 0x10000;
786   bool rtcFound = false;
787 
788   while(p  < end) {
789     u32 d = READ32LE(p);
790 
791     if(d == 0x52504545) {
792       if(memcmp(p, "EEPROM_", 7) == 0) {
793         if(detectedSaveType == 0 || detectedSaveType == 4)
794           detectedSaveType = 1;
795       }
796     } else if (d == 0x4D415253) {
797       if(memcmp(p, "SRAM_", 5) == 0) {
798         if(detectedSaveType == 0 || detectedSaveType == 1 || detectedSaveType == 4)
799           detectedSaveType = 2;
800       }
801     } else if (d == 0x53414C46) {
802       if(memcmp(p, "FLASH1M_", 8) == 0) {
803         if(detectedSaveType == 0) {
804           detectedSaveType = 3;
805           flashSize = 0x20000;
806         }
807 	  } else if (memcmp(p, "FLASH512_", 9) == 0) {
808 		  if (detectedSaveType == 0) {
809 			  detectedSaveType = 3;
810 			  flashSize = 0x10000;
811 		  }
812       } else if(memcmp(p, "FLASH", 5) == 0) {
813         if(detectedSaveType == 0) {
814           detectedSaveType = 4;
815           flashSize = 0x10000;
816         }
817       }
818     } else if (d == 0x52494953) {
819       if(memcmp(p, "SIIRTC_V", 8) == 0)
820         rtcFound = true;
821     }
822     p++;
823   }
824   // if no matches found, then set it to NONE
825   if(detectedSaveType == 0) {
826     detectedSaveType = 5;
827   }
828   if(detectedSaveType == 4) {
829     detectedSaveType = 3;
830   }
831   rtcEnable(rtcFound);
832   rtcEnableRumble(!rtcFound);
833   saveType = detectedSaveType;
834   flashSetSize(flashSize);
835 }
836 
utilUpdateSystemColorMaps(bool lcd)837 void utilUpdateSystemColorMaps(bool lcd)
838 {
839   switch(systemColorDepth) {
840   case 16:
841     {
842       for(int i = 0; i < 0x10000; i++) {
843         systemColorMap16[i] = ((i & 0x1f) << systemRedShift) |
844           (((i & 0x3e0) >> 5) << systemGreenShift) |
845           (((i & 0x7c00) >> 10) << systemBlueShift);
846       }
847       if (lcd) gbafilter_pal(systemColorMap16, 0x10000);
848     }
849     break;
850   case 24:
851   case 32:
852     {
853       for(int i = 0; i < 0x10000; i++) {
854         systemColorMap32[i] = ((i & 0x1f) << systemRedShift) |
855           (((i & 0x3e0) >> 5) << systemGreenShift) |
856           (((i & 0x7c00) >> 10) << systemBlueShift);
857       }
858       if (lcd) gbafilter_pal32(systemColorMap32, 0x10000);
859     }
860     break;
861   }
862 }
863 
864 // Check for existence of file.
utilFileExists(const char * filename)865 bool utilFileExists( const char *filename )
866 {
867 	FILE *f = fopen( filename, "r" );
868 	if( f == NULL ) {
869 		return false;
870 	} else {
871 		fclose( f );
872 		return true;
873 	}
874 }
875