static void ReadM3U(std::vector<std::string> &file_list, std::string path, unsigned depth = 0) { std::vector<std::string> ret; FileWrapper m3u_file(path.c_str(), FileWrapper::MODE_READ, _("M3U CD Set")); std::string dir_path; char linebuf[2048]; MDFN_GetFilePathComponents(path, &dir_path); while(m3u_file.get_line(linebuf, sizeof(linebuf))) { std::string efp; if(linebuf[0] == '#') continue; MDFN_rtrim(linebuf); if(linebuf[0] == 0) continue; efp = MDFN_EvalFIP(dir_path, std::string(linebuf)); if(efp.size() >= 4 && efp.substr(efp.size() - 4) == ".m3u") { if(efp == path) throw(MDFN_Error(0, _("M3U at \"%s\" references self."), efp.c_str())); if(depth == 99) throw(MDFN_Error(0, _("M3U load recursion too deep!"))); ReadM3U(file_list, efp, depth++); } else file_list.push_back(efp); } }
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); } }
void CDAccess_CCD::Load(const char *path, bool image_memcache) { FileStream cf(path, FileStream::MODE_READ); std::map<std::string, CCD_Section> Sections; std::string linebuf; std::string cur_section_name; std::string dir_path, file_base, file_ext; char img_extsd[4] = { 'i', 'm', 'g', 0 }; char sub_extsd[4] = { 's', 'u', 'b', 0 }; MDFN_GetFilePathComponents(path, &dir_path, &file_base, &file_ext); if(file_ext.length() == 4 && file_ext[0] == '.') { signed char extupt[3] = { -1, -1, -1 }; for(int i = 1; i < 4; i++) { if(file_ext[i] >= 'A' && file_ext[i] <= 'Z') extupt[i - 1] = 'A' - 'a'; else if(file_ext[i] >= 'a' && file_ext[i] <= 'z') extupt[i - 1] = 0; } signed char av = -1; for(int i = 0; i < 3; i++) { if(extupt[i] != -1) av = extupt[i]; else extupt[i] = av; } if(av == -1) av = 0; for(int i = 0; i < 3; i++) { if(extupt[i] == -1) extupt[i] = av; } for(int i = 0; i < 3; i++) { img_extsd[i] += extupt[i]; sub_extsd[i] += extupt[i]; } } //printf("%s %d %d %d\n", file_ext.c_str(), extupt[0], extupt[1], extupt[2]); linebuf.reserve(256); while(cf.get_line(linebuf) >= 0) { MDFN_trim(linebuf); if(linebuf.length() == 0) // Skip blank lines. continue; if(linebuf[0] == '[') { if(linebuf.length() < 3 || linebuf[linebuf.length() - 1] != ']') throw MDFN_Error(0, _("Malformed section specifier: %s"), linebuf.c_str()); cur_section_name = linebuf.substr(1, linebuf.length() - 2); MDFN_strtoupper(cur_section_name); } else { const size_t feqpos = linebuf.find('='); const size_t leqpos = linebuf.rfind('='); std::string k, v; if(feqpos == std::string::npos || feqpos != leqpos) throw MDFN_Error(0, _("Malformed value pair specifier: %s"), linebuf.c_str()); k = linebuf.substr(0, feqpos); v = linebuf.substr(feqpos + 1); MDFN_trim(k); MDFN_trim(v); MDFN_strtoupper(k); Sections[cur_section_name][k] = v; } } { CCD_Section& ds = Sections["DISC"]; unsigned toc_entries = CCD_ReadInt<unsigned>(ds, "TOCENTRIES"); unsigned num_sessions = CCD_ReadInt<unsigned>(ds, "SESSIONS"); bool data_tracks_scrambled = CCD_ReadInt<unsigned>(ds, "DATATRACKSSCRAMBLED"); if(num_sessions != 1) throw MDFN_Error(0, _("Unsupported number of sessions: %u"), num_sessions); if(data_tracks_scrambled) throw MDFN_Error(0, _("Scrambled CCD data tracks currently not supported.")); //printf("MOO: %d\n", toc_entries); for(unsigned te = 0; te < toc_entries; te++) { char tmpbuf[64]; snprintf(tmpbuf, sizeof(tmpbuf), "ENTRY %u", te); CCD_Section& ts = Sections[std::string(tmpbuf)]; unsigned session = CCD_ReadInt<unsigned>(ts, "SESSION"); uint8 point = CCD_ReadInt<uint8>(ts, "POINT"); uint8 adr = CCD_ReadInt<uint8>(ts, "ADR"); uint8 control = CCD_ReadInt<uint8>(ts, "CONTROL"); uint8 pmin = CCD_ReadInt<uint8>(ts, "PMIN"); uint8 psec = CCD_ReadInt<uint8>(ts, "PSEC"); uint8 pframe = CCD_ReadInt<uint8>(ts, "PFRAME"); signed plba = CCD_ReadInt<signed>(ts, "PLBA"); if(session != 1) throw MDFN_Error(0, "Unsupported TOC entry Session value: %u", session); // Reference: ECMA-394, page 5-14 switch(point) { default: throw MDFN_Error(0, "Unsupported TOC entry Point value: %u", point); break; case 0xA0: tocd.first_track = pmin; tocd.disc_type = psec; break; case 0xA1: tocd.last_track = pmin; break; case 0xA2: tocd.tracks[100].adr = adr; tocd.tracks[100].control = control; tocd.tracks[100].lba = plba; break; case 99: case 98: case 97: case 96: case 95: case 94: case 93: case 92: case 91: case 90: case 89: case 88: case 87: case 86: case 85: case 84: case 83: case 82: case 81: case 80: case 79: case 78: case 77: case 76: case 75: case 74: case 73: case 72: case 71: case 70: case 69: case 68: case 67: case 66: case 65: case 64: case 63: case 62: case 61: case 60: case 59: case 58: case 57: case 56: case 55: case 54: case 53: case 52: case 51: case 50: case 49: case 48: case 47: case 46: case 45: case 44: case 43: case 42: case 41: case 40: case 39: case 38: case 37: case 36: case 35: case 34: case 33: case 32: case 31: case 30: case 29: case 28: case 27: case 26: case 25: case 24: case 23: case 22: case 21: case 20: case 19: case 18: case 17: case 16: case 15: case 14: case 13: case 12: case 11: case 10: case 9: case 8: case 7: case 6: case 5: case 4: case 3: case 2: case 1: tocd.tracks[point].adr = adr; tocd.tracks[point].control = control; tocd.tracks[point].lba = plba; break; } } } // Convenience leadout track duplication. if(tocd.last_track < 99) tocd.tracks[tocd.last_track + 1] = tocd.tracks[100]; // // Open image stream. { std::string image_path = MDFN_EvalFIP(dir_path, file_base + std::string(".") + std::string(img_extsd), true); if(image_memcache) { img_stream = new MemoryStream(new FileStream(image_path.c_str(), FileStream::MODE_READ)); } else { img_stream = new FileStream(image_path.c_str(), FileStream::MODE_READ); } int64 ss = img_stream->size(); if(ss % 2352) throw MDFN_Error(0, _("CCD image size is not evenly divisible by 2352.")); img_numsectors = ss / 2352; } // // Open subchannel stream { std::string sub_path = MDFN_EvalFIP(dir_path, file_base + std::string(".") + std::string(sub_extsd), true); if(image_memcache) sub_stream = new MemoryStream(new FileStream(sub_path.c_str(), FileStream::MODE_READ)); else sub_stream = new FileStream(sub_path.c_str(), FileStream::MODE_READ); if(sub_stream->size() != (int64)img_numsectors * 96) throw MDFN_Error(0, _("CCD SUB file size mismatch.")); } CheckSubQSanity(); }