rlm@1: #include rlm@1: #include rlm@1: #include rlm@1: #include rlm@1: rlm@1: extern "C" { rlm@1: #include rlm@1: } rlm@1: rlm@1: #if 0 rlm@1: #include "unrarlib.h" rlm@1: #endif rlm@1: rlm@1: #include "unzip.h" rlm@1: rlm@1: #include "../NLS.h" rlm@1: #include "System.h" rlm@1: #include "Util.h" rlm@1: #include "../gba/Flash.h" rlm@1: #include "../gba/RTC.h" rlm@1: rlm@1: extern "C" { rlm@1: #include "memgzio.h" rlm@1: } rlm@1: rlm@1: #ifndef _MSC_VER rlm@1: #define _stricmp strcasecmp rlm@1: #endif // ! _MSC_VER rlm@1: rlm@1: extern int32 cpuSaveType; rlm@1: rlm@1: extern int systemColorDepth; rlm@1: extern int systemRedShift; rlm@1: extern int systemGreenShift; rlm@1: extern int systemBlueShift; rlm@1: rlm@1: extern u16 systemColorMap16[0x10000]; rlm@1: extern u32 systemColorMap32[0x10000]; rlm@1: rlm@1: static int (ZEXPORT *utilGzWriteFunc)(gzFile, voidp, unsigned int) = NULL; rlm@1: static int (ZEXPORT *utilGzReadFunc)(gzFile, voidp, unsigned int) = NULL; rlm@1: static int (ZEXPORT *utilGzCloseFunc)(gzFile) = NULL; rlm@1: static z_off_t (ZEXPORT *utilGzSeekFunc)(gzFile, z_off_t, int) = NULL; rlm@1: static z_off_t (ZEXPORT *utilGzTellFunc)(gzFile) = NULL; rlm@1: rlm@1: //Kludge to get it to compile in Linux, GCC cannot convert rlm@1: //gzwrite function pointer to the type of utilGzWriteFunc rlm@1: //due to void* and const void* differences rlm@1: //--Felipe rlm@1: int gzWrite(gzFile file, void* buf, unsigned len){ rlm@496: return gzwrite(file,buf,len); rlm@1: } rlm@1: rlm@1: void utilPutDword(u8 *p, u32 value) rlm@1: { rlm@496: *p++ = value & 255; rlm@496: *p++ = (value >> 8) & 255; rlm@496: *p++ = (value >> 16) & 255; rlm@496: *p = (value >> 24) & 255; rlm@1: } rlm@1: rlm@1: void utilPutWord(u8 *p, u16 value) rlm@1: { rlm@496: *p++ = value & 255; rlm@496: *p = (value >> 8) & 255; rlm@1: } rlm@1: rlm@1: void utilWriteBMP(u8 *b, int w, int h, int dstDepth, u8 *pix) rlm@1: { rlm@496: int sizeX = w; rlm@496: int sizeY = h; rlm@1: rlm@496: switch (dstDepth > 0 ? dstDepth : systemColorDepth) rlm@496: { rlm@496: case 16: rlm@496: { rlm@496: u16 *p = (u16 *)(pix + (w + 2) * (h) * 2); // skip first black line rlm@496: for (int y = 0; y < sizeY; y++) rlm@496: { rlm@496: for (int x = 0; x < sizeX; x++) rlm@496: { rlm@496: u16 v = *p++; rlm@1: rlm@496: *b++ = ((v >> systemBlueShift) & 0x01f) << 3; // B rlm@496: *b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G rlm@496: *b++ = ((v >> systemRedShift) & 0x001f) << 3; // R rlm@496: } rlm@496: p++; // skip black pixel for filters rlm@496: p++; // skip black pixel for filters rlm@496: p -= 2 * (w + 2); rlm@496: } rlm@496: break; rlm@496: } rlm@496: case 24: rlm@496: { rlm@496: u8 *pixU8 = (u8 *)pix + 3 * w * (h - 1); rlm@496: for (int y = 0; y < sizeY; y++) rlm@496: { rlm@496: for (int x = 0; x < sizeX; x++) rlm@496: { rlm@496: if (systemRedShift > systemBlueShift) rlm@496: { rlm@496: *b++ = *pixU8++; // B rlm@496: *b++ = *pixU8++; // G rlm@496: *b++ = *pixU8++; // R rlm@496: } rlm@496: else rlm@496: { rlm@496: int red = *pixU8++; rlm@496: int green = *pixU8++; rlm@496: int blue = *pixU8++; rlm@1: rlm@496: *b++ = blue; rlm@496: *b++ = green; rlm@496: *b++ = red; rlm@496: } rlm@496: } rlm@496: pixU8 -= 2 * 3 * w; rlm@496: } rlm@496: break; rlm@496: } rlm@496: case 32: rlm@496: { rlm@496: u32 *pixU32 = (u32 *)(pix + 4 * (w + 1) * (h)); rlm@496: for (int y = 0; y < sizeY; y++) rlm@496: { rlm@496: for (int x = 0; x < sizeX; x++) rlm@496: { rlm@496: u32 v = *pixU32++; rlm@496: //RLM pack bits for java ARGB rlm@1: rlm@496: rlm@496: *b++ = ((v >> systemRedShift) & 0x001f) << 3; // R rlm@496: *b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G rlm@496: *b++ = ((v >> systemBlueShift) & 0x001f) << 3; // B rlm@496: *b++ = 0; // Alpha rlm@496: rlm@496: rlm@496: rlm@496: // end RLM rlm@496: rlm@496: rlm@496: } rlm@496: pixU32++; rlm@496: pixU32 -= 2 * (w + 1); rlm@496: } rlm@496: break; rlm@496: } rlm@496: } rlm@1: } rlm@1: rlm@1: bool utilWriteBMPFile(const char *fileName, int w, int h, u8 *pix) rlm@1: { rlm@496: u8 writeBuffer[256 * 3]; rlm@1: rlm@496: FILE *fp = fopen(fileName, "wb"); rlm@1: rlm@496: if (!fp) rlm@496: { rlm@496: systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), fileName); rlm@496: return false; rlm@496: } rlm@1: rlm@496: struct rlm@496: { rlm@496: u8 ident[2]; rlm@496: u8 filesize[4]; rlm@496: u8 reserved[4]; rlm@496: u8 dataoffset[4]; rlm@496: u8 headersize[4]; rlm@496: u8 width[4]; rlm@496: u8 height[4]; rlm@496: u8 planes[2]; rlm@496: u8 bitsperpixel[2]; rlm@496: u8 compression[4]; rlm@496: u8 datasize[4]; rlm@496: u8 hres[4]; rlm@496: u8 vres[4]; rlm@496: u8 colors[4]; rlm@496: u8 importantcolors[4]; rlm@496: // u8 pad[2]; rlm@496: } bmpheader; rlm@496: memset(&bmpheader, 0, sizeof(bmpheader)); rlm@1: rlm@496: bmpheader.ident[0] = 'B'; rlm@496: bmpheader.ident[1] = 'M'; rlm@1: rlm@496: u32 fsz = sizeof(bmpheader) + w * h * 3; rlm@496: utilPutDword(bmpheader.filesize, fsz); rlm@496: utilPutDword(bmpheader.dataoffset, 0x36); rlm@496: utilPutDword(bmpheader.headersize, 0x28); rlm@496: utilPutDword(bmpheader.width, w); rlm@496: utilPutDword(bmpheader.height, h); rlm@496: utilPutDword(bmpheader.planes, 1); rlm@496: utilPutDword(bmpheader.bitsperpixel, 24); rlm@496: utilPutDword(bmpheader.datasize, 3 * w * h); rlm@1: rlm@496: fwrite(&bmpheader, 1, sizeof(bmpheader), fp); rlm@1: rlm@1: #if 0 rlm@496: // FIXME: need sufficient buffer rlm@496: utilWriteBMP(writeBuffer, w, h, systemColorDepth, pix); rlm@1: #else rlm@496: u8 *b = writeBuffer; rlm@1: rlm@496: int sizeX = w; rlm@496: int sizeY = h; rlm@1: rlm@496: switch (systemColorDepth) rlm@496: { rlm@496: case 16: rlm@496: { rlm@496: u16 *p = (u16 *)(pix + (w + 2) * (h) * 2); // skip first black line rlm@496: for (int y = 0; y < sizeY; y++) rlm@496: { rlm@496: for (int x = 0; x < sizeX; x++) rlm@496: { rlm@496: u16 v = *p++; rlm@1: rlm@496: *b++ = ((v >> systemBlueShift) & 0x01f) << 3; // B rlm@496: *b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G rlm@496: *b++ = ((v >> systemRedShift) & 0x001f) << 3; // R rlm@496: } rlm@496: p++; // skip black pixel for filters rlm@496: p++; // skip black pixel for filters rlm@496: p -= 2 * (w + 2); rlm@496: fwrite(writeBuffer, 1, 3 * w, fp); rlm@1: rlm@496: b = writeBuffer; rlm@496: } rlm@496: break; rlm@496: } rlm@496: case 24: rlm@496: { rlm@496: u8 *pixU8 = (u8 *)pix + 3 * w * (h - 1); rlm@496: for (int y = 0; y < sizeY; y++) rlm@496: { rlm@496: for (int x = 0; x < sizeX; x++) rlm@496: { rlm@496: if (systemRedShift > systemBlueShift) rlm@496: { rlm@496: *b++ = *pixU8++; // B rlm@496: *b++ = *pixU8++; // G rlm@496: *b++ = *pixU8++; // R rlm@496: } rlm@496: else rlm@496: { rlm@496: int red = *pixU8++; rlm@496: int green = *pixU8++; rlm@496: int blue = *pixU8++; rlm@1: rlm@496: *b++ = blue; rlm@496: *b++ = green; rlm@496: *b++ = red; rlm@496: } rlm@496: } rlm@496: pixU8 -= 2 * 3 * w; rlm@496: fwrite(writeBuffer, 1, 3 * w, fp); rlm@1: rlm@496: b = writeBuffer; rlm@496: } rlm@496: break; rlm@496: } rlm@496: case 32: rlm@496: { rlm@496: u32 *pixU32 = (u32 *)(pix + 4 * (w + 1) * (h)); rlm@496: for (int y = 0; y < sizeY; y++) rlm@496: { rlm@496: for (int x = 0; x < sizeX; x++) rlm@496: { rlm@496: u32 v = *pixU32++; rlm@1: rlm@496: *b++ = ((v >> systemBlueShift) & 0x001f) << 3; // B rlm@496: *b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G rlm@496: *b++ = ((v >> systemRedShift) & 0x001f) << 3; // R rlm@496: } rlm@496: pixU32++; rlm@496: pixU32 -= 2 * (w + 1); rlm@1: rlm@496: fwrite(writeBuffer, 1, 3 * w, fp); rlm@1: rlm@496: b = writeBuffer; rlm@496: } rlm@496: break; rlm@496: } rlm@496: } rlm@1: #endif rlm@1: rlm@496: fclose(fp); rlm@1: rlm@496: return true; rlm@1: } rlm@1: rlm@1: bool utilWritePNGFile(const char *fileName, int w, int h, u8 *pix) rlm@1: { rlm@41: u8 writeBuffer[256 * 3]; rlm@1: rlm@41: FILE *fp = fopen(fileName, "wb"); rlm@1: rlm@41: if (!fp) rlm@41: { rlm@41: systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), fileName); rlm@41: return false; rlm@41: } rlm@1: rlm@41: png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, rlm@41: NULL, rlm@41: NULL, rlm@41: NULL); rlm@41: if (!png_ptr) rlm@41: { rlm@41: fclose(fp); rlm@41: return false; rlm@41: } rlm@1: rlm@41: png_infop info_ptr = png_create_info_struct(png_ptr); rlm@1: rlm@41: if (!info_ptr) rlm@41: { rlm@41: png_destroy_write_struct(&png_ptr, NULL); rlm@41: fclose(fp); rlm@41: return false; rlm@41: } rlm@1: rlm@41: if (setjmp(png_jmpbuf(png_ptr))) rlm@41: { rlm@41: png_destroy_write_struct(&png_ptr, NULL); rlm@41: fclose(fp); rlm@41: return false; rlm@41: } rlm@1: rlm@41: png_init_io(png_ptr, fp); rlm@1: rlm@41: png_set_IHDR(png_ptr, rlm@41: info_ptr, rlm@41: w, rlm@41: h, rlm@41: 8, rlm@41: PNG_COLOR_TYPE_RGB, rlm@41: PNG_INTERLACE_NONE, rlm@41: PNG_COMPRESSION_TYPE_DEFAULT, rlm@41: PNG_FILTER_TYPE_DEFAULT); rlm@1: rlm@41: png_write_info(png_ptr, info_ptr); rlm@1: rlm@41: u8 *b = writeBuffer; rlm@1: rlm@41: int sizeX = w; rlm@41: int sizeY = h; rlm@1: rlm@41: switch (systemColorDepth) rlm@41: { rlm@41: case 16: rlm@41: { rlm@41: u16 *p = (u16 *)(pix + (w + 2) * 2); // skip first black line rlm@41: for (int y = 0; y < sizeY; y++) rlm@41: { rlm@41: for (int x = 0; x < sizeX; x++) rlm@41: { rlm@41: u16 v = *p++; rlm@1: rlm@41: *b++ = ((v >> systemRedShift) & 0x001f) << 3; // R rlm@41: *b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G rlm@41: *b++ = ((v >> systemBlueShift) & 0x01f) << 3; // B rlm@41: } rlm@41: p++; // skip black pixel for filters rlm@41: p++; // skip black pixel for filters rlm@41: png_write_row(png_ptr, writeBuffer); rlm@1: rlm@41: b = writeBuffer; rlm@41: } rlm@41: break; rlm@41: } rlm@41: case 24: rlm@41: { rlm@41: u8 *pixU8 = (u8 *)pix; rlm@41: for (int y = 0; y < sizeY; y++) rlm@41: { rlm@41: for (int x = 0; x < sizeX; x++) rlm@41: { rlm@41: if (systemRedShift < systemBlueShift) rlm@41: { rlm@41: *b++ = *pixU8++; // R rlm@41: *b++ = *pixU8++; // G rlm@41: *b++ = *pixU8++; // B rlm@41: } rlm@41: else rlm@41: { rlm@41: int blue = *pixU8++; rlm@41: int green = *pixU8++; rlm@41: int red = *pixU8++; rlm@1: rlm@41: *b++ = red; rlm@41: *b++ = green; rlm@41: *b++ = blue; rlm@41: } rlm@41: } rlm@41: png_write_row(png_ptr, writeBuffer); rlm@1: rlm@41: b = writeBuffer; rlm@41: } rlm@41: break; rlm@41: } rlm@41: case 32: rlm@41: { rlm@41: u32 *pixU32 = (u32 *)(pix + 4 * (w + 1)); rlm@41: for (int y = 0; y < sizeY; y++) rlm@41: { rlm@41: for (int x = 0; x < sizeX; x++) rlm@41: { rlm@41: u32 v = *pixU32++; rlm@1: rlm@41: *b++ = ((v >> systemRedShift) & 0x001f) << 3; // R rlm@41: *b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G rlm@41: *b++ = ((v >> systemBlueShift) & 0x001f) << 3; // B rlm@41: } rlm@41: pixU32++; rlm@1: rlm@41: png_write_row(png_ptr, writeBuffer); rlm@1: rlm@41: b = writeBuffer; rlm@41: } rlm@41: break; rlm@41: } rlm@41: } rlm@1: rlm@41: png_write_end(png_ptr, info_ptr); rlm@1: rlm@41: png_destroy_write_struct(&png_ptr, &info_ptr); rlm@1: rlm@41: fclose(fp); rlm@1: rlm@41: return true; rlm@1: } rlm@1: rlm@1: static int utilReadInt2(FILE *f) rlm@1: { rlm@496: int res = 0; rlm@496: int c = fgetc(f); rlm@496: if (c == EOF) rlm@496: return -1; rlm@496: res = c; rlm@496: c = fgetc(f); rlm@496: if (c == EOF) rlm@496: return -1; rlm@496: return c + (res << 8); rlm@1: } rlm@1: rlm@1: static int utilReadInt3(FILE *f) rlm@1: { rlm@496: int res = 0; rlm@496: int c = fgetc(f); rlm@496: if (c == EOF) rlm@496: return -1; rlm@496: res = c; rlm@496: c = fgetc(f); rlm@496: if (c == EOF) rlm@496: return -1; rlm@496: res = c + (res << 8); rlm@496: c = fgetc(f); rlm@496: if (c == EOF) rlm@496: return -1; rlm@496: return c + (res << 8); rlm@1: } rlm@1: rlm@1: void utilApplyIPS(const char *ips, u8 * *r, int *s) rlm@1: { rlm@496: // from the IPS spec at http://zerosoft.zophar.net/ips.htm rlm@496: FILE *f = fopen(ips, "rb"); rlm@496: if (!f) rlm@496: return; rlm@496: u8 *rom = *r; rlm@496: int size = *s; rlm@496: if (fgetc(f) == 'P' && rlm@496: fgetc(f) == 'A' && rlm@496: fgetc(f) == 'T' && rlm@496: fgetc(f) == 'C' && rlm@496: fgetc(f) == 'H') rlm@496: { rlm@496: int b; rlm@496: int offset; rlm@496: int len; rlm@496: for (;; ) rlm@1: { rlm@496: // read offset rlm@496: offset = utilReadInt3(f); rlm@496: // if offset == EOF, end of patch rlm@496: if (offset == 0x454f46) rlm@496: break; rlm@496: // read length rlm@496: len = utilReadInt2(f); rlm@496: if (!len) rlm@496: { rlm@496: // len == 0, RLE block rlm@496: len = utilReadInt2(f); rlm@496: // byte to fill rlm@496: int c = fgetc(f); rlm@496: if (c == -1) rlm@496: break; rlm@496: b = (u8)c; rlm@496: } rlm@496: else rlm@496: b = -1; rlm@496: // check if we need to reallocate our ROM rlm@496: if ((offset + len) >= size) rlm@496: { rlm@496: size *= 2; rlm@496: rom = (u8 *)realloc(rom, size); rlm@496: *r = rom; rlm@496: *s = size; rlm@496: } rlm@496: if (b == -1) rlm@496: { rlm@496: // normal block, just read the data rlm@496: if (fread(&rom[offset], 1, len, f) != (size_t)len) rlm@496: break; rlm@496: } rlm@496: else rlm@496: { rlm@496: // fill the region with the given byte rlm@496: while (len--) rlm@1: { rlm@496: rom[offset++] = b; rlm@1: } rlm@496: } rlm@1: } rlm@496: } rlm@496: // close the file rlm@496: fclose(f); rlm@1: } rlm@1: rlm@1: extern bool8 cpuIsMultiBoot; rlm@1: rlm@1: bool utilIsGBAImage(const char *file) rlm@1: { rlm@496: cpuIsMultiBoot = false; rlm@496: if (strlen(file) > 4) rlm@496: { rlm@496: const char *p = strrchr(file, '.'); rlm@496: rlm@496: if (p != NULL) rlm@1: { rlm@496: if (_stricmp(p, ".gba") == 0) rlm@496: return true; rlm@496: if (_stricmp(p, ".agb") == 0) rlm@496: return true; rlm@496: if (_stricmp(p, ".bin") == 0) rlm@496: return true; rlm@496: if (_stricmp(p, ".elf") == 0) rlm@496: return true; rlm@496: if (_stricmp(p, ".mb") == 0) rlm@496: { rlm@496: cpuIsMultiBoot = true; rlm@496: return true; rlm@496: } rlm@496: } rlm@496: } rlm@1: rlm@496: return false; rlm@1: } rlm@1: rlm@1: bool utilIsGBImage(const char *file) rlm@1: { rlm@496: if (strlen(file) > 4) rlm@496: { rlm@496: const char *p = strrchr(file, '.'); rlm@496: rlm@496: if (p != NULL) rlm@1: { rlm@496: if (_stricmp(p, ".gb") == 0) rlm@496: return true; rlm@496: if (_stricmp(p, ".gbc") == 0) rlm@496: return true; rlm@496: if (_stricmp(p, ".cgb") == 0) rlm@496: return true; rlm@496: if (_stricmp(p, ".sgb") == 0) rlm@496: return true; rlm@496: } rlm@496: } rlm@1: rlm@496: return false; rlm@1: } rlm@1: rlm@1: bool utilIsGBABios(const char *file) rlm@1: { rlm@496: if (strlen(file) > 4) rlm@496: { rlm@496: const char *p = strrchr(file, '.'); rlm@496: rlm@496: if (p != NULL) rlm@1: { rlm@496: if (_stricmp(p, ".gba") == 0) rlm@496: return true; rlm@496: if (_stricmp(p, ".agb") == 0) rlm@496: return true; rlm@496: if (_stricmp(p, ".bin") == 0) rlm@496: return true; rlm@496: if (_stricmp(p, ".bios") == 0) rlm@496: return true; rlm@496: if (_stricmp(p, ".rom") == 0) rlm@496: return true; rlm@496: } rlm@496: } rlm@1: rlm@496: return false; rlm@1: } rlm@1: rlm@1: bool utilIsGBBios(const char *file) rlm@1: { rlm@496: if (strlen(file) > 4) rlm@496: { rlm@496: const char *p = strrchr(file, '.'); rlm@496: rlm@496: if (p != NULL) rlm@1: { rlm@496: if (_stricmp(p, ".gb") == 0) rlm@496: return true; rlm@496: if (_stricmp(p, ".bin") == 0) rlm@496: return true; rlm@496: if (_stricmp(p, ".bios") == 0) rlm@496: return true; rlm@496: if (_stricmp(p, ".rom") == 0) rlm@496: return true; rlm@496: } rlm@496: } rlm@1: rlm@496: return false; rlm@1: } rlm@1: rlm@1: bool utilIsELF(const char *file) rlm@1: { rlm@496: if (strlen(file) > 4) rlm@496: { rlm@496: const char *p = strrchr(file, '.'); rlm@496: rlm@496: if (p != NULL) rlm@1: { rlm@496: if (_stricmp(p, ".elf") == 0) rlm@496: return true; rlm@1: } rlm@496: } rlm@496: return false; rlm@1: } rlm@1: rlm@1: bool utilIsZipFile(const char *file) rlm@1: { rlm@496: if (strlen(file) > 4) rlm@496: { rlm@496: const char *p = strrchr(file, '.'); rlm@496: rlm@496: if (p != NULL) rlm@1: { rlm@496: if (_stricmp(p, ".zip") == 0) rlm@496: return true; rlm@496: } rlm@496: } rlm@1: rlm@496: return false; rlm@1: } rlm@1: rlm@1: #if 0 rlm@1: bool utilIsRarFile(const char *file) rlm@1: { rlm@496: if (strlen(file) > 4) rlm@496: { rlm@496: char *p = strrchr(file, '.'); rlm@496: rlm@496: if (p != NULL) rlm@1: { rlm@496: if (_stricmp(p, ".rar") == 0) rlm@496: return true; rlm@496: } rlm@496: } rlm@1: rlm@496: return false; rlm@1: } rlm@1: rlm@1: #endif rlm@1: rlm@1: bool utilIsGzipFile(const char *file) rlm@1: { rlm@496: if (strlen(file) > 3) rlm@496: { rlm@496: const char *p = strrchr(file, '.'); rlm@496: rlm@496: if (p != NULL) rlm@1: { rlm@496: if (_stricmp(p, ".gz") == 0) rlm@496: return true; rlm@496: if (_stricmp(p, ".z") == 0) rlm@496: return true; rlm@496: } rlm@496: } rlm@1: rlm@496: return false; rlm@1: } rlm@1: rlm@1: void utilGetBaseName(const char *file, char *buffer) rlm@1: { rlm@496: strcpy(buffer, file); rlm@1: rlm@496: if (utilIsGzipFile(file)) rlm@496: { rlm@496: char *p = strrchr(buffer, '.'); rlm@1: rlm@496: if (p) rlm@496: *p = 0; rlm@496: } rlm@1: } rlm@1: rlm@1: IMAGE_TYPE utilFindType(const char *file) rlm@1: { rlm@496: char buffer[2048]; rlm@1: rlm@496: if (utilIsZipFile(file)) rlm@496: { rlm@496: unzFile unz = unzOpen(file); rlm@496: rlm@496: if (unz == NULL) rlm@1: { rlm@496: systemMessage(MSG_CANNOT_OPEN_FILE, N_("Cannot open file %s"), file); rlm@496: return IMAGE_UNKNOWN; rlm@496: } rlm@1: rlm@496: int r = unzGoToFirstFile(unz); rlm@496: rlm@496: if (r != UNZ_OK) rlm@496: { rlm@496: unzClose(unz); rlm@496: systemMessage(MSG_BAD_ZIP_FILE, N_("Bad ZIP file %s"), file); rlm@496: return IMAGE_UNKNOWN; rlm@496: } rlm@496: rlm@496: IMAGE_TYPE found = IMAGE_UNKNOWN; rlm@496: rlm@496: unz_file_info info; rlm@496: rlm@496: while (true) rlm@496: { rlm@496: r = unzGetCurrentFileInfo(unz, rlm@496: &info, rlm@496: buffer, rlm@496: sizeof(buffer), rlm@496: NULL, rlm@496: 0, rlm@496: NULL, rlm@496: 0); rlm@496: rlm@496: if (r != UNZ_OK) rlm@496: { rlm@496: unzClose(unz); rlm@496: systemMessage(MSG_BAD_ZIP_FILE, N_("Bad ZIP file %s"), file); rlm@496: return IMAGE_UNKNOWN; rlm@496: } rlm@496: rlm@496: if (utilIsGBAImage(buffer)) rlm@496: { rlm@496: found = IMAGE_GBA; rlm@496: break; rlm@496: } rlm@496: rlm@496: if (utilIsGBImage(buffer)) rlm@496: { rlm@496: found = IMAGE_GB; rlm@496: break; rlm@496: } rlm@496: rlm@496: r = unzGoToNextFile(unz); rlm@496: rlm@496: if (r != UNZ_OK) rlm@496: break; rlm@496: } rlm@496: unzClose(unz); rlm@496: rlm@496: if (found == IMAGE_UNKNOWN) rlm@496: { rlm@496: systemMessage(MSG_NO_IMAGE_ON_ZIP, rlm@496: N_("No image found on ZIP file %s"), file); rlm@496: return found; rlm@496: } rlm@496: return found; rlm@496: #if 0 rlm@496: } rlm@496: else if (utilIsRarFile(file)) rlm@496: { rlm@496: IMAGE_TYPE found = IMAGE_UNKNOWN; rlm@496: rlm@496: ArchiveList_struct *rarList = NULL; rlm@496: if (urarlib_list((void *)file, (ArchiveList_struct *)&rarList)) rlm@496: { rlm@496: ArchiveList_struct *p = rarList; rlm@496: rlm@496: while (p) rlm@496: { rlm@496: if (utilIsGBAImage(p->item.Name)) rlm@1: { rlm@496: found = IMAGE_GBA; rlm@496: break; rlm@1: } rlm@1: rlm@496: if (utilIsGBImage(p->item.Name)) rlm@496: { rlm@496: found = IMAGE_GB; rlm@496: break; rlm@496: } rlm@496: p = p->next; rlm@496: } rlm@1: rlm@496: urarlib_freelist(rarList); rlm@496: } rlm@496: return found; rlm@496: #endif rlm@496: } rlm@496: else rlm@496: { rlm@496: if (utilIsGzipFile(file)) rlm@496: utilGetBaseName(file, buffer); rlm@496: else rlm@496: strcpy(buffer, file); rlm@1: rlm@496: if (utilIsGBAImage(buffer)) rlm@496: return IMAGE_GBA; rlm@496: if (utilIsGBImage(buffer)) rlm@496: return IMAGE_GB; rlm@496: } rlm@496: return IMAGE_UNKNOWN; rlm@1: } rlm@1: rlm@1: static int utilGetSize(int size) rlm@1: { rlm@496: int res = 1; rlm@496: while (res < size) rlm@496: res <<= 1; rlm@496: return res; rlm@1: } rlm@1: rlm@1: static u8 *utilLoadFromZip(const char *file, rlm@1: bool (*accept)(const char *), rlm@1: u8 *data, rlm@1: int &size) rlm@1: { rlm@496: char buffer[2048]; rlm@1: rlm@496: unzFile unz = unzOpen(file); rlm@1: rlm@496: if (unz == NULL) rlm@496: { rlm@496: systemMessage(MSG_CANNOT_OPEN_FILE, N_("Cannot open file %s"), file); rlm@496: return NULL; rlm@496: } rlm@496: int r = unzGoToFirstFile(unz); rlm@496: rlm@496: if (r != UNZ_OK) rlm@496: { rlm@496: unzClose(unz); rlm@496: systemMessage(MSG_BAD_ZIP_FILE, N_("Bad ZIP file %s"), file); rlm@496: return NULL; rlm@496: } rlm@496: rlm@496: bool found = false; rlm@496: rlm@496: unz_file_info info; rlm@496: rlm@496: while (true) rlm@496: { rlm@496: r = unzGetCurrentFileInfo(unz, rlm@496: &info, rlm@496: buffer, rlm@496: sizeof(buffer), rlm@496: NULL, rlm@496: 0, rlm@496: NULL, rlm@496: 0); rlm@496: rlm@496: if (r != UNZ_OK) rlm@1: { rlm@496: unzClose(unz); rlm@496: systemMessage(MSG_BAD_ZIP_FILE, N_("Bad ZIP file %s"), file); rlm@496: return NULL; rlm@1: } rlm@1: rlm@496: if (accept(buffer)) rlm@1: { rlm@496: found = true; rlm@496: break; rlm@1: } rlm@1: rlm@496: r = unzGoToNextFile(unz); rlm@496: rlm@496: if (r != UNZ_OK) rlm@496: break; rlm@496: } rlm@496: rlm@496: if (!found) rlm@496: { rlm@496: unzClose(unz); rlm@496: systemMessage(MSG_NO_IMAGE_ON_ZIP, rlm@496: N_("No image found on ZIP file %s"), file); rlm@496: return NULL; rlm@496: } rlm@496: rlm@496: int fileSize = info.uncompressed_size; rlm@496: if (size == 0) rlm@496: size = fileSize; rlm@496: r = unzOpenCurrentFile(unz); rlm@496: rlm@496: if (r != UNZ_OK) rlm@496: { rlm@496: unzClose(unz); rlm@496: systemMessage(MSG_ERROR_OPENING_IMAGE, N_("Error opening image %s"), buffer); rlm@496: return NULL; rlm@496: } rlm@496: rlm@496: u8 *image = data; rlm@496: rlm@496: if (image == NULL) rlm@496: { rlm@496: image = (u8 *)malloc(utilGetSize(size)); rlm@496: if (image == NULL) rlm@1: { rlm@496: unzCloseCurrentFile(unz); rlm@496: unzClose(unz); rlm@496: systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), rlm@496: "data"); rlm@496: return NULL; rlm@1: } rlm@496: size = fileSize; rlm@496: } rlm@496: int read = fileSize <= size ? fileSize : size; rlm@496: r = unzReadCurrentFile(unz, rlm@496: image, rlm@496: read); rlm@1: rlm@496: unzCloseCurrentFile(unz); rlm@496: unzClose(unz); rlm@1: rlm@496: if (r != (int)read) rlm@496: { rlm@496: systemMessage(MSG_ERROR_READING_IMAGE, rlm@496: N_("Error reading image %s"), buffer); rlm@496: if (data == NULL) rlm@496: free(image); rlm@496: return NULL; rlm@496: } rlm@1: rlm@496: size = fileSize; rlm@1: rlm@496: return image; rlm@1: } rlm@1: rlm@1: static u8 *utilLoadGzipFile(const char *file, rlm@1: bool (*accept)(const char *), rlm@1: u8 *data, rlm@1: int &size) rlm@1: { rlm@496: FILE *f = fopen(file, "rb"); rlm@1: rlm@496: if (f == NULL) rlm@496: { rlm@496: systemMessage(MSG_ERROR_OPENING_IMAGE, N_("Error opening image %s"), file); rlm@496: return NULL; rlm@496: } rlm@496: rlm@496: fseek(f, -4, SEEK_END); rlm@496: int fileSize = fgetc(f) | (fgetc(f) << 8) | (fgetc(f) << 16) | (fgetc(f) << 24); rlm@496: fclose(f); rlm@496: if (size == 0) rlm@496: size = fileSize; rlm@496: rlm@496: gzFile gz = gzopen(file, "rb"); rlm@496: rlm@496: if (gz == NULL) rlm@496: { rlm@496: // should not happen, but who knows? rlm@496: systemMessage(MSG_ERROR_OPENING_IMAGE, N_("Error opening image %s"), file); rlm@496: return NULL; rlm@496: } rlm@496: rlm@496: u8 *image = data; rlm@496: rlm@496: if (image == NULL) rlm@496: { rlm@496: image = (u8 *)malloc(utilGetSize(size)); rlm@496: if (image == NULL) rlm@1: { rlm@496: systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), rlm@496: "data"); rlm@496: fclose(f); rlm@496: return NULL; rlm@1: } rlm@496: size = fileSize; rlm@496: } rlm@496: int read = fileSize <= size ? fileSize : size; rlm@496: int r = gzread(gz, image, read); rlm@496: gzclose(gz); rlm@1: rlm@496: if (r != (int)read) rlm@496: { rlm@496: systemMessage(MSG_ERROR_READING_IMAGE, rlm@496: N_("Error reading image %s"), file); rlm@496: if (data == NULL) rlm@496: free(image); rlm@496: return NULL; rlm@496: } rlm@1: rlm@496: size = fileSize; rlm@1: rlm@496: return image; rlm@1: } rlm@1: rlm@1: #if 0 rlm@1: static u8 *utilLoadRarFile(const char *file, rlm@1: bool (*accept)(const char *), rlm@1: u8 *data, rlm@1: int &size) rlm@1: { rlm@496: char buffer[2048]; rlm@1: rlm@496: ArchiveList_struct *rarList = NULL; rlm@496: if (urarlib_list((void *)file, (ArchiveList_struct *)&rarList)) rlm@496: { rlm@496: ArchiveList_struct *p = rarList; rlm@496: rlm@496: bool found = false; rlm@496: while (p) rlm@1: { rlm@496: if (accept(p->item.Name)) rlm@496: { rlm@496: strcpy(buffer, p->item.Name); rlm@496: found = true; rlm@496: break; rlm@496: } rlm@496: p = p->next; rlm@1: } rlm@496: if (found) rlm@496: { rlm@496: void *memory = NULL; rlm@496: unsigned long lsize = 0; rlm@496: size = p->item.UnpSize; rlm@496: int r = urarlib_get((void *)&memory, &lsize, buffer, (void *)file, ""); rlm@496: if (!r) rlm@496: { rlm@496: systemMessage(MSG_ERROR_READING_IMAGE, rlm@496: N_("Error reading image %s"), buffer); rlm@496: urarlib_freelist(rarList); rlm@496: return NULL; rlm@496: } rlm@496: u8 *image = (u8 *)memory; rlm@496: if (data != NULL) rlm@496: { rlm@496: memcpy(image, data, size); rlm@496: } rlm@496: urarlib_freelist(rarList); rlm@496: return image; rlm@496: } rlm@496: systemMessage(MSG_NO_IMAGE_ON_ZIP, rlm@496: N_("No image found on RAR file %s"), file); rlm@496: urarlib_freelist(rarList); rlm@496: return NULL; rlm@496: } rlm@496: // nothing found rlm@496: return NULL; rlm@1: } rlm@1: rlm@1: #endif rlm@1: rlm@1: // the caller is responsible for caling free(return value) to release the memory rlm@1: u8 *utilLoad(const char *file, rlm@1: bool (*accept)(const char *), rlm@1: u8 *data, rlm@1: int &size) rlm@1: { rlm@496: if (utilIsZipFile(file)) rlm@496: { rlm@496: return utilLoadFromZip(file, accept, data, size); rlm@496: } rlm@496: if (utilIsGzipFile(file)) rlm@496: { rlm@496: return utilLoadGzipFile(file, accept, data, size); rlm@496: } rlm@1: #if 0 rlm@496: if (utilIsRarFile(file)) rlm@496: { rlm@496: return utilLoadRarFile(file, accept, data, size); rlm@496: } rlm@1: #endif rlm@1: rlm@496: u8 *image = data; rlm@1: rlm@496: FILE *f = fopen(file, "rb"); rlm@1: rlm@496: if (!f) rlm@496: { rlm@496: systemMessage(MSG_ERROR_OPENING_IMAGE, N_("Error opening image %s"), file); rlm@496: return NULL; rlm@496: } rlm@496: rlm@496: fseek(f, 0, SEEK_END); rlm@496: int fileSize = ftell(f); rlm@496: fseek(f, 0, SEEK_SET); rlm@496: if (size == 0) rlm@496: size = fileSize; rlm@496: rlm@496: if (image == NULL) rlm@496: { rlm@496: image = (u8 *)malloc(utilGetSize(size)); rlm@496: if (image == NULL) rlm@1: { rlm@496: systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), rlm@496: "data"); rlm@496: fclose(f); rlm@496: return NULL; rlm@1: } rlm@496: size = fileSize; rlm@496: } rlm@496: int read = fileSize <= size ? fileSize : size; rlm@496: int r = fread(image, 1, read, f); rlm@496: fclose(f); rlm@1: rlm@496: if (r != (int)read) rlm@496: { rlm@496: systemMessage(MSG_ERROR_READING_IMAGE, rlm@496: N_("Error reading image %s"), file); rlm@496: if (data == NULL) rlm@496: free(image); rlm@496: return NULL; rlm@496: } rlm@1: rlm@496: size = fileSize; rlm@1: rlm@496: return image; rlm@1: } rlm@1: rlm@1: void utilWriteInt(gzFile gzFile, int32 i) rlm@1: { rlm@496: utilGzWrite(gzFile, &i, sizeof(int32)); rlm@1: } rlm@1: rlm@1: int32 utilReadInt(gzFile gzFile) rlm@1: { rlm@496: int32 i = 0; rlm@496: utilGzRead(gzFile, &i, sizeof(int32)); rlm@496: return i; rlm@1: } rlm@1: rlm@1: void utilReadData(gzFile gzFile, variable_desc *data) rlm@1: { rlm@496: while (data->address) rlm@496: { rlm@496: utilGzRead(gzFile, data->address, data->size); rlm@496: data++; rlm@496: } rlm@1: } rlm@1: rlm@1: void utilWriteData(gzFile gzFile, variable_desc *data) rlm@1: { rlm@496: while (data->address) rlm@496: { rlm@496: utilGzWrite(gzFile, data->address, data->size); rlm@496: data++; rlm@496: } rlm@1: } rlm@1: rlm@1: gzFile utilGzOpen(const char *file, const char *mode) rlm@1: { rlm@496: utilGzWriteFunc = gzWrite; rlm@496: utilGzReadFunc = gzread; rlm@496: utilGzCloseFunc = gzclose; rlm@496: utilGzSeekFunc = gzseek; rlm@496: utilGzTellFunc = gztell; rlm@1: rlm@496: return gzopen(file, mode); rlm@1: } rlm@1: rlm@1: gzFile utilGzReopen(int id, const char *mode) rlm@1: { rlm@496: utilGzWriteFunc = gzWrite; rlm@496: utilGzReadFunc = gzread; rlm@496: utilGzCloseFunc = gzclose; rlm@496: utilGzSeekFunc = gzseek; rlm@496: utilGzTellFunc = gztell; rlm@1: rlm@496: return gzdopen(id, mode); rlm@1: } rlm@1: rlm@1: gzFile utilMemGzOpen(char *memory, int available, char *mode) rlm@1: { rlm@496: utilGzWriteFunc = memgzwrite; rlm@496: utilGzReadFunc = memgzread; rlm@496: utilGzCloseFunc = memgzclose; rlm@496: utilGzSeekFunc = NULL; // FIXME: not implemented... rlm@496: utilGzTellFunc = memtell; rlm@1: rlm@496: return memgzopen(memory, available, mode); rlm@1: } rlm@1: rlm@1: int utilGzWrite(gzFile file, voidp buffer, unsigned int len) rlm@1: { rlm@496: return utilGzWriteFunc(file, buffer, len); rlm@1: } rlm@1: rlm@1: int utilGzRead(gzFile file, voidp buffer, unsigned int len) rlm@1: { rlm@496: return utilGzReadFunc(file, buffer, len); rlm@1: } rlm@1: rlm@1: int utilGzClose(gzFile file) rlm@1: { rlm@496: return utilGzCloseFunc(file); rlm@1: } rlm@1: rlm@1: z_off_t utilGzSeek(gzFile file, z_off_t offset, int whence) rlm@1: { rlm@496: return utilGzSeekFunc(file, offset, whence); rlm@1: } rlm@1: rlm@1: z_off_t utilGzTell(gzFile file) rlm@1: { rlm@496: return utilGzTellFunc(file); rlm@1: } rlm@1: rlm@1: void utilGBAFindSave(const u8 *data, const int size) rlm@1: { rlm@496: u32 *p = (u32 *)data; rlm@496: u32 *end = (u32 *)(data + size); rlm@496: int saveType = 0; rlm@496: int flashSize = 0x10000; rlm@496: bool rtcFound = false; rlm@1: rlm@496: while (p < end) rlm@496: { rlm@496: u32 d = READ32LE(p); rlm@496: rlm@496: if (d == 0x52504545) rlm@1: { rlm@496: if (memcmp(p, "EEPROM_", 7) == 0) rlm@496: { rlm@496: if (saveType == 0) rlm@496: saveType = 1; rlm@496: } rlm@496: } rlm@496: else if (d == 0x4D415253) rlm@496: { rlm@496: if (memcmp(p, "SRAM_", 5) == 0) rlm@496: { rlm@496: if (saveType == 0) rlm@496: saveType = 2; rlm@496: } rlm@496: } rlm@496: else if (d == 0x53414C46) rlm@496: { rlm@496: if (memcmp(p, "FLASH1M_", 8) == 0) rlm@496: { rlm@496: if (saveType == 0) rlm@1: { rlm@496: saveType = 3; rlm@496: flashSize = 0x20000; rlm@1: } rlm@496: } rlm@496: else if (memcmp(p, "FLASH", 5) == 0) rlm@496: { rlm@496: if (saveType == 0) rlm@1: { rlm@496: saveType = 3; rlm@496: flashSize = 0x10000; rlm@1: } rlm@496: } rlm@1: } rlm@496: else if (d == 0x52494953) rlm@1: { rlm@496: if (memcmp(p, "SIIRTC_V", 8) == 0) rlm@496: rtcFound = true; rlm@1: } rlm@496: p++; rlm@496: } rlm@496: // if no matches found, then set it to NONE rlm@496: if (saveType == 0) rlm@496: { rlm@496: saveType = 5; rlm@496: } rlm@496: rtcEnable(rtcFound); rlm@496: cpuSaveType = saveType; rlm@496: flashSetSize(flashSize); rlm@1: } rlm@1: rlm@1: void utilUpdateSystemColorMaps() rlm@1: { rlm@496: switch (systemColorDepth) rlm@496: { rlm@496: case 16: rlm@496: { rlm@496: for (int i = 0; i < 0x10000; i++) rlm@496: { rlm@496: systemColorMap16[i] = ((i & 0x1f) << systemRedShift) | rlm@496: (((i & 0x3e0) >> 5) << systemGreenShift) | rlm@496: (((i & 0x7c00) >> 10) << systemBlueShift); rlm@496: } rlm@496: break; rlm@496: } rlm@496: case 24: rlm@496: case 32: rlm@496: { rlm@496: for (int i = 0; i < 0x10000; i++) rlm@496: { rlm@496: systemColorMap32[i] = ((i & 0x1f) << systemRedShift) | rlm@496: (((i & 0x3e0) >> 5) << systemGreenShift) | rlm@496: (((i & 0x7c00) >> 10) << systemBlueShift); rlm@496: } rlm@496: break; rlm@496: } rlm@496: } rlm@1: } rlm@1: rlm@1: //// BIOS stuff rlm@1: // systemType uses the same enum values as gbEmulatorType does rlm@1: rlm@1: bool utilLoadBIOS(u8 *bios, const char *biosFileName, int systemType) rlm@1: { rlm@496: if (bios == NULL || strlen(biosFileName) == 0) rlm@496: return false; rlm@1: rlm@496: if (systemType == 4) rlm@496: { rlm@496: int biosSize = 0x4000; rlm@496: if (utilLoad(biosFileName, utilIsGBABios, bios, biosSize)) rlm@1: { rlm@496: if (biosSize == 0x4000) rlm@496: return true; rlm@1: } rlm@496: } rlm@496: else rlm@496: { rlm@496: int biosSize = 0x100; rlm@496: if (utilLoad(biosFileName, utilIsGBBios, bios, biosSize)) rlm@1: { rlm@496: if (biosSize == 0x100) rlm@496: return true; rlm@1: } rlm@496: } rlm@1: rlm@496: return false; rlm@1: } rlm@1: rlm@1: bool utilCheckBIOS(const char *biosFileName, int systemType) rlm@1: { rlm@496: if (strlen(biosFileName) == 0) rlm@496: return false; rlm@1: rlm@496: u8 * tempBIOS = (u8 *)malloc(systemType == 4 ? 0x4000 : 0x100); rlm@496: bool result = utilLoadBIOS(tempBIOS, biosFileName, systemType); rlm@496: free(tempBIOS); rlm@1: rlm@496: return result; rlm@1: } rlm@1: rlm@1: #if 0 rlm@1: // returns the checksum of the BIOS that will be loaded after the next restart rlm@1: u16 utilCalcBIOSChecksum(const u8 *bios, int systemType) rlm@1: { rlm@496: u32 biosChecksum = 0; rlm@496: if (bios) rlm@496: { rlm@496: int biosSize = (systemType == 4 ? 0x4000 : 0x100); rlm@496: const u16 *data = reinterpret_cast(bios); rlm@496: for (int i = biosSize; i > 0; i -= 2) rlm@496: biosChecksum += *data++; rlm@496: } rlm@1: rlm@496: while ((biosChecksum >> 16) & 0xFFFF) rlm@496: biosChecksum = (biosChecksum &0xFFFF) + ((biosChecksum >> 16) & 0xFFFF); rlm@1: rlm@496: return biosChecksum & 0xFFFF; rlm@1: } rlm@1: #else rlm@1: // returns the checksum of the BIOS that will be loaded after the next restart rlm@1: u16 utilCalcBIOSChecksum(const u8 *bios, int systemType) rlm@1: { rlm@496: u32 biosChecksum = 0; rlm@496: if (bios) rlm@496: { rlm@496: int biosSize = (systemType == 4 ? 0x4000 : 0x100); rlm@496: const u32 *data = reinterpret_cast(bios); rlm@496: for (int i = biosSize; i > 0; i -= 4) rlm@496: biosChecksum += *data++; rlm@496: } rlm@1: rlm@496: return biosChecksum & 0xFFFF; rlm@1: } rlm@1: #endif rlm@1: rlm@1: // returns the checksum of the BIOS file rlm@1: u16 utilCalcBIOSFileChecksum(const char *biosFileName, int systemType) rlm@1: { rlm@496: if (strlen(biosFileName) == 0) rlm@496: return 0; rlm@1: rlm@496: u16 biosChecksum = 0; rlm@496: const int biosSize = (systemType == 4 ? 0x4000 : 0x100); rlm@496: u8 * tempBIOS = (u8 *)malloc(biosSize); rlm@496: bool hasBIOS = utilLoadBIOS(tempBIOS, biosFileName, systemType); rlm@496: if (hasBIOS) rlm@496: { rlm@496: biosChecksum = utilCalcBIOSChecksum(tempBIOS, systemType); rlm@496: } rlm@496: free(tempBIOS); rlm@1: rlm@496: return biosChecksum; rlm@1: } rlm@1: