bool MDFNFILE::Open(const char *path, const FileExtensionSpecStruct *known_ext, const char *purpose, const bool suppress_notfound_pe) { void *t; unzFile tz; local_errno = 0; error_code = MDFNFILE_EC_OTHER; // Set to 0 at the end if the function succeeds. //f_data = (uint8 *)0xDEADBEEF; // Try opening it as a zip file first if((tz = unzOpen(path))) { char tempu[1024]; int errcode; if((errcode = unzGoToFirstFile(tz)) != UNZ_OK) { MDFN_PrintError(_("Could not seek to first file in ZIP archive: %s"), unzErrorString(errcode)); unzClose(tz); return(NULL); } if(known_ext) { bool FileFound = FALSE; while(!FileFound) { size_t tempu_strlen; const FileExtensionSpecStruct *ext_search = known_ext; if((errcode = unzGetCurrentFileInfo(tz, 0, tempu, 1024, 0, 0, 0, 0)) != UNZ_OK) { MDFN_PrintError(_("Could not get file information in ZIP archive: %s"), unzErrorString(errcode)); unzClose(tz); return(NULL); } tempu[1023] = 0; tempu_strlen = strlen(tempu); while(ext_search->extension && !FileFound) { size_t ttmeow = strlen(ext_search->extension); if(tempu_strlen >= ttmeow) { if(!strcasecmp(tempu + tempu_strlen - ttmeow, ext_search->extension)) FileFound = TRUE; } ext_search++; } if(FileFound) break; if((errcode = unzGoToNextFile(tz)) != UNZ_OK) { if(errcode != UNZ_END_OF_LIST_OF_FILE) { MDFN_PrintError(_("Error seeking to next file in ZIP archive: %s"), unzErrorString(errcode)); unzClose(tz); return(NULL); } if((errcode = unzGoToFirstFile(tz)) != UNZ_OK) { MDFN_PrintError(_("Could not seek to first file in ZIP archive: %s"), unzErrorString(errcode)); unzClose(tz); return(NULL); } break; } } // end to while(!FileFound) } // end to if(ext) if((errcode = unzOpenCurrentFile(tz)) != UNZ_OK) { MDFN_PrintError(_("Could not open file in ZIP archive: %s"), unzErrorString(errcode)); unzClose(tz); return(NULL); } if(!MakeMemWrap(tz, MDFN_FILETYPE_ZIP)) return(0); char *ld = strrchr(tempu, '.'); f_ext = strdup(ld ? ld + 1 : ""); } else // If it's not a zip file, handle it as...another type of file! { if(!(t = fopen(path,"rb"))) { ErrnoHolder ene(errno); local_errno = ene.Errno(); if(ene.Errno() == ENOENT) { local_errno = ene.Errno(); error_code = MDFNFILE_EC_NOTFOUND; } if(ene.Errno() != ENOENT || !suppress_notfound_pe) MDFN_PrintError(_("Error opening \"%s\": %s"), path, ene.StrError()); return(0); } uint32 gzmagic; gzmagic = ::fgetc((FILE *)t); gzmagic |= ::fgetc((FILE *)t)<<8; gzmagic |= ::fgetc((FILE *)t)<<16; if(gzmagic!=0x088b1f) /* Not gzip... */ { ::fseek((FILE *)t,0,SEEK_SET); if(!MakeMemWrap(t, 0)) return(0); const char *ld = strrchr(path, '.'); f_ext = strdup(ld ? ld + 1 : ""); } else /* Probably gzip */ { int fd; //fd = dup(fileno( (FILE *)t)); lseek(fd, 0, SEEK_SET); if(!(t=gzdopen(fd, "rb"))) { close(fd); return(0); } if(!MakeMemWrap(t, 1)) { gzclose(t); return(0); } char *tmp_path = strdup(path); char *ld = strrchr(tmp_path, '.'); if(ld && ld > tmp_path) { char *last_ld = ld; *ld = 0; ld = strrchr(tmp_path, '.'); if(!ld) { *last_ld = '.'; ld = last_ld; } } f_ext = strdup(ld ? ld + 1 : ""); free(tmp_path); } // End gzip handling } // End normal and gzip file handling else to zip // FIXME: Handle extension fixing for cases where loaded filename is like "moo.moo/lalala" error_code = 0; return(TRUE); }
void MDFNFILE::Open(const char *path, const FileExtensionSpecStruct *known_ext, const char *purpose) { unzFile tz = NULL; try { // // Try opening it as a zip file first // if((tz = unzOpen(path))) { char tempu[1024]; int errcode; if((errcode = unzGoToFirstFile(tz)) != UNZ_OK) { throw MDFN_Error(0, _("Could not seek to first file in ZIP archive: %s"), unzErrorString(errcode)); } if(known_ext) { bool FileFound = FALSE; while(!FileFound) { size_t tempu_strlen; const FileExtensionSpecStruct *ext_search = known_ext; if((errcode = unzGetCurrentFileInfo(tz, 0, tempu, 1024, 0, 0, 0, 0)) != UNZ_OK) { throw MDFN_Error(0, _("Could not get file information in ZIP archive: %s"), unzErrorString(errcode)); } tempu[1023] = 0; tempu_strlen = strlen(tempu); while(ext_search->extension && !FileFound) { size_t ttmeow = strlen(ext_search->extension); if(tempu_strlen >= ttmeow) { if(!strcasecmp(tempu + tempu_strlen - ttmeow, ext_search->extension)) FileFound = TRUE; } ext_search++; } if(FileFound) break; if((errcode = unzGoToNextFile(tz)) != UNZ_OK) { if(errcode != UNZ_END_OF_LIST_OF_FILE) { throw MDFN_Error(0, _("Error seeking to next file in ZIP archive: %s"), unzErrorString(errcode)); } if((errcode = unzGoToFirstFile(tz)) != UNZ_OK) { throw MDFN_Error(0, _("Could not seek to first file in ZIP archive: %s"), unzErrorString(errcode)); } break; } } // end to while(!FileFound) } // end to if(ext) if((errcode = unzOpenCurrentFile(tz)) != UNZ_OK) { throw MDFN_Error(0, _("Could not open file in ZIP archive: %s"), unzErrorString(errcode)); } { unz_file_info ufo; unzGetCurrentFileInfo((unzFile)tz, &ufo, 0, 0, 0, 0, 0, 0); if(ufo.uncompressed_size > MaxROMImageSize) throw MDFN_Error(0, _("ROM image is too large; maximum size allowed is %llu bytes."), (unsigned long long)MaxROMImageSize); str.reset(new MemoryStream(ufo.uncompressed_size, true)); unzReadCurrentFile((unzFile)tz, str->map(), str->size()); } // Don't use MDFN_GetFilePathComponents() here. { char* ld = strrchr(tempu, '.'); f_ext = std::string(ld ? ld : ""); f_fbase = std::string(tempu, ld ? (ld - tempu) : strlen(tempu)); } } else // If it's not a zip file, handle it as...another type of file! { std::unique_ptr<Stream> tfp(new FileStream(path, FileStream::MODE_READ)); // We'll clean up f_ext to remove the leading period, and convert to lowercase, after // the plain vs gzip file handling code below(since gzip handling path will want to strip off an extra extension). MDFN_GetFilePathComponents(path, NULL, &f_fbase, &f_ext); uint8 gzmagic[3] = { 0 }; if(tfp->read(gzmagic, 3, false) != 3 || gzmagic[0] != 0x1F || gzmagic[1] != 0x8b || gzmagic[2] != 0x08) { tfp->seek(0, SEEK_SET); if(tfp->size() > MaxROMImageSize) throw MDFN_Error(0, _("ROM image is too large; maximum size allowed is %llu bytes."), (unsigned long long)MaxROMImageSize); str = std::move(tfp); } else /* Probably gzip */ { delete tfp.release(); str.reset(new MemoryStream(new GZFileStream(path, GZFileStream::MODE::READ), MaxROMImageSize)); MDFN_GetFilePathComponents(f_fbase, NULL, &f_fbase, &f_ext); } // End gzip handling } // End normal and gzip file handling else to zip // Remove leading period in file extension. if(f_ext.size() > 0 && f_ext[0] == '.') f_ext = f_ext.substr(1); // Convert file extension A-Z chars to lowercase, a-z for(auto& c : f_ext) if(c >= 'A' && c <= 'Z') c = 'a' + (c - 'A'); //printf("|%s| --- |%s|\n", f_fbase.c_str(), f_ext.c_str()); } catch(...) { if(tz != NULL) { unzCloseCurrentFile(tz); unzClose(tz); } Close(); throw; } if(tz != NULL) { unzCloseCurrentFile(tz); unzClose(tz); } }