diff --git a/source/fileop.cpp b/source/fileop.cpp index d80c7bf..2e8610a 100644 --- a/source/fileop.cpp +++ b/source/fileop.cpp @@ -1,964 +1,931 @@ -/**************************************************************************** - * Visual Boy Advance GX - * - * Tantric 2008-2009 - * - * fileop.cpp - * - * File operations - ***************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "vbagx.h" -#include "vbasupport.h" -#include "fileop.h" -#include "networkop.h" -#include "gcunzip.h" -#include "menu.h" -#include "filebrowser.h" -#include "gui/gui.h" - -#define THREAD_SLEEP 100 - -unsigned char *savebuffer; -static mutex_t bufferLock = LWP_MUTEX_NULL; -FILE * file; // file pointer - the only one we should ever use! -bool unmountRequired[7] = { false, false, false, false, false, false, false }; -bool isMounted[7] = { false, false, false, false, false, false, false }; - -#ifdef HW_RVL - const DISC_INTERFACE* sd = &__io_wiisd; - const DISC_INTERFACE* usb = &__io_usbstorage; - const DISC_INTERFACE* dvd = &__io_wiidvd; -#else - const DISC_INTERFACE* carda = &__io_gcsda; - const DISC_INTERFACE* cardb = &__io_gcsdb; - const DISC_INTERFACE* dvd = &__io_gcdvd; -#endif - -// folder parsing thread -static lwp_t parsethread = LWP_THREAD_NULL; -static DIR *dir = NULL; -static bool parseHalt = true; -static bool parseFilter = true; -static bool ParseDirEntries(); -int selectLoadedFile = 0; - -// device thread -static lwp_t devicethread = LWP_THREAD_NULL; -static bool deviceHalt = true; - -/**************************************************************************** - * ResumeDeviceThread - * - * Signals the device thread to start, and resumes the thread. - ***************************************************************************/ -void -ResumeDeviceThread() -{ - deviceHalt = false; - LWP_ResumeThread(devicethread); -} - -/**************************************************************************** - * HaltGui - * - * Signals the device thread to stop. - ***************************************************************************/ -void -HaltDeviceThread() -{ -#ifdef HW_RVL - deviceHalt = true; - - // wait for thread to finish - while(!LWP_ThreadIsSuspended(devicethread)) - usleep(THREAD_SLEEP); -#endif -} - -/**************************************************************************** - * HaltParseThread - * - * Signals the parse thread to stop. - ***************************************************************************/ -void -HaltParseThread() -{ - parseHalt = true; - - while(!LWP_ThreadIsSuspended(parsethread)) - usleep(THREAD_SLEEP); -} - - -/**************************************************************************** - * devicecallback - * - * This checks our devices for changes (SD/USB/DVD removed) - ***************************************************************************/ -#ifdef HW_RVL -static int devsleep; - -static void * -devicecallback (void *arg) -{ - while (1) - { - if(isMounted[DEVICE_SD]) - { - if(!sd->isInserted()) // check if the device was removed - { - unmountRequired[DEVICE_SD] = true; - isMounted[DEVICE_SD] = false; - } - } - - if(isMounted[DEVICE_USB]) - { - if(!usb->isInserted()) // check if the device was removed - { - unmountRequired[DEVICE_USB] = true; - isMounted[DEVICE_USB] = false; - } - } - - if(isMounted[DEVICE_DVD]) - { - if(!dvd->isInserted()) // check if the device was removed - { - unmountRequired[DEVICE_DVD] = true; - isMounted[DEVICE_DVD] = false; - } - } - - devsleep = 1000*1000; // 1 sec - - while(devsleep > 0) - { - if(deviceHalt) - LWP_SuspendThread(devicethread); - usleep(THREAD_SLEEP); - devsleep -= THREAD_SLEEP; - } - } - return NULL; -} -#endif - -static void * -parsecallback (void *arg) -{ - while(1) - { - while(ParseDirEntries()) - usleep(THREAD_SLEEP); - LWP_SuspendThread(parsethread); - } - return NULL; -} - -/**************************************************************************** - * InitDeviceThread - * - * libOGC provides a nice wrapper for LWP access. - * This function sets up a new local queue and attaches the thread to it. - ***************************************************************************/ -void -InitDeviceThread() -{ -#ifdef HW_RVL - LWP_CreateThread (&devicethread, devicecallback, NULL, NULL, 0, 40); -#endif - LWP_CreateThread (&parsethread, parsecallback, NULL, NULL, 0, 80); -} - -/**************************************************************************** - * UnmountAllFAT - * Unmounts all FAT devices - ***************************************************************************/ -void UnmountAllFAT() -{ -#ifdef HW_RVL - fatUnmount("sd:"); - fatUnmount("usb:"); -#else - fatUnmount("carda:"); - fatUnmount("cardb:"); -#endif -} - -/**************************************************************************** - * MountFAT - * Checks if the device needs to be (re)mounted - * If so, unmounts the device - * Attempts to mount the device specified - * Sets libfat to use the device by default - ***************************************************************************/ - -static bool MountFAT(int device, int silent) -{ - bool mounted = false; - int retry = 1; - char name[10], name2[10]; - const DISC_INTERFACE* disc = NULL; - - switch(device) - { -#ifdef HW_RVL - case DEVICE_SD: - sprintf(name, "sd"); - sprintf(name2, "sd:"); - disc = sd; - break; - case DEVICE_USB: - sprintf(name, "usb"); - sprintf(name2, "usb:"); - disc = usb; - break; -#else - case DEVICE_SD_SLOTA: - sprintf(name, "carda"); - sprintf(name2, "carda:"); - disc = carda; - break; - - case DEVICE_SD_SLOTB: - sprintf(name, "cardb"); - sprintf(name2, "cardb:"); - disc = cardb; - break; -#endif - default: - return false; // unknown device - } - - if(unmountRequired[device]) - { - unmountRequired[device] = false; - fatUnmount(name2); - disc->shutdown(); - isMounted[device] = false; - } - - while(retry) - { - if(disc->startup() && fatMountSimple(name, disc)) - mounted = true; - - if(mounted || silent) - break; - -#ifdef HW_RVL - if(device == DEVICE_SD) - retry = ErrorPromptRetry("SD card not found!"); - else - retry = ErrorPromptRetry("USB drive not found!"); -#else - retry = ErrorPromptRetry("SD card not found!"); -#endif - } - - isMounted[device] = mounted; - return mounted; -} - -void MountAllFAT() -{ -#ifdef HW_RVL - MountFAT(DEVICE_SD, SILENT); - MountFAT(DEVICE_USB, SILENT); -#else - MountFAT(DEVICE_SD_SLOTA, SILENT); - MountFAT(DEVICE_SD_SLOTB, SILENT); -#endif -} - -/**************************************************************************** - * MountDVD() - * - * Tests if a ISO9660 DVD is inserted and available, and mounts it - ***************************************************************************/ -bool MountDVD(bool silent) -{ - bool mounted = false; - int retry = 1; - - if(unmountRequired[DEVICE_DVD]) - { - unmountRequired[DEVICE_DVD] = false; - ISO9660_Unmount("dvd:"); - } - - while(retry) - { - ShowAction("Loading DVD..."); - - if(!dvd->isInserted()) - { - if(silent) - break; - - retry = ErrorPromptRetry("No disc inserted!"); - } - else if(!ISO9660_Mount("dvd", dvd)) - { - if(silent) - break; - - retry = ErrorPromptRetry("Unrecognized DVD format."); - } - else - { - mounted = true; - break; - } - } - CancelAction(); - isMounted[DEVICE_DVD] = mounted; - return mounted; -} - -bool FindDevice(char * filepath, int * device) -{ - if(!filepath || filepath[0] == 0) - return false; - - if(strncmp(filepath, "sd:", 3) == 0) - { - *device = DEVICE_SD; - return true; - } - else if(strncmp(filepath, "usb:", 4) == 0) - { - *device = DEVICE_USB; - return true; - } - else if(strncmp(filepath, "smb:", 4) == 0) - { - *device = DEVICE_SMB; - return true; - } - else if(strncmp(filepath, "carda:", 6) == 0) - { - *device = DEVICE_SD_SLOTA; - return true; - } - else if(strncmp(filepath, "cardb:", 6) == 0) - { - *device = DEVICE_SD_SLOTB; - return true; - } - else if(strncmp(filepath, "dvd:", 4) == 0) - { - *device = DEVICE_DVD; - return true; - } - return false; -} - -char * StripDevice(char * path) -{ - if(path == NULL) - return NULL; - - char * newpath = strchr(path,'/'); - - if(newpath != NULL) - newpath++; - - return newpath; -} - -/**************************************************************************** - * ChangeInterface - * Attempts to mount/configure the device specified - ***************************************************************************/ -bool ChangeInterface(int device, bool silent) -{ - if(isMounted[device]) - return true; - - bool mounted = false; - - switch(device) - { -#ifdef HW_RVL - case DEVICE_SD: - case DEVICE_USB: -#else - case DEVICE_SD_SLOTA: - case DEVICE_SD_SLOTB: -#endif - mounted = MountFAT(device, silent); - break; - case DEVICE_DVD: - mounted = MountDVD(silent); - break; - case DEVICE_SMB: - mounted = ConnectShare(silent); - break; - } - - return mounted; -} - -bool ChangeInterface(char * filepath, bool silent) -{ - int device = -1; - - if(!FindDevice(filepath, &device)) - return false; - - return ChangeInterface(device, silent); -} - -void CreateAppPath(char * origpath) -{ - if(!origpath || origpath[0] == 0) - return; - - char * path = strdup(origpath); // make a copy so we don't mess up original - - if(!path) - return; - - char * loc = strrchr(path,'/'); - if (loc != NULL) - *loc = 0; // strip file name - - int pos = 0; - - // replace fat:/ with sd:/ - if(strncmp(path, "fat:/", 5) == 0) - { - pos++; - path[1] = 's'; - path[2] = 'd'; - } - if(ChangeInterface(&path[pos], SILENT)) - snprintf(appPath, MAXPATHLEN-1, "%s", &path[pos]); - - free(path); -} - -static char *GetExt(char *file) -{ - if(!file) - return NULL; - - char *ext = strrchr(file,'.'); - if(ext != NULL) - { - ext++; - int extlen = strlen(ext); - if(extlen > 5) - return NULL; - } - return ext; -} - -bool GetFileSize(int i) -{ - if(browserList[i].length > 0) - return true; - - struct stat filestat; - char path[MAXPATHLEN+1]; - snprintf(path, MAXPATHLEN, "%s%s", browser.dir, browserList[i].filename); - - if(stat(path, &filestat) < 0) - return false; - - browserList[i].length = filestat.st_size; - return true; -} - -void FindAndSelectLastLoadedFile () -{ - int indexFound = -1; - - for(int j=1; j < browser.numEntries; j++) - { - if(strcmp(browserList[j].filename, GCSettings.LastFileLoaded) == 0) - { - indexFound = j; - break; - } - } - - // move to this file - if(indexFound > 0) - { - if(indexFound >= FILE_PAGESIZE) - { - int newIndex = (floor(indexFound/(float)FILE_PAGESIZE)) * FILE_PAGESIZE; - - if(newIndex + FILE_PAGESIZE > browser.numEntries) - newIndex = browser.numEntries - FILE_PAGESIZE; - - if(newIndex < 0) - newIndex = 0; - - browser.pageIndex = newIndex; - } - browser.selIndex = indexFound; - } - - selectLoadedFile = 2; // selecting done -} - -static bool ParseDirEntries() -{ - if(!dir) - return false; - - char *ext; - struct dirent *entry = NULL; - int isdir; - - int i = 0; - - while(i < 20 && !parseHalt) - { - entry = readdir(dir); - - if(entry == NULL) - break; - - if(entry->d_name[0] == '.' && entry->d_name[1] != '.') - continue; - - if(strcmp(entry->d_name, "..") == 0) - { - isdir = 1; - } - else - { - if(entry->d_type==DT_DIR) - isdir = 1; - else - isdir = 0; - - // don't show the file if it's not a valid ROM - if(parseFilter && !isdir) - { - ext = GetExt(entry->d_name); - - if(ext == NULL) - continue; - - if( strcasecmp(ext, "agb") != 0 && strcasecmp(ext, "gba") != 0 && - strcasecmp(ext, "bin") != 0 && strcasecmp(ext, "elf") != 0 && - strcasecmp(ext, "mb") != 0 && strcasecmp(ext, "dmg") != 0 && - strcasecmp(ext, "gb") != 0 && strcasecmp(ext, "gbc") != 0 && - strcasecmp(ext, "cgb") != 0 && strcasecmp(ext, "sgb") != 0 && - strcasecmp(ext, "zip") != 0 && strcasecmp(ext, "7z") != 0) - continue; - } - } - - if(!AddBrowserEntry()) - { - parseHalt = true; - break; - } - - snprintf(browserList[browser.numEntries+i].filename, MAXJOLIET, "%s", entry->d_name); - browserList[browser.numEntries+i].isdir = isdir; // flag this as a dir - - if(isdir) - { - if(strcmp(entry->d_name, "..") == 0) - sprintf(browserList[browser.numEntries+i].displayname, "Up One Level"); - else - snprintf(browserList[browser.numEntries+i].displayname, MAXJOLIET, "%s", browserList[browser.numEntries+i].filename); - browserList[browser.numEntries+i].icon = ICON_FOLDER; - } - else - { - StripExt(browserList[browser.numEntries+i].displayname, browserList[browser.numEntries+i].filename); // hide file extension - } - i++; - } - - if(!parseHalt) - { - // Sort the file list - if(i >= 0) - qsort(browserList, browser.numEntries+i, sizeof(BROWSERENTRY), FileSortCallback); - - browser.numEntries += i; - } - - if(entry == NULL || parseHalt) - { - closedir(dir); // close directory - dir = NULL; - - return false; // no more entries - } - return true; // more entries -} - -/*************************************************************************** - * Browse subdirectories - **************************************************************************/ -int -ParseDirectory(bool waitParse, bool filter) -{ - int retry = 1; - bool mounted = false; - parseFilter = filter; - - ResetBrowser(); // reset browser - - // add trailing slash - if(browser.dir[strlen(browser.dir)-1] != '/') - strcat(browser.dir, "/"); - - // open the directory - while(dir == NULL && retry == 1) - { - mounted = ChangeInterface(browser.dir, NOTSILENT); - - if(mounted) - dir = opendir(browser.dir); - else - return -1; - - if(dir == NULL) - retry = ErrorPromptRetry("Error opening directory!"); - } - - // if we can't open the dir, try higher levels - if (dir == NULL) - { - char * devEnd = strrchr(browser.dir, '/'); - - while(!IsDeviceRoot(browser.dir)) - { - devEnd[0] = 0; // strip slash - devEnd = strrchr(browser.dir, '/'); - - if(devEnd == NULL) - break; - - devEnd[1] = 0; // strip remaining file listing - dir = opendir(browser.dir); - if (dir) - break; - } - } - - if(dir == NULL) - return -1; - - if(IsDeviceRoot(browser.dir)) - { - AddBrowserEntry(); - sprintf(browserList[0].filename, ".."); - sprintf(browserList[0].displayname, "Up One Level"); - browserList[0].length = 0; - browserList[0].isdir = 1; // flag this as a dir - browserList[0].icon = ICON_FOLDER; - browser.numEntries++; - } - - parseHalt = false; - ParseDirEntries(); // index first 20 entries - - LWP_ResumeThread(parsethread); // index remaining entries - - if(waitParse) // wait for complete parsing - { - ShowAction("Loading..."); - - while(!LWP_ThreadIsSuspended(parsethread)) - usleep(THREAD_SLEEP); - - CancelAction(); - } - - return browser.numEntries; -} - -bool CreateDirectory(char * path) -{ - DIR *dir = opendir(path); - if (!dir) { - if(mkdir(path, 0777) != 0) { - return false; - } - } - else { - closedir(dir); - } - return true; -} - -/**************************************************************************** - * AllocSaveBuffer () - * Clear and allocate the savebuffer - ***************************************************************************/ -void -AllocSaveBuffer () -{ - if(bufferLock == LWP_MUTEX_NULL) - LWP_MutexInit(&bufferLock, false); - - if(bufferLock != LWP_MUTEX_NULL) - LWP_MutexLock(bufferLock); - memset (savebuffer, 0, SAVEBUFFERSIZE); -} - -/**************************************************************************** - * FreeSaveBuffer () - * Free the savebuffer memory - ***************************************************************************/ -void -FreeSaveBuffer () -{ - if(bufferLock != LWP_MUTEX_NULL) - LWP_MutexUnlock(bufferLock); -} - -/**************************************************************************** - * LoadSzFile - * Loads the selected file # from the specified 7z into rbuffer - * Returns file size - ***************************************************************************/ -size_t -LoadSzFile(char * filepath, unsigned char * rbuffer) -{ - size_t size = 0; - - // stop checking if devices were removed/inserted - // since we're loading a file - HaltDeviceThread(); - - // halt parsing - HaltParseThread(); - - file = fopen (filepath, "rb"); - if (file > 0) - { - size = SzExtractFile(browserList[browser.selIndex].filenum, rbuffer); - fclose (file); - } - else - { - ErrorPrompt("Error opening file!"); - } - - // go back to checking if devices were inserted/removed - ResumeDeviceThread(); - - return size; -} - -/**************************************************************************** - * LoadFile - ***************************************************************************/ -size_t -LoadFile (char * rbuffer, char *filepath, size_t length, bool silent) -{ - char zipbuffer[2048]; - size_t size = 0, offset = 0, readsize = 0; - int retry = 1; - int device; - - if(!FindDevice(filepath, &device)) - return 0; - - // stop checking if devices were removed/inserted - // since we're loading a file - HaltDeviceThread(); - - // halt parsing - HaltParseThread(); - - // open the file - while(retry) - { - if(!ChangeInterface(device, silent)) - break; - - file = fopen (filepath, "rb"); - - if(!file) - { - if(silent) - break; - - retry = ErrorPromptRetry("Error opening file!"); - continue; - } - - if(length > 0 && length <= 2048) // do a partial read (eg: to check file header) - { - size = fread (rbuffer, 1, length, file); - } - else // load whole file - { - readsize = fread (zipbuffer, 1, 32, file); - - if(!readsize) - { - unmountRequired[device] = true; - retry = ErrorPromptRetry("Error reading file!"); - fclose (file); - continue; - } - - if (IsZipFile (zipbuffer)) - { - size = UnZipBuffer ((unsigned char *)rbuffer); // unzip - } - else - { - fseeko(file,0,SEEK_END); - size = ftello(file); - fseeko(file,0,SEEK_SET); - - while(!feof(file)) - { - // If the size requested is *less* than the filesize, only read that much - we don't want to overrun the buffer - int toread = 4096; - if (length > 0 && offset+toread > length) { - toread = length - offset; - } - - ShowProgress ("Loading...", offset, size); - readsize = fread (rbuffer + offset, 1, 4096, file); // read in next chunk - - if(readsize <= 0) - break; // reading finished (or failed) - - offset += readsize; - if (length > 0 && offset >= length) { - break; - } - } - size = offset; - CancelAction(); - } - } - retry = 0; - fclose (file); - } - - // go back to checking if devices were inserted/removed - ResumeDeviceThread(); - CancelAction(); - return size; -} - -size_t LoadFile(char * filepath, bool silent) -{ - struct stat filestat; - - if(stat(filepath, &filestat) != 0) { - return 0; - } - - int size = filestat.st_size; - - if(size >= SAVEBUFFERSIZE) { - return 0; - } - - return LoadFile((char *)savebuffer, filepath, 0, silent); -} - -/**************************************************************************** - * SaveFile - * Write buffer to file - ***************************************************************************/ -size_t -SaveFile (char * buffer, char *filepath, size_t datasize, bool silent) -{ - size_t written = 0; - size_t writesize, nextwrite; - int retry = 1; - int device; - - if(!FindDevice(filepath, &device)) - return 0; - - if(datasize == 0) - return 0; - - // stop checking if devices were removed/inserted - // since we're saving a file - HaltDeviceThread(); - - // halt parsing - HaltParseThread(); - - if(!silent) - ShowAction("Saving..."); - - while(!written && retry == 1) - { - if(!ChangeInterface(device, silent)) - break; - - file = fopen (filepath, "wb"); - - if(!file) - { - if(silent) - break; - - retry = ErrorPromptRetry("Error creating file!"); - continue; - } - - while(written < datasize) - { - if(datasize - written > 4096) nextwrite=4096; - else nextwrite = datasize-written; - writesize = fwrite (buffer+written, 1, nextwrite, file); - if(writesize != nextwrite) break; // write failure - written += writesize; - } - fclose (file); - - if(written != datasize) written = 0; - - if(!written) - { - unmountRequired[device] = true; - if(silent) break; - retry = ErrorPromptRetry("Error saving file!"); - } - } - - // go back to checking if devices were inserted/removed - ResumeDeviceThread(); - - if(!silent) - CancelAction(); - return written; -} - -size_t SaveFile(char * filepath, size_t datasize, bool silent) -{ - return SaveFile((char *)savebuffer, filepath, datasize, silent); -} +/**************************************************************************** + * Visual Boy Advance GX + * + * Tantric 2008-2009 + * + * fileop.cpp + * + * File operations + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vbagx.h" +#include "vbasupport.h" +#include "fileop.h" +#include "networkop.h" +#include "gcunzip.h" +#include "menu.h" +#include "filebrowser.h" +#include "gui/gui.h" + +#define THREAD_SLEEP 100 + +unsigned char *savebuffer = NULL; +static mutex_t bufferLock = LWP_MUTEX_NULL; +FILE * file; // file pointer - the only one we should ever use! +bool unmountRequired[7] = { false, false, false, false, false, false, false }; +bool isMounted[7] = { false, false, false, false, false, false, false }; + +#ifdef HW_RVL + const DISC_INTERFACE* sd = &__io_wiisd; + const DISC_INTERFACE* usb = &__io_usbstorage; + const DISC_INTERFACE* dvd = &__io_wiidvd; +#else + const DISC_INTERFACE* carda = &__io_gcsda; + const DISC_INTERFACE* cardb = &__io_gcsdb; + const DISC_INTERFACE* dvd = &__io_gcdvd; +#endif + +// folder parsing thread +static lwp_t parsethread = LWP_THREAD_NULL; +static DIR *dir = NULL; +static bool parseHalt = true; +static bool parseFilter = true; +static bool ParseDirEntries(); +int selectLoadedFile = 0; + +// device thread +static lwp_t devicethread = LWP_THREAD_NULL; +static bool deviceHalt = true; + +/**************************************************************************** + * ResumeDeviceThread + * + * Signals the device thread to start, and resumes the thread. + ***************************************************************************/ +void +ResumeDeviceThread() +{ + deviceHalt = false; + LWP_ResumeThread(devicethread); +} + +/**************************************************************************** + * HaltGui + * + * Signals the device thread to stop. + ***************************************************************************/ +void +HaltDeviceThread() +{ +#ifdef HW_RVL + deviceHalt = true; + + // wait for thread to finish + while(!LWP_ThreadIsSuspended(devicethread)) + usleep(THREAD_SLEEP); +#endif +} + +/**************************************************************************** + * HaltParseThread + * + * Signals the parse thread to stop. + ***************************************************************************/ +void +HaltParseThread() +{ + parseHalt = true; + + while(!LWP_ThreadIsSuspended(parsethread)) + usleep(THREAD_SLEEP); +} + + +/**************************************************************************** + * devicecallback + * + * This checks our devices for changes (SD/USB/DVD removed) + ***************************************************************************/ +#ifdef HW_RVL +static int devsleep; + +static void * +devicecallback (void *arg) +{ + while (1) + { + if(isMounted[DEVICE_SD]) + { + if(!sd->isInserted()) // check if the device was removed + { + unmountRequired[DEVICE_SD] = true; + isMounted[DEVICE_SD] = false; + } + } + + if(isMounted[DEVICE_USB]) + { + if(!usb->isInserted()) // check if the device was removed + { + unmountRequired[DEVICE_USB] = true; + isMounted[DEVICE_USB] = false; + } + } + + if(isMounted[DEVICE_DVD]) + { + if(!dvd->isInserted()) // check if the device was removed + { + unmountRequired[DEVICE_DVD] = true; + isMounted[DEVICE_DVD] = false; + } + } + + devsleep = 1000*1000; // 1 sec + + while(devsleep > 0) + { + if(deviceHalt) + LWP_SuspendThread(devicethread); + usleep(THREAD_SLEEP); + devsleep -= THREAD_SLEEP; + } + } + return NULL; +} +#endif + +static void * +parsecallback (void *arg) +{ + while(1) + { + while(ParseDirEntries()) + usleep(THREAD_SLEEP); + LWP_SuspendThread(parsethread); + } + return NULL; +} + +/**************************************************************************** + * InitDeviceThread + * + * libOGC provides a nice wrapper for LWP access. + * This function sets up a new local queue and attaches the thread to it. + ***************************************************************************/ +void +InitDeviceThread() +{ +#ifdef HW_RVL + LWP_CreateThread (&devicethread, devicecallback, NULL, NULL, 0, 40); +#endif + LWP_CreateThread (&parsethread, parsecallback, NULL, NULL, 0, 80); +} + +/**************************************************************************** + * UnmountAllFAT + * Unmounts all FAT devices + ***************************************************************************/ +void UnmountAllFAT() +{ +#ifdef HW_RVL + fatUnmount("sd:"); + fatUnmount("usb:"); +#else + fatUnmount("carda:"); + fatUnmount("cardb:"); +#endif +} + +/**************************************************************************** + * MountFAT + * Checks if the device needs to be (re)mounted + * If so, unmounts the device + * Attempts to mount the device specified + * Sets libfat to use the device by default + ***************************************************************************/ + +static bool MountFAT(int device, int silent) +{ + bool mounted = false; + int retry = 1; + char name[10], name2[10]; + const DISC_INTERFACE* disc = NULL; + + switch(device) + { +#ifdef HW_RVL + case DEVICE_SD: + sprintf(name, "sd"); + sprintf(name2, "sd:"); + disc = sd; + break; + case DEVICE_USB: + sprintf(name, "usb"); + sprintf(name2, "usb:"); + disc = usb; + break; +#else + case DEVICE_SD_SLOTA: + sprintf(name, "carda"); + sprintf(name2, "carda:"); + disc = carda; + break; + + case DEVICE_SD_SLOTB: + sprintf(name, "cardb"); + sprintf(name2, "cardb:"); + disc = cardb; + break; +#endif + default: + return false; // unknown device + } + + if(unmountRequired[device]) + { + unmountRequired[device] = false; + fatUnmount(name2); + disc->shutdown(); + isMounted[device] = false; + } + + while(retry) + { + if(disc->startup() && fatMountSimple(name, disc)) + mounted = true; + + if(mounted || silent) + break; + +#ifdef HW_RVL + if(device == DEVICE_SD) + retry = ErrorPromptRetry("SD card not found!"); + else + retry = ErrorPromptRetry("USB drive not found!"); +#else + retry = ErrorPromptRetry("SD card not found!"); +#endif + } + + isMounted[device] = mounted; + return mounted; +} + +void MountAllFAT() +{ +#ifdef HW_RVL + MountFAT(DEVICE_SD, SILENT); + MountFAT(DEVICE_USB, SILENT); +#else + MountFAT(DEVICE_SD_SLOTA, SILENT); + MountFAT(DEVICE_SD_SLOTB, SILENT); +#endif +} + +/**************************************************************************** + * MountDVD() + * + * Tests if a ISO9660 DVD is inserted and available, and mounts it + ***************************************************************************/ +bool MountDVD(bool silent) +{ + bool mounted = false; + int retry = 1; + + if(unmountRequired[DEVICE_DVD]) + { + unmountRequired[DEVICE_DVD] = false; + ISO9660_Unmount("dvd:"); + } + + while(retry) + { + ShowAction("Loading DVD..."); + + if(!dvd->isInserted()) + { + if(silent) + break; + + retry = ErrorPromptRetry("No disc inserted!"); + } + else if(!ISO9660_Mount("dvd", dvd)) + { + if(silent) + break; + + retry = ErrorPromptRetry("Unrecognized DVD format."); + } + else + { + mounted = true; + break; + } + } + CancelAction(); + isMounted[DEVICE_DVD] = mounted; + return mounted; +} + +bool FindDevice(char * filepath, int * device) +{ + if(!filepath || filepath[0] == 0) + return false; + + if(strncmp(filepath, "sd:", 3) == 0) + { + *device = DEVICE_SD; + return true; + } + else if(strncmp(filepath, "usb:", 4) == 0) + { + *device = DEVICE_USB; + return true; + } + else if(strncmp(filepath, "smb:", 4) == 0) + { + *device = DEVICE_SMB; + return true; + } + else if(strncmp(filepath, "carda:", 6) == 0) + { + *device = DEVICE_SD_SLOTA; + return true; + } + else if(strncmp(filepath, "cardb:", 6) == 0) + { + *device = DEVICE_SD_SLOTB; + return true; + } + else if(strncmp(filepath, "dvd:", 4) == 0) + { + *device = DEVICE_DVD; + return true; + } + return false; +} + +char * StripDevice(char * path) +{ + if(path == NULL) + return NULL; + + char * newpath = strchr(path,'/'); + + if(newpath != NULL) + newpath++; + + return newpath; +} + +/**************************************************************************** + * ChangeInterface + * Attempts to mount/configure the device specified + ***************************************************************************/ +bool ChangeInterface(int device, bool silent) +{ + if(isMounted[device]) + return true; + + bool mounted = false; + + switch(device) + { +#ifdef HW_RVL + case DEVICE_SD: + case DEVICE_USB: +#else + case DEVICE_SD_SLOTA: + case DEVICE_SD_SLOTB: +#endif + mounted = MountFAT(device, silent); + break; + case DEVICE_DVD: + mounted = MountDVD(silent); + break; + case DEVICE_SMB: + mounted = ConnectShare(silent); + break; + } + + return mounted; +} + +bool ChangeInterface(char * filepath, bool silent) +{ + int device = -1; + + if(!FindDevice(filepath, &device)) + return false; + + return ChangeInterface(device, silent); +} + +void CreateAppPath(char * origpath) +{ + if(!origpath || origpath[0] == 0) + return; + + char * path = strdup(origpath); // make a copy so we don't mess up original + + if(!path) + return; + + char * loc = strrchr(path,'/'); + if (loc != NULL) + *loc = 0; // strip file name + + int pos = 0; + + // replace fat:/ with sd:/ + if(strncmp(path, "fat:/", 5) == 0) + { + pos++; + path[1] = 's'; + path[2] = 'd'; + } + if(ChangeInterface(&path[pos], SILENT)) + snprintf(appPath, MAXPATHLEN-1, "%s", &path[pos]); + + free(path); +} + +static char *GetExt(char *file) +{ + if(!file) + return NULL; + + char *ext = strrchr(file,'.'); + if(ext != NULL) + { + ext++; + int extlen = strlen(ext); + if(extlen > 5) + return NULL; + } + return ext; +} + +void FindAndSelectLastLoadedFile () +{ + int indexFound = -1; + + for(int j=1; j < browser.numEntries; j++) + { + if(strcmp(browserList[j].filename, GCSettings.LastFileLoaded) == 0) + { + indexFound = j; + break; + } + } + + // move to this file + if(indexFound > 0) + { + if(indexFound >= FILE_PAGESIZE) + { + int newIndex = (floor(indexFound/(float)FILE_PAGESIZE)) * FILE_PAGESIZE; + + if(newIndex + FILE_PAGESIZE > browser.numEntries) + newIndex = browser.numEntries - FILE_PAGESIZE; + + if(newIndex < 0) + newIndex = 0; + + browser.pageIndex = newIndex; + } + browser.selIndex = indexFound; + } + + selectLoadedFile = 2; // selecting done +} + +static bool ParseDirEntries() +{ + if(!dir) + return false; + + char *ext; + struct dirent *entry = NULL; + int isdir; + + int i = 0; + + while(i < 20 && !parseHalt) + { + entry = readdir(dir); + + if(entry == NULL) + break; + + if(entry->d_name[0] == '.' && entry->d_name[1] != '.') + continue; + + if(strcmp(entry->d_name, "..") == 0) + { + isdir = 1; + } + else + { + if(entry->d_type==DT_DIR) + isdir = 1; + else + isdir = 0; + + // don't show the file if it's not a valid ROM + if(parseFilter && !isdir) + { + ext = GetExt(entry->d_name); + + if(ext == NULL) + continue; + + if( strcasecmp(ext, "agb") != 0 && strcasecmp(ext, "gba") != 0 && + strcasecmp(ext, "bin") != 0 && strcasecmp(ext, "elf") != 0 && + strcasecmp(ext, "mb") != 0 && strcasecmp(ext, "dmg") != 0 && + strcasecmp(ext, "gb") != 0 && strcasecmp(ext, "gbc") != 0 && + strcasecmp(ext, "cgb") != 0 && strcasecmp(ext, "sgb") != 0 && + strcasecmp(ext, "zip") != 0 && strcasecmp(ext, "7z") != 0) + continue; + } + } + + if(!AddBrowserEntry()) + { + parseHalt = true; + break; + } + + snprintf(browserList[browser.numEntries+i].filename, MAXJOLIET, "%s", entry->d_name); + browserList[browser.numEntries+i].isdir = isdir; // flag this as a dir + + if(isdir) + { + if(strcmp(entry->d_name, "..") == 0) + sprintf(browserList[browser.numEntries+i].displayname, "Up One Level"); + else + snprintf(browserList[browser.numEntries+i].displayname, MAXJOLIET, "%s", browserList[browser.numEntries+i].filename); + browserList[browser.numEntries+i].icon = ICON_FOLDER; + } + else + { + StripExt(browserList[browser.numEntries+i].displayname, browserList[browser.numEntries+i].filename); // hide file extension + } + i++; + } + + if(!parseHalt) + { + // Sort the file list + if(i >= 0) + qsort(browserList, browser.numEntries+i, sizeof(BROWSERENTRY), FileSortCallback); + + browser.numEntries += i; + } + + if(entry == NULL || parseHalt) + { + closedir(dir); // close directory + dir = NULL; + + return false; // no more entries + } + return true; // more entries +} + +/*************************************************************************** + * Browse subdirectories + **************************************************************************/ +int +ParseDirectory(bool waitParse, bool filter) +{ + int retry = 1; + bool mounted = false; + parseFilter = filter; + + ResetBrowser(); // reset browser + + // add trailing slash + if(browser.dir[strlen(browser.dir)-1] != '/') + strcat(browser.dir, "/"); + + // open the directory + while(dir == NULL && retry == 1) + { + mounted = ChangeInterface(browser.dir, NOTSILENT); + + if(mounted) + dir = opendir(browser.dir); + else + return -1; + + if(dir == NULL) + retry = ErrorPromptRetry("Error opening directory!"); + } + + // if we can't open the dir, try higher levels + if (dir == NULL) + { + char * devEnd = strrchr(browser.dir, '/'); + + while(!IsDeviceRoot(browser.dir)) + { + devEnd[0] = 0; // strip slash + devEnd = strrchr(browser.dir, '/'); + + if(devEnd == NULL) + break; + + devEnd[1] = 0; // strip remaining file listing + dir = opendir(browser.dir); + if (dir) + break; + } + } + + if(dir == NULL) + return -1; + + if(IsDeviceRoot(browser.dir)) + { + AddBrowserEntry(); + sprintf(browserList[0].filename, ".."); + sprintf(browserList[0].displayname, "Up One Level"); + browserList[0].isdir = 1; // flag this as a dir + browserList[0].icon = ICON_FOLDER; + browser.numEntries++; + } + + parseHalt = false; + ParseDirEntries(); // index first 20 entries + + LWP_ResumeThread(parsethread); // index remaining entries + + if(waitParse) // wait for complete parsing + { + ShowAction("Loading..."); + + while(!LWP_ThreadIsSuspended(parsethread)) + usleep(THREAD_SLEEP); + + CancelAction(); + } + + return browser.numEntries; +} + +bool CreateDirectory(char * path) +{ + DIR *dir = opendir(path); + if (!dir) { + if(mkdir(path, 0777) != 0) { + return false; + } + } + else { + closedir(dir); + } + return true; +} + +/**************************************************************************** + * AllocSaveBuffer () + * Clear and allocate the savebuffer + ***************************************************************************/ +void +AllocSaveBuffer () +{ + if(bufferLock == LWP_MUTEX_NULL) + LWP_MutexInit(&bufferLock, false); + + if(bufferLock != LWP_MUTEX_NULL) + LWP_MutexLock(bufferLock); + memset (savebuffer, 0, SAVEBUFFERSIZE); +} + +/**************************************************************************** + * FreeSaveBuffer () + * Free the savebuffer memory + ***************************************************************************/ +void +FreeSaveBuffer () +{ + if(bufferLock != LWP_MUTEX_NULL) + LWP_MutexUnlock(bufferLock); +} + +/**************************************************************************** + * LoadSzFile + * Loads the selected file # from the specified 7z into rbuffer + * Returns file size + ***************************************************************************/ +size_t +LoadSzFile(char * filepath, unsigned char * rbuffer) +{ + size_t size = 0; + + // stop checking if devices were removed/inserted + // since we're loading a file + HaltDeviceThread(); + + // halt parsing + HaltParseThread(); + + file = fopen (filepath, "rb"); + if (file > 0) + { + size = SzExtractFile(browserList[browser.selIndex].filenum, rbuffer); + fclose (file); + } + else + { + ErrorPrompt("Error opening file!"); + } + + // go back to checking if devices were inserted/removed + ResumeDeviceThread(); + + return size; +} + +/**************************************************************************** + * LoadFile + ***************************************************************************/ +size_t +LoadFile (char * rbuffer, char *filepath, size_t length, size_t buffersize, bool silent) +{ + char zipbuffer[2048]; + size_t size = 0, offset = 0, readsize = 0; + int retry = 1; + int device; + + if(!FindDevice(filepath, &device)) + return 0; + + // stop checking if devices were removed/inserted + // since we're loading a file + HaltDeviceThread(); + + // halt parsing + HaltParseThread(); + + // open the file + while(retry) + { + if(!ChangeInterface(device, silent)) + break; + + file = fopen (filepath, "rb"); + + if(!file) + { + if(silent) + break; + + retry = ErrorPromptRetry("Error opening file!"); + continue; + } + + if(length > 0 && length <= 2048) // do a partial read (eg: to check file header) + { + size = fread (rbuffer, 1, length, file); + } + else // load whole file + { + readsize = fread (zipbuffer, 1, 32, file); + + if(!readsize) + { + unmountRequired[device] = true; + retry = ErrorPromptRetry("Error reading file!"); + fclose (file); + continue; + } + + if (IsZipFile (zipbuffer)) + { + size = UnZipBuffer ((unsigned char *)rbuffer, buffersize); // unzip + } + else + { + fseeko(file,0,SEEK_END); + size = ftello(file); + fseeko(file,0,SEEK_SET); + + if(size > buffersize) { + size = 0; + } + else { + while(!feof(file)) + { + ShowProgress ("Loading...", offset, size); + readsize = fread (rbuffer + offset, 1, 4096, file); // read in next chunk + + if(readsize <= 0) + break; // reading finished (or failed) + + offset += readsize; + } + size = offset; + CancelAction(); + } + } + } + retry = 0; + fclose (file); + } + + // go back to checking if devices were inserted/removed + ResumeDeviceThread(); + CancelAction(); + return size; +} + +size_t LoadFile(char * filepath, bool silent) +{ + return LoadFile((char *)savebuffer, filepath, 0, SAVEBUFFERSIZE, silent); +} + +/**************************************************************************** + * SaveFile + * Write buffer to file + ***************************************************************************/ +size_t +SaveFile (char * buffer, char *filepath, size_t datasize, bool silent) +{ + size_t written = 0; + size_t writesize, nextwrite; + int retry = 1; + int device; + + if(!FindDevice(filepath, &device)) + return 0; + + if(datasize == 0) + return 0; + + // stop checking if devices were removed/inserted + // since we're saving a file + HaltDeviceThread(); + + // halt parsing + HaltParseThread(); + + if(!silent) + ShowAction("Saving..."); + + while(!written && retry == 1) + { + if(!ChangeInterface(device, silent)) + break; + + file = fopen (filepath, "wb"); + + if(!file) + { + if(silent) + break; + + retry = ErrorPromptRetry("Error creating file!"); + continue; + } + + while(written < datasize) + { + if(datasize - written > 4096) nextwrite=4096; + else nextwrite = datasize-written; + writesize = fwrite (buffer+written, 1, nextwrite, file); + if(writesize != nextwrite) break; // write failure + written += writesize; + } + fclose (file); + + if(written != datasize) written = 0; + + if(!written) + { + unmountRequired[device] = true; + if(silent) break; + retry = ErrorPromptRetry("Error saving file!"); + } + } + + // go back to checking if devices were inserted/removed + ResumeDeviceThread(); + if(!silent) + CancelAction(); + return written; +} + +size_t SaveFile(char * filepath, size_t datasize, bool silent) +{ + return SaveFile((char *)savebuffer, filepath, datasize, silent); +} diff --git a/source/fileop.h b/source/fileop.h index 569200f..0bed018 100644 --- a/source/fileop.h +++ b/source/fileop.h @@ -1,52 +1,48 @@ -/**************************************************************************** - * Visual Boy Advance GX - * - * Tantric September 2008 - * - * fileop.h - * - * File operations - ****************************************************************************/ - -#ifndef _FILEOP_H_ -#define _FILEOP_H_ - -#include -#include -#include -#include -#include -#include - -#define SAVEBUFFERSIZE (1024 * 1024 * 2) // leave room for IPS/UPS files and larger images - -void InitDeviceThread(); -void ResumeDeviceThread(); -void HaltDeviceThread(); -void HaltParseThread(); -void MountAllFAT(); -void UnmountAllFAT(); -bool FindDevice(char * filepath, int * device); -char * StripDevice(char * path); -bool ChangeInterface(int device, bool silent); -bool ChangeInterface(char * filepath, bool silent); -void CreateAppPath(char * origpath); -bool GetFileSize(int i); -void FindAndSelectLastLoadedFile(); -int ParseDirectory(bool waitParse = false, bool filter = true); -bool CreateDirectory(char * path); -void AllocSaveBuffer(); -void FreeSaveBuffer(); -size_t LoadFile(char * rbuffer, char *filepath, size_t length, bool silent); -size_t LoadFile(char * filepath, bool silent); -size_t LoadSzFile(char * filepath, unsigned char * rbuffer); -size_t SaveFile(char * buffer, char *filepath, size_t datasize, bool silent); -size_t SaveFile(char * filepath, size_t datasize, bool silent); - -extern unsigned char *savebuffer; -extern FILE * file; -extern bool unmountRequired[]; -extern bool isMounted[]; -extern int selectLoadedFile; - -#endif +/**************************************************************************** + * Visual Boy Advance GX + * + * Tantric September 2008 + * + * fileop.h + * + * File operations + ****************************************************************************/ + +#ifndef _FILEOP_H_ +#define _FILEOP_H_ + +#include +#include +#include + +#define SAVEBUFFERSIZE (1024 * 1024 * 2) // leave room for IPS/UPS files and larger images + +void InitDeviceThread(); +void ResumeDeviceThread(); +void HaltDeviceThread(); +void HaltParseThread(); +void MountAllFAT(); +void UnmountAllFAT(); +bool FindDevice(char * filepath, int * device); +char * StripDevice(char * path); +bool ChangeInterface(int device, bool silent); +bool ChangeInterface(char * filepath, bool silent); +void CreateAppPath(char * origpath); +void FindAndSelectLastLoadedFile(); +int ParseDirectory(bool waitParse = false, bool filter = true); +bool CreateDirectory(char * path); +void AllocSaveBuffer(); +void FreeSaveBuffer(); +size_t LoadFile(char * rbuffer, char *filepath, size_t length, size_t buffersize, bool silent); +size_t LoadFile(char * filepath, bool silent); +size_t LoadSzFile(char * filepath, unsigned char * rbuffer); +size_t SaveFile(char * buffer, char *filepath, size_t datasize, bool silent); +size_t SaveFile(char * filepath, size_t datasize, bool silent); + +extern unsigned char *savebuffer; +extern FILE * file; +extern bool unmountRequired[]; +extern bool isMounted[]; +extern int selectLoadedFile; + +#endif diff --git a/source/gcunzip.cpp b/source/gcunzip.cpp index f9033a4..24ec5a7 100644 --- a/source/gcunzip.cpp +++ b/source/gcunzip.cpp @@ -1,526 +1,529 @@ -/**************************************************************************** - * Visual Boy Advance GX - * - * Tantric September 2008 - * - * gcunzip.cpp - * - * File unzip routines - ***************************************************************************/ - -#include -#include -#include -#include -#include -#include - -#include "vbagx.h" -#include "fileop.h" -#include "filebrowser.h" -#include "menu.h" -#include "gcunzip.h" - -extern "C" { -#include "utils/sz/7zCrc.h" -#include "utils/sz/7zIn.h" -#include "utils/sz/7zExtract.h" -} - -#define ZIPCHUNK 2048 - -/* - * Zip file header definition - */ -typedef struct -{ - unsigned int zipid __attribute__ ((__packed__)); // 0x04034b50 - unsigned short zipversion __attribute__ ((__packed__)); - unsigned short zipflags __attribute__ ((__packed__)); - unsigned short compressionMethod __attribute__ ((__packed__)); - unsigned short lastmodtime __attribute__ ((__packed__)); - unsigned short lastmoddate __attribute__ ((__packed__)); - unsigned int crc32 __attribute__ ((__packed__)); - unsigned int compressedSize __attribute__ ((__packed__)); - unsigned int uncompressedSize __attribute__ ((__packed__)); - unsigned short filenameLength __attribute__ ((__packed__)); - unsigned short extraDataLength __attribute__ ((__packed__)); -} -PKZIPHEADER; - -/* - * Zip files are stored little endian - * Support functions for short and int types - */ -static u32 -FLIP32 (u32 b) -{ - unsigned int c; - - c = (b & 0xff000000) >> 24; - c |= (b & 0xff0000) >> 8; - c |= (b & 0xff00) << 8; - c |= (b & 0xff) << 24; - - return c; -} - -static u16 -FLIP16 (u16 b) -{ - u16 c; - - c = (b & 0xff00) >> 8; - c |= (b & 0xff) << 8; - - return c; -} - -/**************************************************************************** - * IsZipFile - * - * Returns TRUE when 0x504b0304 is first four characters of buffer - ***************************************************************************/ -int -IsZipFile (char *buffer) -{ - unsigned int *check = (unsigned int *) buffer; - - if (check[0] == 0x504b0304) - return 1; - - return 0; -} - -/***************************************************************************** -* UnZipBuffer -******************************************************************************/ - -size_t -UnZipBuffer (unsigned char *outbuffer) -{ - PKZIPHEADER pkzip; - size_t zipoffset = 0; - size_t zipchunk = 0; - char out[ZIPCHUNK]; - z_stream zs; - int res; - size_t bufferoffset = 0; - size_t have = 0; - char readbuffer[ZIPCHUNK]; - size_t sizeread = 0; - - // Read Zip Header - fseek(file, 0, SEEK_SET); - sizeread = fread (readbuffer, 1, ZIPCHUNK, file); - - if(sizeread <= 0) - return 0; - - /*** Copy PKZip header to local, used as info ***/ - memcpy (&pkzip, readbuffer, sizeof (PKZIPHEADER)); - - pkzip.uncompressedSize = FLIP32 (pkzip.uncompressedSize); - - ShowProgress ("Loading...", 0, pkzip.uncompressedSize); - - /*** Prepare the zip stream ***/ - memset (&zs, 0, sizeof (z_stream)); - zs.zalloc = Z_NULL; - zs.zfree = Z_NULL; - zs.opaque = Z_NULL; - zs.avail_in = 0; - zs.next_in = Z_NULL; - res = inflateInit2 (&zs, -MAX_WBITS); - - if (res != Z_OK) - goto done; - - /*** Set ZipChunk for first pass ***/ - zipoffset = - (sizeof (PKZIPHEADER) + FLIP16 (pkzip.filenameLength) + - FLIP16 (pkzip.extraDataLength)); - zipchunk = ZIPCHUNK - zipoffset; - - /*** Now do it! ***/ - do - { - zs.avail_in = zipchunk; - zs.next_in = (Bytef *) & readbuffer[zipoffset]; - - /*** Now inflate until input buffer is exhausted ***/ - do - { - zs.avail_out = ZIPCHUNK; - zs.next_out = (Bytef *) & out; - - res = inflate (&zs, Z_NO_FLUSH); - - if (res == Z_MEM_ERROR) - { - goto done; - } - - have = ZIPCHUNK - zs.avail_out; - if (have) - { - /*** Copy to normal block buffer ***/ - memcpy (&outbuffer[bufferoffset], &out, have); - bufferoffset += have; - } - } - while (zs.avail_out == 0); - - // Readup the next 2k block - zipoffset = 0; - zipchunk = ZIPCHUNK; - - sizeread = fread (readbuffer, 1, ZIPCHUNK, file); - if(sizeread <= 0) - goto done; // read failure - - ShowProgress ("Loading...", bufferoffset, pkzip.uncompressedSize); - } - while (res != Z_STREAM_END); - -done: - inflateEnd (&zs); - CancelAction(); - - if (res == Z_STREAM_END) - return pkzip.uncompressedSize; - else - return 0; -} - -/**************************************************************************** -* GetFirstZipFilename -* -* Returns the filename of the first file in the zipped archive -* The idea here is to do the least amount of work required -***************************************************************************/ - -char * -GetFirstZipFilename () -{ - char * firstFilename = NULL; - char tempbuffer[ZIPCHUNK]; - char filepath[1024]; - - if(!MakeFilePath(filepath, FILE_ROM)) - return NULL; - - // read start of ZIP - if(LoadFile (tempbuffer, filepath, ZIPCHUNK, NOTSILENT) < 35) - return NULL; - - tempbuffer[28] = 0; // truncate - filename length is 2 bytes long (bytes 26-27) - int namelength = tempbuffer[26]; // filename length starts 26 bytes in - - if(namelength < 0 || namelength > 200) // filename is not a reasonable length - { - ErrorPrompt("Error - Invalid ZIP file!"); - return NULL; - } - - firstFilename = &tempbuffer[30]; // first filename of a ZIP starts 31 bytes in - firstFilename[namelength] = 0; // truncate at filename length - return strdup(firstFilename); -} - -/**************************************************************************** -* 7z functions -***************************************************************************/ - -typedef struct _SzFileInStream -{ - ISzInStream InStream; - u64 offset; // offset of the file - unsigned int len; // length of the file - u64 pos; // current position of the file pointer -} SzFileInStream; - -// 7zip error list -static char szerrormsg[][100] = { - "File is corrupt.", // 7z: Data error - "Archive contains too many files.", // 7z: Out of memory - "File is corrupt (CRC mismatch).", // 7z: CRC Error - "File uses unsupported compression settings.", // 7z: Not implemented - "File is corrupt.", // 7z: Fail - "Failed to read file data.", // 7z: Data read failure - "File is corrupt.", // 7z: Archive error - "File uses too high of compression settings (dictionary size is too large).", // 7z: Dictionary too large -}; - -static SZ_RESULT SzRes; -static SzFileInStream SzArchiveStream; -static CArchiveDatabaseEx SzDb; -static ISzAlloc SzAllocImp; -static ISzAlloc SzAllocTempImp; -static UInt32 SzBlockIndex = 0xFFFFFFFF; -static size_t SzBufferSize; -static size_t SzOffset; -static size_t SzOutSizeProcessed; -static CFileItem *SzF; - -static char sz_buffer[2048]; -static int szMethod = 0; - -/**************************************************************************** -* Is7ZipFile -* -* Returns 1 when 7z signature is found -****************************************************************************/ -int -Is7ZipFile (char *buffer) -{ - // 7z signature - static Byte Signature[6] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C}; - - int i; - for(i = 0; i < 6; i++) - if(buffer[i] != Signature[i]) - return 0; - - return 1; // 7z archive found -} - -// display an error message -static void SzDisplayError(SZ_RESULT res) -{ - char msg[1024]; - sprintf(msg, "7z decompression failed: %s", szerrormsg[(res - 1)]); - ErrorPrompt(msg); -} - -// function used by the 7zip SDK to read data from SD/USB/DVD/SMB -static SZ_RESULT SzFileReadImp(void *object, void **buffer, size_t maxRequiredSize, size_t *processedSize) -{ - size_t sizeread = 0; - - if(maxRequiredSize == 0) - return SZ_OK; - - // the void* object is a SzFileInStream - SzFileInStream *s = (SzFileInStream *) object; - - if (maxRequiredSize > 2048) - maxRequiredSize = 2048; - - // read data - sizeread = fread(sz_buffer, 1, maxRequiredSize, file); - - if(sizeread <= 0) - return SZE_FAILREAD; - - *buffer = sz_buffer; - *processedSize = sizeread; - s->pos += sizeread; - - if(sizeread > 1024) // only show progress for large reads - // this isn't quite right, but oh well - ShowProgress ("Loading...", s->pos, browserList[browser.selIndex].length); - - return SZ_OK; -} - -// function used by the 7zip SDK to change the filepointer -static SZ_RESULT SzFileSeekImp(void *object, CFileSize pos) -{ - // the void* object is a SzFileInStream - SzFileInStream *s = (SzFileInStream *) object; - - // check if the 7z SDK wants to move the pointer to somewhere after the EOF - if (pos >= s->len) - return SZE_FAIL; - - // save new position and return - if(fseek(file, (long)pos, SEEK_SET) != 0) - return SZE_FAIL; - - s->pos = pos; - return SZ_OK; -} - -/**************************************************************************** -* SzClose -* -* Closes a 7z file -***************************************************************************/ - -void SzClose() -{ - if(SzDb.Database.NumFiles > 0) - SzArDbExFree(&SzDb, SzAllocImp.Free); -} - -/**************************************************************************** -* SzParse -* -* Opens a 7z file, and parses it -* It parses the entire 7z for full browsing capability -***************************************************************************/ - -int SzParse(char * filepath) -{ - if(!filepath) - return 0; - - int device; - - struct stat filestat; - if(stat(filepath, &filestat) < 0) - return 0; - unsigned int filelen = filestat.st_size; - - if(!FindDevice(filepath, &device) || !filelen) - return 0; - - int nbfiles = 0; - // setup archive stream - SzArchiveStream.offset = 0; - SzArchiveStream.len = filelen; - SzArchiveStream.pos = 0; - - // open file - file = fopen (filepath, "rb"); - if(!file) - return 0; - - // set szMethod to current chosen load device - szMethod = device; - - // set handler functions for reading data from SD/USB/SMB/DVD - SzArchiveStream.InStream.Read = SzFileReadImp; - SzArchiveStream.InStream.Seek = SzFileSeekImp; - - // set default 7Zip SDK handlers for allocation and freeing memory - SzAllocImp.Alloc = SzAlloc; - SzAllocImp.Free = SzFree; - SzAllocTempImp.Alloc = SzAllocTemp; - SzAllocTempImp.Free = SzFreeTemp; - - // prepare CRC and 7Zip database structures - InitCrcTable(); - SzArDbExInit(&SzDb); - - // open the archive - SzRes = SzArchiveOpen(&SzArchiveStream.InStream, &SzDb, &SzAllocImp, - &SzAllocTempImp); - - if (SzRes != SZ_OK) - { - SzDisplayError(SzRes); - // free memory used by the 7z SDK - SzClose(); - } - else // archive opened successfully - { - if(SzDb.Database.NumFiles > 0) - { - // Parses the 7z into a full file listing - - HaltParseThread(); // halt parsing - ResetBrowser(); // reset browser - - // add '..' folder in case the user wants exit the 7z - AddBrowserEntry(); - sprintf(browserList[0].filename, ".."); - sprintf(browserList[0].displayname, "Up One Level"); - browserList[0].isdir = 1; - browserList[0].length = filelen; - browserList[0].icon = ICON_FOLDER; - - // get contents and parse them into file list structure - unsigned int SzI, SzJ; - SzJ = 1; - for (SzI = 0; SzI < SzDb.Database.NumFiles; SzI++) - { - SzF = SzDb.Database.Files + SzI; - - // skip directories - if (SzF->IsDirectory) - continue; - - if(!AddBrowserEntry()) - { - ResetBrowser(); - ErrorPrompt("Out of memory: too many files!"); - SzClose(); - SzJ = 0; - break; - } - - // parse information about this file to the file list structure - snprintf(browserList[SzJ].filename, MAXJOLIET, "%s", SzF->Name); - StripExt(browserList[SzJ].displayname, browserList[SzJ].filename); - char* strPos = strstr(browserList[SzJ].displayname, szname); - if(strPos) - { - snprintf(browserList[SzJ].displayname, MAXJOLIET, "%s", strPos + strlen(szname)); - } - - browserList[SzJ].length = SzF->Size; // filesize - browserList[SzJ].isdir = 0; // only files will be displayed (-> no flags) - browserList[SzJ].filenum = SzI; // the extraction function identifies the file with this number - SzJ++; - } - nbfiles = SzJ; - } - else - { - SzClose(); - } - } - - CancelAction(); - - // close file - fclose(file); - return nbfiles; -} - -/**************************************************************************** -* SzExtractFile -* -* Extracts the given file # into the buffer specified -* Must parse the 7z BEFORE running this function -***************************************************************************/ - -size_t SzExtractFile(int i, unsigned char *buffer) -{ - // prepare some variables - SzBlockIndex = 0xFFFFFFFF; - SzOffset = 0; - - // Unzip the file - - SzRes = SzExtract2( - &SzArchiveStream.InStream, - &SzDb, - i, // index of file - &SzBlockIndex, // index of solid block - &buffer, - &SzBufferSize, - &SzOffset, // offset of stream for required file in *outBuffer - &SzOutSizeProcessed, // size of file in *outBuffer - &SzAllocImp, - &SzAllocTempImp); - - // close 7Zip archive and free memory - SzClose(); - - CancelAction(); - - // check for errors - if(SzRes != SZ_OK) - { - // display error message - SzDisplayError(SzRes); - return 0; - } - else - { - return SzOutSizeProcessed; - } -} +/**************************************************************************** + * Visual Boy Advance GX + * + * Tantric September 2008 + * + * gcunzip.cpp + * + * File unzip routines + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include "vbagx.h" +#include "fileop.h" +#include "filebrowser.h" +#include "menu.h" +#include "gcunzip.h" + +extern "C" { +#include "utils/sz/7zCrc.h" +#include "utils/sz/7zIn.h" +#include "utils/sz/7zExtract.h" +} + +#define ZIPCHUNK 2048 + +/* + * Zip file header definition + */ +typedef struct +{ + unsigned int zipid __attribute__ ((__packed__)); // 0x04034b50 + unsigned short zipversion __attribute__ ((__packed__)); + unsigned short zipflags __attribute__ ((__packed__)); + unsigned short compressionMethod __attribute__ ((__packed__)); + unsigned short lastmodtime __attribute__ ((__packed__)); + unsigned short lastmoddate __attribute__ ((__packed__)); + unsigned int crc32 __attribute__ ((__packed__)); + unsigned int compressedSize __attribute__ ((__packed__)); + unsigned int uncompressedSize __attribute__ ((__packed__)); + unsigned short filenameLength __attribute__ ((__packed__)); + unsigned short extraDataLength __attribute__ ((__packed__)); +} +PKZIPHEADER; + +/* + * Zip files are stored little endian + * Support functions for short and int types + */ +static u32 +FLIP32 (u32 b) +{ + unsigned int c; + + c = (b & 0xff000000) >> 24; + c |= (b & 0xff0000) >> 8; + c |= (b & 0xff00) << 8; + c |= (b & 0xff) << 24; + + return c; +} + +static u16 +FLIP16 (u16 b) +{ + u16 c; + + c = (b & 0xff00) >> 8; + c |= (b & 0xff) << 8; + + return c; +} + +/**************************************************************************** + * IsZipFile + * + * Returns TRUE when 0x504b0304 is first four characters of buffer + ***************************************************************************/ +int +IsZipFile (char *buffer) +{ + unsigned int *check = (unsigned int *) buffer; + + if (check[0] == 0x504b0304) + return 1; + + return 0; +} + +/***************************************************************************** +* UnZipBuffer +******************************************************************************/ + +size_t +UnZipBuffer (unsigned char *outbuffer, size_t buffersize) +{ + PKZIPHEADER pkzip; + size_t zipoffset = 0; + size_t zipchunk = 0; + char out[ZIPCHUNK]; + z_stream zs; + int res; + size_t bufferoffset = 0; + size_t have = 0; + char readbuffer[ZIPCHUNK]; + size_t sizeread = 0; + + // Read Zip Header + fseek(file, 0, SEEK_SET); + sizeread = fread (readbuffer, 1, ZIPCHUNK, file); + + if(sizeread <= 0) + return 0; + + /*** Copy PKZip header to local, used as info ***/ + memcpy (&pkzip, readbuffer, sizeof (PKZIPHEADER)); + + pkzip.uncompressedSize = FLIP32 (pkzip.uncompressedSize); + + if(pkzip.uncompressedSize > buffersize) { + return 0; + } + + ShowProgress ("Loading...", 0, pkzip.uncompressedSize); + + /*** Prepare the zip stream ***/ + memset (&zs, 0, sizeof (z_stream)); + zs.zalloc = Z_NULL; + zs.zfree = Z_NULL; + zs.opaque = Z_NULL; + zs.avail_in = 0; + zs.next_in = Z_NULL; + res = inflateInit2 (&zs, -MAX_WBITS); + + if (res != Z_OK) + goto done; + + /*** Set ZipChunk for first pass ***/ + zipoffset = + (sizeof (PKZIPHEADER) + FLIP16 (pkzip.filenameLength) + + FLIP16 (pkzip.extraDataLength)); + zipchunk = ZIPCHUNK - zipoffset; + + /*** Now do it! ***/ + do + { + zs.avail_in = zipchunk; + zs.next_in = (Bytef *) & readbuffer[zipoffset]; + + /*** Now inflate until input buffer is exhausted ***/ + do + { + zs.avail_out = ZIPCHUNK; + zs.next_out = (Bytef *) & out; + + res = inflate (&zs, Z_NO_FLUSH); + + if (res == Z_MEM_ERROR) + { + goto done; + } + + have = ZIPCHUNK - zs.avail_out; + if (have) + { + /*** Copy to normal block buffer ***/ + memcpy (&outbuffer[bufferoffset], &out, have); + bufferoffset += have; + } + } + while (zs.avail_out == 0); + + // Readup the next 2k block + zipoffset = 0; + zipchunk = ZIPCHUNK; + + sizeread = fread (readbuffer, 1, ZIPCHUNK, file); + if(sizeread <= 0) + goto done; // read failure + + ShowProgress ("Loading...", bufferoffset, pkzip.uncompressedSize); + } + while (res != Z_STREAM_END); + +done: + inflateEnd (&zs); + CancelAction(); + + if (res == Z_STREAM_END) + return pkzip.uncompressedSize; + else + return 0; +} + +/**************************************************************************** +* GetFirstZipFilename +* +* Returns the filename of the first file in the zipped archive +* The idea here is to do the least amount of work required +***************************************************************************/ + +char * +GetFirstZipFilename () +{ + char * firstFilename = NULL; + char tempbuffer[ZIPCHUNK]; + char filepath[1024]; + + if(!MakeFilePath(filepath, FILE_ROM)) + return NULL; + + // read start of ZIP + if(LoadFile (tempbuffer, filepath, ZIPCHUNK, ZIPCHUNK, NOTSILENT) < 35) + return NULL; + + tempbuffer[28] = 0; // truncate - filename length is 2 bytes long (bytes 26-27) + int namelength = tempbuffer[26]; // filename length starts 26 bytes in + + if(namelength < 0 || namelength > 200) // filename is not a reasonable length + { + ErrorPrompt("Error - Invalid ZIP file!"); + return NULL; + } + + firstFilename = &tempbuffer[30]; // first filename of a ZIP starts 31 bytes in + firstFilename[namelength] = 0; // truncate at filename length + return strdup(firstFilename); +} + +/**************************************************************************** +* 7z functions +***************************************************************************/ + +typedef struct _SzFileInStream +{ + ISzInStream InStream; + u64 offset; // offset of the file + unsigned int len; // length of the file + u64 pos; // current position of the file pointer +} SzFileInStream; + +// 7zip error list +static char szerrormsg[][100] = { + "File is corrupt.", // 7z: Data error + "Archive contains too many files.", // 7z: Out of memory + "File is corrupt (CRC mismatch).", // 7z: CRC Error + "File uses unsupported compression settings.", // 7z: Not implemented + "File is corrupt.", // 7z: Fail + "Failed to read file data.", // 7z: Data read failure + "File is corrupt.", // 7z: Archive error + "File uses too high of compression settings (dictionary size is too large).", // 7z: Dictionary too large +}; + +static SZ_RESULT SzRes; +static SzFileInStream SzArchiveStream; +static CArchiveDatabaseEx SzDb; +static ISzAlloc SzAllocImp; +static ISzAlloc SzAllocTempImp; +static UInt32 SzBlockIndex = 0xFFFFFFFF; +static size_t SzBufferSize; +static size_t SzOffset; +static size_t SzOutSizeProcessed; +static CFileItem *SzF; + +static char sz_buffer[2048]; +static int szMethod = 0; + +/**************************************************************************** +* Is7ZipFile +* +* Returns 1 when 7z signature is found +****************************************************************************/ +int +Is7ZipFile (char *buffer) +{ + // 7z signature + static Byte Signature[6] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C}; + + int i; + for(i = 0; i < 6; i++) + if(buffer[i] != Signature[i]) + return 0; + + return 1; // 7z archive found +} + +// display an error message +static void SzDisplayError(SZ_RESULT res) +{ + char msg[1024]; + sprintf(msg, "7z decompression failed: %s", szerrormsg[(res - 1)]); + ErrorPrompt(msg); +} + +// function used by the 7zip SDK to read data from SD/USB/DVD/SMB +static SZ_RESULT SzFileReadImp(void *object, void **buffer, size_t maxRequiredSize, size_t *processedSize) +{ + size_t sizeread = 0; + + if(maxRequiredSize == 0) + return SZ_OK; + + // the void* object is a SzFileInStream + SzFileInStream *s = (SzFileInStream *) object; + + if (maxRequiredSize > 2048) + maxRequiredSize = 2048; + + // read data + sizeread = fread(sz_buffer, 1, maxRequiredSize, file); + + if(sizeread <= 0) + return SZE_FAILREAD; + + *buffer = sz_buffer; + *processedSize = sizeread; + s->pos += sizeread; + + if(sizeread > 1024) // only show progress for large reads + // this isn't quite right, but oh well + ShowProgress ("Loading...", s->pos, browserList[browser.selIndex].length); + + return SZ_OK; +} + +// function used by the 7zip SDK to change the filepointer +static SZ_RESULT SzFileSeekImp(void *object, CFileSize pos) +{ + // the void* object is a SzFileInStream + SzFileInStream *s = (SzFileInStream *) object; + + // check if the 7z SDK wants to move the pointer to somewhere after the EOF + if (pos >= s->len) + return SZE_FAIL; + + // save new position and return + if(fseek(file, (long)pos, SEEK_SET) != 0) + return SZE_FAIL; + + s->pos = pos; + return SZ_OK; +} + +/**************************************************************************** +* SzClose +* +* Closes a 7z file +***************************************************************************/ + +void SzClose() +{ + if(SzDb.Database.NumFiles > 0) + SzArDbExFree(&SzDb, SzAllocImp.Free); +} + +/**************************************************************************** +* SzParse +* +* Opens a 7z file, and parses it +* It parses the entire 7z for full browsing capability +***************************************************************************/ + +int SzParse(char * filepath) +{ + if(!filepath) + return 0; + + int device; + + struct stat filestat; + if(stat(filepath, &filestat) < 0) + return 0; + unsigned int filelen = filestat.st_size; + + if(!FindDevice(filepath, &device) || !filelen) + return 0; + + int nbfiles = 0; + // setup archive stream + SzArchiveStream.offset = 0; + SzArchiveStream.len = filelen; + SzArchiveStream.pos = 0; + + // open file + file = fopen (filepath, "rb"); + if(!file) + return 0; + + // set szMethod to current chosen load device + szMethod = device; + + // set handler functions for reading data from SD/USB/SMB/DVD + SzArchiveStream.InStream.Read = SzFileReadImp; + SzArchiveStream.InStream.Seek = SzFileSeekImp; + + // set default 7Zip SDK handlers for allocation and freeing memory + SzAllocImp.Alloc = SzAlloc; + SzAllocImp.Free = SzFree; + SzAllocTempImp.Alloc = SzAllocTemp; + SzAllocTempImp.Free = SzFreeTemp; + + // prepare CRC and 7Zip database structures + InitCrcTable(); + SzArDbExInit(&SzDb); + + // open the archive + SzRes = SzArchiveOpen(&SzArchiveStream.InStream, &SzDb, &SzAllocImp, + &SzAllocTempImp); + + if (SzRes != SZ_OK) + { + SzDisplayError(SzRes); + // free memory used by the 7z SDK + SzClose(); + } + else // archive opened successfully + { + if(SzDb.Database.NumFiles > 0) + { + // Parses the 7z into a full file listing + + HaltParseThread(); // halt parsing + ResetBrowser(); // reset browser + + // add '..' folder in case the user wants exit the 7z + AddBrowserEntry(); + sprintf(browserList[0].filename, ".."); + sprintf(browserList[0].displayname, "Up One Level"); + browserList[0].isdir = 1; + browserList[0].icon = ICON_FOLDER; + + // get contents and parse them into file list structure + unsigned int SzI, SzJ; + SzJ = 1; + for (SzI = 0; SzI < SzDb.Database.NumFiles; SzI++) + { + SzF = SzDb.Database.Files + SzI; + + // skip directories + if (SzF->IsDirectory) + continue; + + if(!AddBrowserEntry()) + { + ResetBrowser(); + ErrorPrompt("Out of memory: too many files!"); + SzClose(); + SzJ = 0; + break; + } + + // parse information about this file to the file list structure + snprintf(browserList[SzJ].filename, MAXJOLIET, "%s", SzF->Name); + StripExt(browserList[SzJ].displayname, browserList[SzJ].filename); + char* strPos = strstr(browserList[SzJ].displayname, szname); + if(strPos) + { + snprintf(browserList[SzJ].displayname, MAXJOLIET, "%s", strPos + strlen(szname)); + } + + browserList[SzJ].length = SzF->Size; // filesize + browserList[SzJ].isdir = 0; // only files will be displayed (-> no flags) + browserList[SzJ].filenum = SzI; // the extraction function identifies the file with this number + SzJ++; + } + nbfiles = SzJ; + } + else + { + SzClose(); + } + } + + CancelAction(); + + // close file + fclose(file); + return nbfiles; +} + +/**************************************************************************** +* SzExtractFile +* +* Extracts the given file # into the buffer specified +* Must parse the 7z BEFORE running this function +***************************************************************************/ + +size_t SzExtractFile(int i, unsigned char *buffer) +{ + // prepare some variables + SzBlockIndex = 0xFFFFFFFF; + SzOffset = 0; + + // Unzip the file + + SzRes = SzExtract2( + &SzArchiveStream.InStream, + &SzDb, + i, // index of file + &SzBlockIndex, // index of solid block + &buffer, + &SzBufferSize, + &SzOffset, // offset of stream for required file in *outBuffer + &SzOutSizeProcessed, // size of file in *outBuffer + &SzAllocImp, + &SzAllocTempImp); + + // close 7Zip archive and free memory + SzClose(); + + CancelAction(); + + // check for errors + if(SzRes != SZ_OK) + { + // display error message + SzDisplayError(SzRes); + return 0; + } + else + { + return SzOutSizeProcessed; + } +} diff --git a/source/gcunzip.h b/source/gcunzip.h index 689a80a..1986ebf 100644 --- a/source/gcunzip.h +++ b/source/gcunzip.h @@ -12,7 +12,7 @@ int IsZipFile (char *buffer); char * GetFirstZipFilename(); -size_t UnZipBuffer (unsigned char *outbuffer); +size_t UnZipBuffer (unsigned char *outbuffer, size_t buffersize); int SzParse(char * filepath); size_t SzExtractFile(int i, unsigned char *buffer); void SzClose(); diff --git a/source/vbasupport.cpp b/source/vbasupport.cpp index 9d86704..913861c 100644 --- a/source/vbasupport.cpp +++ b/source/vbasupport.cpp @@ -420,7 +420,7 @@ bool SaveBatteryOrState(char * filepath, int action, bool silent) const char* generic_goomba_error = "Cannot save SRAM in Goomba format (did not load correctly.)"; // check for goomba sram format char* old_sram = (char*)malloc(GOOMBA_COLOR_SRAM_SIZE); - size_t br = LoadFile(old_sram, filepath, GOOMBA_COLOR_SRAM_SIZE, true); + size_t br = LoadFile(old_sram, filepath, GOOMBA_COLOR_SRAM_SIZE, GOOMBA_COLOR_SRAM_SIZE, true); if (br >= GOOMBA_COLOR_SRAM_SIZE && goomba_is_sram(old_sram)) { void* cleaned = goomba_cleanup(old_sram); if (cleaned == NULL) { @@ -1005,12 +1005,12 @@ void LoadPNGBorder(const char* fallback) char error[1024]; error[1023] = 0; int r; - bool borderLoaded = LoadFile((char*)png_tmp_buf, borderPath, 1024*1024, SILENT); + bool borderLoaded = LoadFile((char*)png_tmp_buf, borderPath, 0, 1024*1024, SILENT); if (!borderLoaded) { // Try default border.png free(borderPath); borderPath = AllocAndGetPNGBorderPath(fallback); - borderLoaded = LoadFile((char*)png_tmp_buf, borderPath, 1024*1024, SILENT); + borderLoaded = LoadFile((char*)png_tmp_buf, borderPath, 0, 1024*1024, SILENT); } if (!borderLoaded) goto cleanup; @@ -1060,12 +1060,7 @@ bool LoadGBROM() { gbEmulatorType = GCSettings.GBHardware; - if (browserList[browser.selIndex].length > 1024*1024*8) - { - InfoPrompt("ROM size is too large (> 8 MB)"); - return false; - } - gbRom = (u8 *)malloc(1024*1024*8); // 32 MB is too much for sure + gbRom = (u8 *)malloc(1024*1024*8); if (!gbRom) { InfoPrompt("Unable to allocate 8 MB of memory"); @@ -1082,7 +1077,7 @@ bool LoadGBROM() if(!MakeFilePath(filepath, FILE_ROM)) return false; - gbRomSize = LoadFile ((char *)gbRom, filepath, browserList[browser.selIndex].length, NOTSILENT); + gbRomSize = LoadFile ((char *)gbRom, filepath, 0, (1024*1024*8), NOTSILENT); } else { @@ -1174,12 +1169,6 @@ bool LoadVBAROM() ErrorPrompt("Unrecognized file extension!"); return false; } - - if(!GetFileSize(browser.selIndex)) - { - ErrorPrompt("Error loading game!"); - return false; - } srcWidth = 0; srcHeight = 0; diff --git a/source/vmmem.cpp b/source/vmmem.cpp index f14d573..1fe11db 100644 --- a/source/vmmem.cpp +++ b/source/vmmem.cpp @@ -165,7 +165,7 @@ int VMCPULoadROM() if(!MakeFilePath(filepath, FILE_ROM)) return 0; - GBAROMSize = LoadFile ((char *)rom, filepath, browserList[browser.selIndex].length, NOTSILENT); + GBAROMSize = LoadFile ((char *)rom, filepath, 0, (1024*1024*32), NOTSILENT); } else {