mirror of
https://github.com/MultiMC/MultiMC5.git
synced 2024-12-26 18:14:22 +00:00
179 lines
3.8 KiB
C++
179 lines
3.8 KiB
C++
/*
|
|
* Copyright 2020 Petr Mrázek
|
|
*
|
|
* This source is subject to the Microsoft Permissive License (MS-PL).
|
|
* Please see the COPYING.md file for more information.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <QString>
|
|
#include <map>
|
|
#include <set>
|
|
#include <QStringList>
|
|
#include "tasks/Task.h"
|
|
|
|
namespace mojang_files {
|
|
|
|
using Hash = QString;
|
|
extern const Hash empty_hash;
|
|
|
|
// simple-ish path implementation. assumes always relative and does not allow '..' entries
|
|
class Path
|
|
{
|
|
public:
|
|
using parts_type = QStringList;
|
|
|
|
Path() = default;
|
|
Path(QString string) {
|
|
auto parts_in = string.split('/');
|
|
for(auto & part: parts_in) {
|
|
if(part.isEmpty() || part == ".") {
|
|
continue;
|
|
}
|
|
if(part == "..") {
|
|
if(parts.size()) {
|
|
parts.pop_back();
|
|
}
|
|
continue;
|
|
}
|
|
parts.push_back(part);
|
|
}
|
|
}
|
|
|
|
bool has_parent_path() const
|
|
{
|
|
return parts.size() > 0;
|
|
}
|
|
|
|
Path parent_path() const
|
|
{
|
|
if (parts.empty())
|
|
return Path();
|
|
return Path(parts.begin(), std::prev(parts.end()));
|
|
}
|
|
|
|
bool empty() const
|
|
{
|
|
return parts.empty();
|
|
}
|
|
|
|
int length() const
|
|
{
|
|
return parts.length();
|
|
}
|
|
|
|
bool operator==(const Path & rhs) const {
|
|
return parts == rhs.parts;
|
|
}
|
|
|
|
bool operator!=(const Path & rhs) const {
|
|
return parts != rhs.parts;
|
|
}
|
|
|
|
inline bool operator<(const Path& rhs) const
|
|
{
|
|
return compare(rhs) < 0;
|
|
}
|
|
|
|
parts_type::const_iterator begin() const
|
|
{
|
|
return parts.begin();
|
|
}
|
|
|
|
parts_type::const_iterator end() const
|
|
{
|
|
return parts.end();
|
|
}
|
|
|
|
QString toString() const {
|
|
return parts.join("/");
|
|
}
|
|
|
|
private:
|
|
Path(const parts_type::const_iterator & start, const parts_type::const_iterator & end) {
|
|
auto cursor = start;
|
|
while(cursor != end) {
|
|
parts.push_back(*cursor);
|
|
cursor++;
|
|
}
|
|
}
|
|
int compare(const Path& p) const;
|
|
|
|
parts_type parts;
|
|
};
|
|
|
|
|
|
enum class Compression {
|
|
Raw,
|
|
Lzma,
|
|
Unknown
|
|
};
|
|
|
|
|
|
struct FileSource
|
|
{
|
|
Compression compression = Compression::Unknown;
|
|
Hash hash;
|
|
QString url;
|
|
std::size_t size = 0;
|
|
void upgrade(const FileSource & other) {
|
|
if(compression == Compression::Unknown || other.size < size) {
|
|
*this = other;
|
|
}
|
|
}
|
|
bool isBad() const {
|
|
return compression == Compression::Unknown;
|
|
}
|
|
};
|
|
|
|
struct File
|
|
{
|
|
Hash hash;
|
|
bool executable;
|
|
std::uint64_t size = 0;
|
|
};
|
|
|
|
struct Package {
|
|
static Package fromInspectedFolder(const QString &folderPath);
|
|
static Package fromManifestFile(const QString &path);
|
|
static Package fromManifestContents(const QByteArray& contents);
|
|
|
|
explicit operator bool() const
|
|
{
|
|
return valid;
|
|
}
|
|
void addFolder(Path folder);
|
|
void addFile(const Path & path, const File & file);
|
|
void addLink(const Path & path, const Path & target);
|
|
void addSource(const FileSource & source);
|
|
|
|
std::map<Hash, FileSource> sources;
|
|
bool valid = true;
|
|
std::set<Path> folders;
|
|
std::map<Path, File> files;
|
|
std::map<Path, Path> symlinks;
|
|
};
|
|
|
|
struct FileDownload : FileSource
|
|
{
|
|
FileDownload(const FileSource& source, bool executable) {
|
|
static_cast<FileSource &> (*this) = source;
|
|
this->executable = executable;
|
|
}
|
|
bool executable = false;
|
|
};
|
|
|
|
struct UpdateOperations {
|
|
static UpdateOperations resolve(const Package & from, const Package & to);
|
|
bool valid = false;
|
|
std::vector<Path> deletes;
|
|
std::vector<Path> rmdirs;
|
|
std::vector<Path> mkdirs;
|
|
std::map<Path, FileDownload> downloads;
|
|
std::map<Path, Path> mklinks;
|
|
std::map<Path, bool> executable_fixes;
|
|
};
|
|
|
|
}
|