Fixed build with system libzip and miniupnpc

This commit is contained in:
Kevin Reinholz
2025-05-31 16:03:57 -07:00
parent bdb47b3eae
commit 795c8678a6
8 changed files with 551 additions and 5 deletions
+5 -1
View File
@@ -1,4 +1,8 @@
#include <ext/libzip/zip.h>
#ifdef SHARED_LIBZIP
#include <zip.h>
#else
#include "ext/libzip/zip.h"
#endif
#include "Core/FileLoaders/LocalFileLoader.h"
#include "Core/FileLoaders/ZipFileLoader.h"
+152
View File
@@ -0,0 +1,152 @@
#include <ext/libzip/zip.h>
#include "Core/FileLoaders/LocalFileLoader.h"
#include "Core/FileLoaders/ZipFileLoader.h"
ZipFileLoader::ZipFileLoader(FileLoader *sourceLoader)
: ProxiedFileLoader(sourceLoader), zipArchive_(nullptr) {
if (!backend_ || !backend_->Exists() || backend_->IsDirectory()) {
// bad
}
zip_error_t error{};
zip_source_t* zipSource = zip_source_function_create([](void* userdata, void* data, zip_uint64_t len, zip_source_cmd_t cmd) -> zip_int64_t {
ZipFileLoader *loader = (ZipFileLoader *)userdata;
return loader->ZipSourceCallback(data, len, cmd);
}, this, &error);
if (!zipSource) {
ERROR_LOG(Log::IO, "Failed to create ZIP source: %s", zip_error_strerror(&error));
return;
}
zipArchive_ = zip_open_from_source(zipSource, ZIP_RDONLY, &error);
if (!zipArchive_) {
ERROR_LOG(Log::IO, "Failed to open ZIP archive: %s", zip_error_strerror(&error));
zip_source_free(zipSource);
}
}
ZipFileLoader::~ZipFileLoader() {
if (dataFile_) {
zip_fclose(dataFile_);
}
if (zipArchive_) {
zip_discard(zipArchive_);
}
if (data_) {
free(data_);
}
}
bool ZipFileLoader::Initialize(int fileIndex) {
_dbg_assert_(!data_);
struct zip_stat zstat;
int retval = zip_stat_index(zipArchive_, fileIndex, ZIP_FL_NOCASE | ZIP_FL_UNCHANGED, &zstat);
if (retval < 0) {
return false;
}
const char *name = zip_get_name(zipArchive_, fileIndex, ZIP_FL_NOCASE | ZIP_FL_UNCHANGED);
fileExtension_ = KeepIncludingLast(name, '.');
_dbg_assert_(zstat.index == fileIndex);
dataFileSize_ = zstat.size;
dataFile_ = zip_fopen_index(zipArchive_, zstat.index, ZIP_FL_UNCHANGED);
data_ = (u8 *)malloc(dataFileSize_);
return data_ != nullptr;
}
size_t ZipFileLoader::ReadAt(s64 absolutePos, size_t bytes, void *data, Flags flags) {
if (!dataFile_ || absolutePos < 0 || absolutePos >= dataFileSize_) {
return 0;
}
if (absolutePos + (s64)bytes > dataFileSize_) {
// TODO: This could go negative..
bytes = dataFileSize_ - absolutePos;
}
// Decompress until the requested point, filling up data_ as we go. TODO: Do on thread.
while (dataReadPos_ < absolutePos + (s64)bytes) {
int remaining = BLOCK_SIZE;
if (dataReadPos_ + remaining > dataFileSize_) {
remaining = (int)(dataFileSize_ - dataReadPos_);
}
zip_int64_t retval = zip_fread(dataFile_, data_ + dataReadPos_, remaining);
_dbg_assert_(retval == remaining);
dataReadPos_ += retval;
}
// Perform the read.
memcpy(data, data_ + absolutePos, bytes);
return bytes;
}
zip_int64_t ZipFileLoader::ZipSourceCallback(void *data, zip_uint64_t len, zip_source_cmd_t cmd) {
switch (cmd) {
case ZIP_SOURCE_OPEN:
{
zipReadPos_ = 0;
return 0;
}
case ZIP_SOURCE_READ:
{
size_t readBytes = static_cast<zip_int64_t>(backend_->ReadAt(zipReadPos_, len, data));
zipReadPos_ += readBytes;
return readBytes;
}
case ZIP_SOURCE_SEEK:
{
struct SeekData {
zip_int64_t offset;
int whence;
};
if (len < sizeof(SeekData)) {
return -1; // Invalid argument size
}
const SeekData *seekData = static_cast<const SeekData*>(data);
zip_int64_t new_offset;
switch (seekData->whence) {
case SEEK_SET:
new_offset = seekData->offset;
break;
case SEEK_CUR:
new_offset = zipReadPos_ + seekData->offset;
break;
case SEEK_END:
new_offset = backend_->FileSize() + seekData->offset;
break;
default:
return -1; // Invalid 'whence' value
}
if (new_offset < 0 || new_offset > backend_->FileSize()) {
return -1; // Offset out of bounds
}
zipReadPos_ = new_offset;
return 0;
}
case ZIP_SOURCE_TELL:
return zipReadPos_;
case ZIP_SOURCE_CLOSE:
return 0;
case ZIP_SOURCE_STAT:
{
if (len < sizeof(zip_stat_t)) {
return -1;
}
zip_stat_t* st = static_cast<zip_stat_t*>(data);
zip_stat_init(st);
st->valid = ZIP_STAT_SIZE;
st->size = static_cast<zip_uint64_t>(backend_->FileSize());
return sizeof(zip_stat_t);
}
case ZIP_SOURCE_ERROR:
return -1;
case ZIP_SOURCE_FREE:
return 0;
case ZIP_SOURCE_SUPPORTS:
return zip_source_make_command_bitmap(ZIP_SOURCE_READ, ZIP_SOURCE_SEEK, ZIP_SOURCE_TELL, ZIP_SOURCE_OPEN, ZIP_SOURCE_CLOSE, ZIP_SOURCE_STAT);
default:
return -1;
}
}
+5 -1
View File
@@ -2,7 +2,11 @@
#include <mutex>
#include <ext/libzip/zip.h>
#ifdef SHARED_LIBZIP
#include <zip.h>
#else
#include "ext/libzip/zip.h"
#endif
#include "Common/CommonTypes.h"
#include "Common/Log.h"
+65
View File
@@ -0,0 +1,65 @@
#pragma once
#include <mutex>
#include <ext/libzip/zip.h>
#include "Common/CommonTypes.h"
#include "Common/Log.h"
#include "Common/File/Path.h"
#include "Common/StringUtils.h"
#include "Core/Loaders.h"
// Exposes a single (chosen) file from a zip file as another file loader.
// Useful in a bunch of possible chains.
class ZipFileLoader : public ProxiedFileLoader {
public:
ZipFileLoader(FileLoader *sourceLoader);
~ZipFileLoader() override;
zip_t *GetZip() const {
return zipArchive_;
}
bool Initialize(int fileIndex);
bool Exists() override {
return dataFile_ != nullptr;
}
bool IsDirectory() override {
return false;
}
s64 FileSize() override {
return dataFileSize_;
}
Path GetPath() const override {
return backend_->GetPath();
}
size_t ReadAt(s64 absolutePos, size_t bytes, size_t count, void *data, Flags flags = Flags::NONE) override {
return ReadAt(absolutePos, bytes * count, data, flags) / bytes;
}
size_t ReadAt(s64 absolutePos, size_t bytes, void *data, Flags flags = Flags::NONE) override;
std::string GetFileExtension() const override {
return fileExtension_;
}
private:
zip_int64_t ZipSourceCallback(void* data, zip_uint64_t len, zip_source_cmd_t cmd);
enum {
BLOCK_SIZE = 65536,
};
zip_t *zipArchive_ = nullptr;
s64 zipReadPos_ = 0;
zip_file_t *dataFile_ = nullptr;
uint8_t *data_ = nullptr; // malloc/free
s64 dataReadPos_ = 0;
s64 dataFileSize_ = 0;
std::string fileExtension_;
};
+4
View File
@@ -20,7 +20,11 @@
#include <string>
#include <memory>
#ifdef SHARED_LIBZIP
#include <zip.h>
#else
#include "ext/libzip/zip.h"
#endif
#include "Common/CommonTypes.h"
#include "Common/File/Path.h"
+191
View File
@@ -0,0 +1,191 @@
// 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 <string>
#include <memory>
#include "ext/libzip/zip.h"
#include "Common/CommonTypes.h"
#include "Common/File/Path.h"
enum class IdentifiedFileType {
ERROR_IDENTIFYING,
PSP_PBP_DIRECTORY,
PSP_PBP,
PSP_ELF,
PSP_ISO,
PSP_ISO_NP,
PSP_DISC_DIRECTORY,
UNKNOWN_BIN,
UNKNOWN_ELF,
UNKNOWN_ISO,
// Try to reduce support emails...
ARCHIVE_RAR,
ARCHIVE_ZIP,
ARCHIVE_7Z,
PSP_PS1_PBP,
ISO_MODE2,
NORMAL_DIRECTORY,
PSP_SAVEDATA_DIRECTORY,
PPSSPP_SAVESTATE,
PPSSPP_GE_DUMP,
UNKNOWN,
};
// NB: It is a REQUIREMENT that implementations of this class are entirely thread safe!
// TOOD: actually, is it really?
class FileLoader {
public:
enum class Flags {
NONE,
// Not necessary to read from / store into cache.
HINT_UNCACHED,
};
virtual ~FileLoader() {}
virtual bool IsRemote() {
return false;
}
virtual bool Exists() = 0;
virtual bool ExistsFast() {
return Exists();
}
virtual bool IsDirectory() = 0;
virtual s64 FileSize() = 0;
virtual Path GetPath() const = 0;
virtual std::string GetFileExtension() const {
return GetPath().GetFileExtension();
}
virtual size_t ReadAt(s64 absolutePos, size_t bytes, size_t count, void *data, Flags flags = Flags::NONE) = 0;
virtual size_t ReadAt(s64 absolutePos, size_t bytes, void *data, Flags flags = Flags::NONE) {
return ReadAt(absolutePos, 1, bytes, data, flags);
}
// Cancel any operations that might block, if possible.
virtual void Cancel() {}
virtual std::string LatestError() const {
return "";
}
};
class ProxiedFileLoader : public FileLoader {
public:
ProxiedFileLoader(FileLoader *backend) : backend_(backend) {}
~ProxiedFileLoader() {
// Takes ownership.
delete backend_;
}
bool IsRemote() override {
return backend_->IsRemote();
}
bool Exists() override {
return backend_->Exists();
}
bool ExistsFast() override {
return backend_->ExistsFast();
}
bool IsDirectory() override {
return backend_->IsDirectory();
}
s64 FileSize() override {
return backend_->FileSize();
}
Path GetPath() const override {
return backend_->GetPath();
}
void Cancel() override {
backend_->Cancel();
}
std::string LatestError() const override {
return backend_->LatestError();
}
size_t ReadAt(s64 absolutePos, size_t bytes, size_t count, void *data, Flags flags = Flags::NONE) override {
return backend_->ReadAt(absolutePos, bytes, count, data, flags);
}
size_t ReadAt(s64 absolutePos, size_t bytes, void *data, Flags flags = Flags::NONE) override {
return backend_->ReadAt(absolutePos, bytes, data, flags);
}
FileLoader *Steal() {
FileLoader *backend = backend_;
backend_ = nullptr;
return backend;
}
protected:
FileLoader *backend_;
};
inline u32 operator & (const FileLoader::Flags &a, const FileLoader::Flags &b) {
return (u32)a & (u32)b;
}
FileLoader *ConstructFileLoader(const Path &filename);
// Resolve to the target binary, ISO, or other file (e.g. from a directory.)
FileLoader *ResolveFileLoaderTarget(FileLoader *fileLoader);
Path ResolvePBPDirectory(const Path &filename);
Path ResolvePBPFile(const Path &filename);
IdentifiedFileType Identify_File(FileLoader *fileLoader, std::string *errorString);
bool UmdReplace(const Path &filepath, FileLoader **fileLoader, std::string &error);
enum class ZipFileContents {
UNKNOWN,
PSP_GAME_DIR,
ISO_FILE,
TEXTURE_PACK,
SAVE_DATA,
FRAME_DUMP,
};
struct ZipFileInfo {
ZipFileContents contents;
int numFiles;
int stripChars; // for PSP game - how much to strip from the path.
int isoFileIndex; // for ISO
int textureIniIndex; // for textures
bool ignoreMetaFiles;
std::string gameTitle; // from PARAM.SFO if available
std::string savedataTitle;
std::string savedataDetails;
std::string savedataDir;
std::string mTime;
s64 totalFileSize;
std::string contentName;
};
struct zip *ZipOpenPath(const Path &fileName);
void ZipClose(zip *z);
bool DetectZipFileContents(const Path &fileName, ZipFileInfo *info);
void DetectZipFileContents(struct zip *z, ZipFileInfo *info);
+3 -3
View File
@@ -22,9 +22,9 @@
#pragma once
#ifdef USE_SYSTEM_MINIUPNPC
#include <miniupnpc/include/miniwget.h>
#include <miniupnpc/include/miniupnpc.h>
#include <miniupnpc/include/upnpcommands.h>
#include <miniupnpc/miniwget.h>
#include <miniupnpc/miniupnpc.h>
#include <miniupnpc/upnpcommands.h>
#else
#ifndef MINIUPNP_STATICLIB
#define MINIUPNP_STATICLIB
+126
View File
@@ -0,0 +1,126 @@
// Copyright (c) 2013- 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/.
// Most of the code are based on https://github.com/RJ/libportfwd and updated to the latest miniupnp library
// All credit goes to him and the official miniupnp project! http://miniupnp.free.fr/
#pragma once
#ifdef USE_SYSTEM_MINIUPNPC
#include <miniupnpc/include/miniwget.h>
#include <miniupnpc/include/miniupnpc.h>
#include <miniupnpc/include/upnpcommands.h>
#else
#ifndef MINIUPNP_STATICLIB
#define MINIUPNP_STATICLIB
#endif
#include "ext/miniupnp/miniupnpc/include/miniwget.h"
#include "ext/miniupnp/miniupnpc/include/miniupnpc.h"
#include "ext/miniupnp/miniupnpc/include/upnpcommands.h"
#endif
#include <string>
#include <deque>
struct UPnPArgs {
int cmd;
std::string protocol;
unsigned short port;
unsigned short intport;
};
#define IP_PROTOCOL_TCP "TCP"
#define IP_PROTOCOL_UDP "UDP"
#define UPNP_INITSTATE_NONE 0
#define UPNP_INITSTATE_BUSY 1
#define UPNP_INITSTATE_DONE 2
#define UPNP_CMD_ADD 0
#define UPNP_CMD_REMOVE 1
struct UPNPUrls;
struct IGDdatas;
struct PortMap {
bool taken;
std::string protocol;
std::string extPort_str;
std::string intPort_str;
std::string lanip;
std::string remoteHost;
std::string desc;
std::string duration;
std::string enabled;
};
class PortManager {
public:
PortManager();
~PortManager();
// Initialize UPnP
// timeout: milliseconds to wait for a router to respond (default = 2000 ms)
bool Initialize(const unsigned int timeout = 2000);
// Get UPnP Initialization status
int GetInitState();
// Add a port & protocol (TCP, UDP or vendor-defined) to map for forwarding (intport = 0 : same as [external] port)
bool Add(const char* protocol, unsigned short port, unsigned short intport = 0);
// Remove a port mapping (external port)
bool Remove(const char* protocol, unsigned short port);
// Call on exit. Does a full shutdown.
void Shutdown();
private:
// Retrieves port lists mapped by PPSSPP for current LAN IP & other's applications
bool RefreshPortList();
// Removes any lingering mapped ports created by PPSSPP (including from previous crashes)
bool Clear();
// Restore ports mapped by others that were taken by PPSSPP, better used after Clear()
bool Restore();
// Uninitialize/Reset the state
void Terminate();
struct UPNPUrls* urls = nullptr;
struct IGDdatas* datas = nullptr;
int m_InitState = UPNP_INITSTATE_NONE;
int m_LocalPort = UPNP_LOCAL_PORT_ANY;
std::string m_lanip;
std::string m_defaultDesc;
std::string m_leaseDuration = "43200"; // range(0-604800) in seconds (0 = Indefinite/permanent). Some routers doesn't support non-zero value
std::deque<std::pair<std::string, std::string>> m_portList;
std::deque<PortMap> m_otherPortList;
};
extern PortManager g_PortManager;
void __UPnPInit(const int timeout_ms);
void __UPnPShutdown();
// Add a port & protocol (TCP, UDP or vendor-defined) to map for forwarding (intport = 0 : same as [external] port)
void UPnP_Add(const char* protocol, unsigned short port, unsigned short intport = 0);
// Remove a port mapping (external port)
void UPnP_Remove(const char* protocol, unsigned short port);