Files
ppsspp/Core/FileLoaders/PS1EbootFileLoader.h
T
Henrik RydgårdandClaude Opus 5.5 34a0090a18 Install PS1 discs from zip and 7z archives, and show them as playable only with a firmware that runs them
A zip or 7z with a PS1 disc in it (a cue sheet and the files it names, a
.ccd with its .img and .sub, or a lone raw .bin or .img) is now installed
like a zipped ISO. A disc of several files goes into a folder of its own,
named after the cue sheet or .ccd. An ISO in the archive still takes
priority, and a lone .bin or .img only counts when nothing else does.

The game screen offers Play for a PS1 disc image only when the installed
firmware's POPS can run it: 3.95 to 6.61, with popsman.prx.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-23 15:01:22 +02:00

124 lines
4.4 KiB
C++

// 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 <functional>
#include <memory>
#include <string>
#include <vector>
#include "Common/CommonTypes.h"
#include "Core/Loaders.h"
// A PS1 disc image (a cue sheet, a CloneCD .ccd, or a bare .bin/.img/.iso) presented as a converted
// PS1 EBOOT.PBP, the kind popstation makes, for the firmware's POPS to run. Only the headers are kept
// in memory. The disc image is stored uncompressed, as stored DEFLATE blocks, so a read of it goes
// straight to the image's 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;
void Cancel() override;
std::string LatestError() const override { return error_; }
const std::string &DiscID() const { return discID_; }
const std::string &Title() const { return title_; }
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 or (file < 0) 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 ParseCue(const Path &cuePath, const std::string &text);
bool ParseCcd(const Path &ccdPath, const std::string &text);
bool OpenBare(const Path &path);
int AddFile(const Path &path);
void AddExtent(u32 lba, u32 count, int file, s64 offset, int sectorSize);
bool ReadRawSectors(u32 lba, u32 count, u8 *out);
bool ReadUserData(u32 lba, u8 *out);
void ReadDiscID();
void BuildHeaders();
Path path_;
std::string error_;
std::vector<std::unique_ptr<FileLoader>> files_;
std::vector<Extent> extents_;
std::vector<Track> tracks_;
u32 numSectors_ = 0;
std::string discID_;
std::string title_;
// The PBP up to the PSAR's block index, then the index and the blocks, which are made on the fly.
std::vector<u8> head_;
u32 psarOffset_ = 0;
u32 numBlocks_ = 0;
s64 size_ = 0;
};
namespace File {
struct FileInfo;
}
// Whether a .cue or .ccd describes a disc, by its contents.
bool IsPS1CueOrCcd(FileLoader *fileLoader);
// The file names a cue sheet's FILE lines give.
std::vector<std::string> CueSheetFileNames(const Path &cuePath);
std::vector<std::string> 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), 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<ArchiveEntry> &entries, const std::function<bool(const std::string &name, std::string *text)> &readText, std::vector<std::string> *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 .bin and .img files from a directory listing 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<File::FileInfo> *files);