// Copyright (c) 2012- PPSSPP Project. // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, version 2.0 or later versions. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License 2.0 for more details. // A copy of the GPL 2.0 should have been included with the program. // If not, see http://www.gnu.org/licenses/ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #pragma once #include #include #include #include #include #include "Common/CommonTypes.h" #include "Core/Loaders.h" // One PS1 disc image (a cue sheet, a CloneCD .ccd, an Alcohol .mds, a CHD, or a bare .bin/.img/.iso): // its tracks, and its sectors as raw 2352-byte ones, however the image stores them. class PS1Disc { public: explicit PS1Disc(const Path &path); ~PS1Disc(); bool IsValid() const { return error_.empty(); } const std::string &Error() const { return error_; } const std::string &DiscID() const { return discID_; } u32 NumBlocks() const { return numBlocks_; } // Its PSISOIMG header, up to the block index (PSAR_HEADER_SIZE bytes). void BuildHeader(const std::string &title, u8 *psisoimg) const; bool ReadRawSectors(u32 lba, u32 count, u8 *out); void Cancel(); private: struct Track { int number; bool audio; u32 start; // Disc LBA of INDEX 01. u32 pregap; // Sectors before it that belong to the track (INDEX 00, or a generated PREGAP). }; // A run of disc sectors, from a file, the CHD (CHD_SOURCE, offset in frames), or (GENERATED) all zeroes. struct Extent { u32 lba; u32 count; int file; s64 offset; int sectorSize; // 2352 raw, 2336 without sync and header, 2048 user data only. bool byteSwapped; // CD audio in a CHD is big-endian. int stride; // Bytes from one sector to the next in a file, more than sectorSize with subchannel data. }; static const int GENERATED = -1; static const int CHD_SOURCE = -2; bool ParseCue(const Path &cuePath, const std::string &text); bool ParseCcd(const Path &ccdPath, const std::string &text); bool OpenBare(const Path &path); bool OpenCHD(const Path &path); bool ParseMds(const Path &mdsPath, const std::string &data); int AddFile(const Path &path); void AddExtent(u32 lba, u32 count, int file, s64 offset, int sectorSize, bool byteSwapped = false, int stride = 0); bool ReadSourceSector(const Extent &e, u32 index, u8 *out); bool ReadUserData(u32 lba, u8 *out); void ReadDiscID(); std::string error_; std::vector> files_; std::vector extents_; std::vector tracks_; u32 numSectors_ = 0; // A CHD, read a hunk (several frames) at a time. struct _chd_file *chd_ = nullptr; std::mutex chdLock_; std::vector hunk_; u32 cachedHunk_ = 0xFFFFFFFF; u32 framesPerHunk_ = 0; std::string discID_; u32 numBlocks_ = 0; }; // One or more PS1 discs presented as a converted PS1 EBOOT.PBP, the kind popstation makes, for the // firmware's POPS to run: one disc image, or an .m3u playlist of up to five, which become a multi-disc // EBOOT. Only the headers are kept in memory. The disc images are stored uncompressed, as stored DEFLATE // blocks, so a read of one goes straight to its files. See docs/POPS.md. class PS1EbootFileLoader : public FileLoader { public: explicit PS1EbootFileLoader(const Path &path); ~PS1EbootFileLoader(); bool IsValid() const { return error_.empty(); } bool Exists() override { return IsValid(); } bool IsDirectory() override { return false; } s64 FileSize() override { return size_; } Path GetPath() const override { return path_; } std::string GetFileExtension() const override { return ".pbp"; } size_t ReadAt(s64 absolutePos, size_t bytes, size_t count, void *data, Flags flags = Flags::NONE) override; using FileLoader::ReadAt; void Cancel() override; std::string LatestError() const override { return error_; } const std::string &DiscID() const { return discs_[0]->DiscID(); } const std::string &Title() const { return title_; } int NumDiscs() const { return (int)discs_.size(); } private: void BuildHeaders(); size_t ReadDisc(int disc, s64 pos, size_t bytes, u8 *out); Path path_; std::string error_; std::string title_; std::vector> discs_; // The PBP up to the PSAR, then (with several discs) the PSTITLEIMG header. Each disc's PSISOIMG // header follows at its offset in the PSAR, then its block index and blocks, made on the fly. std::vector head_; std::vector> discHeaders_; std::vector discOffsets_; u32 psarOffset_ = 0; s64 size_ = 0; }; // The disc images an .m3u playlist lists, as written. std::vector PlaylistFileNames(std::string_view text); namespace File { struct FileInfo; } // Whether a .cue, .ccd or .mds describes a disc, or an .m3u lists disc images, by its contents. bool IsPS1DiscSheet(FileLoader *fileLoader); // Whether a file with this extension can be (part of) a PS1 disc image. bool IsPS1DiscImageExtension(const std::string &ext); // Whether a CHD is of a CD (rather than a DVD, like a PSP disc). bool IsCDChd(FileLoader *fileLoader); // The file names a cue sheet's FILE lines give. std::vector CueSheetFileNames(const Path &cuePath); std::vector CueSheetFileNamesFromText(std::string_view text); // A file in an archive: its path there, and its size. struct ArchiveEntry { std::string name; s64 size; }; // The files of a PS1 disc among an archive's, by their paths in it: a cue sheet and the files it names, // a .ccd with its .img (and .sub), an .mds with its .mdf, or else the largest .bin or .img that's a whole // number of sectors. // readText reads a small file from the archive. bool FindPS1DiscFiles(const std::vector &entries, const std::function &readText, std::vector *discFiles); // The cue sheet next to a disc image whose FILE lines name it, or an empty path. Path FindCueSheetFor(const Path &imagePath); // Removes the disc images from a directory listing that a playlist in it lists, and the .bin and .img // files that a cue sheet or .ccd in it describes, so that each game shows up once, and those that can't be // a raw disc image (a size that isn't a whole number of sectors). void RemoveDescribedDiscImages(std::vector *files);