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);
    }
}
Beispiel #2
0
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();
}