aboutsummaryrefslogtreecommitdiff
path: root/launcher/mojang/PackageManifest.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'launcher/mojang/PackageManifest.cpp')
-rw-r--r--launcher/mojang/PackageManifest.cpp427
1 files changed, 0 insertions, 427 deletions
diff --git a/launcher/mojang/PackageManifest.cpp b/launcher/mojang/PackageManifest.cpp
deleted file mode 100644
index b3dfd7fc..00000000
--- a/launcher/mojang/PackageManifest.cpp
+++ /dev/null
@@ -1,427 +0,0 @@
-#include "PackageManifest.h"
-#include <Json.h>
-#include <QDir>
-#include <QDirIterator>
-#include <QCryptographicHash>
-#include <QDebug>
-
-#ifndef Q_OS_WIN32
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#endif
-
-namespace mojang_files {
-
-const Hash hash_of_empty_string = "da39a3ee5e6b4b0d3255bfef95601890afd80709";
-
-int Path::compare(const Path& rhs) const
-{
- auto left_cursor = begin();
- auto left_end = end();
- auto right_cursor = rhs.begin();
- auto right_end = rhs.end();
-
- while (left_cursor != left_end && right_cursor != right_end)
- {
- if(*left_cursor < *right_cursor)
- {
- return -1;
- }
- else if(*left_cursor > *right_cursor)
- {
- return 1;
- }
- left_cursor++;
- right_cursor++;
- }
-
- if(left_cursor == left_end)
- {
- if(right_cursor == right_end)
- {
- return 0;
- }
- return -1;
- }
- return 1;
-}
-
-void Package::addFile(const Path& path, const File& file) {
- addFolder(path.parent_path());
- files[path] = file;
-}
-
-void Package::addFolder(Path folder) {
- if(!folder.has_parent_path()) {
- return;
- }
- do {
- folders.insert(folder);
- folder = folder.parent_path();
- } while(folder.has_parent_path());
-}
-
-void Package::addLink(const Path& path, const Path& target) {
- addFolder(path.parent_path());
- symlinks[path] = target;
-}
-
-void Package::addSource(const FileSource& source) {
- sources[source.hash] = source;
-}
-
-
-namespace {
-void fromJson(QJsonDocument & doc, Package & out) {
- std::set<Path> seen_paths;
- if (!doc.isObject())
- {
- throw JSONValidationError("file manifest is not an object");
- }
- QJsonObject root = doc.object();
-
- auto filesObj = Json::ensureObject(root, "files");
- auto iter = filesObj.begin();
- while (iter != filesObj.end())
- {
- Path objectPath = Path(iter.key());
- auto value = iter.value();
- iter++;
- if(seen_paths.count(objectPath)) {
- throw JSONValidationError("duplicate path inside manifest, the manifest is invalid");
- }
- if (!value.isObject())
- {
- throw JSONValidationError("file entry inside manifest is not an an object");
- }
- seen_paths.insert(objectPath);
-
- auto fileObject = value.toObject();
- auto type = Json::requireString(fileObject, "type");
- if(type == "directory") {
- out.addFolder(objectPath);
- continue;
- }
- else if(type == "file") {
- FileSource bestSource;
- File file;
- file.executable = Json::ensureBoolean(fileObject, QString("executable"), false);
- auto downloads = Json::requireObject(fileObject, "downloads");
- for(auto iter2 = downloads.begin(); iter2 != downloads.end(); iter2++) {
- FileSource source;
-
- auto downloadObject = Json::requireObject(iter2.value());
- source.hash = Json::requireString(downloadObject, "sha1");
- source.size = Json::requireInteger(downloadObject, "size");
- source.url = Json::requireString(downloadObject, "url");
-
- auto compression = iter2.key();
- if(compression == "raw") {
- file.hash = source.hash;
- file.size = source.size;
- source.compression = Compression::Raw;
- }
- else if (compression == "lzma") {
- source.compression = Compression::Lzma;
- }
- else {
- continue;
- }
- bestSource.upgrade(source);
- }
- if(bestSource.isBad()) {
- throw JSONValidationError("No valid compression method for file " + iter.key());
- }
- out.addFile(objectPath, file);
- out.addSource(bestSource);
- }
- else if(type == "link") {
- auto target = Json::requireString(fileObject, "target");
- out.symlinks[objectPath] = target;
- out.addLink(objectPath, target);
- }
- else {
- throw JSONValidationError("Invalid item type in manifest: " + type);
- }
- }
- // make sure the containing folder exists
- out.folders.insert(Path());
-}
-}
-
-Package Package::fromManifestContents(const QByteArray& contents)
-{
- Package out;
- try
- {
- auto doc = Json::requireDocument(contents, "Manifest");
- fromJson(doc, out);
- return out;
- }
- catch (const Exception &e)
- {
- qDebug() << QString("Unable to parse manifest: %1").arg(e.cause());
- out.valid = false;
- return out;
- }
-}
-
-Package Package::fromManifestFile(const QString & filename) {
- Package out;
- try
- {
- auto doc = Json::requireDocument(filename, filename);
- fromJson(doc, out);
- return out;
- }
- catch (const Exception &e)
- {
- qDebug() << QString("Unable to parse manifest file %1: %2").arg(filename, e.cause());
- out.valid = false;
- return out;
- }
-}
-
-#ifndef Q_OS_WIN32
-
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-
-namespace {
-// FIXME: Qt obscures symlink targets by making them absolute. that is useless. this is the workaround - we do it ourselves
-bool actually_read_symlink_target(const QString & filepath, Path & out)
-{
- struct ::stat st;
- // FIXME: here, we assume the native filesystem encoding. May the Gods have mercy upon our Souls.
- QByteArray nativePath = filepath.toUtf8();
- const char * filepath_cstr = nativePath.data();
-
- if (lstat(filepath_cstr, &st) != 0)
- {
- return false;
- }
-
- auto size = st.st_size ? st.st_size + 1 : PATH_MAX;
- std::string temp(size, '\0');
- // because we don't realiably know how long the damn thing actually is, we loop and expand. POSIX is naff
- do
- {
- auto link_length = ::readlink(filepath_cstr, &temp[0], temp.size());
- if(link_length == -1)
- {
- return false;
- }
- if(std::string::size_type(link_length) < temp.size())
- {
- // buffer was long enough and we managed to read the link target. RETURN here.
- temp.resize(link_length);
- out = Path(QString::fromUtf8(temp.c_str()));
- return true;
- }
- temp.resize(temp.size() * 2);
- } while (true);
-}
-}
-#endif
-
-// FIXME: Qt filesystem abstraction is bad, but ... let's hope it doesn't break too much?
-// FIXME: The error handling is just DEFICIENT
-Package Package::fromInspectedFolder(const QString& folderPath)
-{
- QDir root(folderPath);
-
- Package out;
- QDirIterator iterator(folderPath, QDir::NoDotAndDotDot | QDir::AllEntries | QDir::System | QDir::Hidden, QDirIterator::Subdirectories);
- while(iterator.hasNext()) {
- iterator.next();
-
- auto fileInfo = iterator.fileInfo();
- auto relPath = root.relativeFilePath(fileInfo.filePath());
- // FIXME: this is probably completely busted on Windows anyway, so just disable it.
- // Qt makes shit up and doesn't understand the platform details
- // TODO: Actually use a filesystem library that isn't terrible and has decen license.
- // I only know one, and I wrote it. Sadly, currently proprietary. PAIN.
-#ifndef Q_OS_WIN32
- if(fileInfo.isSymLink()) {
- Path targetPath;
- if(!actually_read_symlink_target(fileInfo.filePath(), targetPath)) {
- qCritical() << "Folder inspection: Unknown filesystem object:" << fileInfo.absoluteFilePath();
- out.valid = false;
- }
- out.addLink(relPath, targetPath);
- }
- else
-#endif
- if(fileInfo.isDir()) {
- out.addFolder(relPath);
- }
- else if(fileInfo.isFile()) {
- File f;
- f.executable = fileInfo.isExecutable();
- f.size = fileInfo.size();
- // FIXME: async / optimize the hashing
- QFile input(fileInfo.absoluteFilePath());
- if(!input.open(QIODevice::ReadOnly)) {
- qCritical() << "Folder inspection: Failed to open file:" << fileInfo.absoluteFilePath();
- out.valid = false;
- break;
- }
- f.hash = QCryptographicHash::hash(input.readAll(), QCryptographicHash::Sha1).toHex().constData();
- out.addFile(relPath, f);
- }
- else {
- // Something else... oh my
- qCritical() << "Folder inspection: Unknown filesystem object:" << fileInfo.absoluteFilePath();
- out.valid = false;
- break;
- }
- }
- out.folders.insert(Path("."));
- out.valid = true;
- return out;
-}
-
-namespace {
-struct shallow_first_sort
-{
- bool operator()(const Path &lhs, const Path &rhs) const
- {
- auto lhs_depth = lhs.length();
- auto rhs_depth = rhs.length();
- if(lhs_depth < rhs_depth)
- {
- return true;
- }
- else if(lhs_depth == rhs_depth)
- {
- if(lhs < rhs)
- {
- return true;
- }
- }
- return false;
- }
-};
-
-struct deep_first_sort
-{
- bool operator()(const Path &lhs, const Path &rhs) const
- {
- auto lhs_depth = lhs.length();
- auto rhs_depth = rhs.length();
- if(lhs_depth > rhs_depth)
- {
- return true;
- }
- else if(lhs_depth == rhs_depth)
- {
- if(lhs < rhs)
- {
- return true;
- }
- }
- return false;
- }
-};
-}
-
-UpdateOperations UpdateOperations::resolve(const Package& from, const Package& to)
-{
- UpdateOperations out;
-
- if(!from.valid || !to.valid) {
- out.valid = false;
- return out;
- }
-
- // Files
- for(auto iter = from.files.begin(); iter != from.files.end(); iter++) {
- const auto &current_hash = iter->second.hash;
- const auto &current_executable = iter->second.executable;
- const auto &path = iter->first;
-
- auto iter2 = to.files.find(path);
- if(iter2 == to.files.end()) {
- // removed
- out.deletes.push_back(path);
- continue;
- }
- auto new_hash = iter2->second.hash;
- auto new_executable = iter2->second.executable;
- if (current_hash != new_hash) {
- out.deletes.push_back(path);
- out.downloads.emplace(
- std::pair<Path, FileDownload>{
- path,
- FileDownload(to.sources.at(iter2->second.hash), iter2->second.executable)
- }
- );
- }
- else if (current_executable != new_executable) {
- out.executable_fixes[path] = new_executable;
- }
- }
- for(auto iter = to.files.begin(); iter != to.files.end(); iter++) {
- auto path = iter->first;
- if(!from.files.count(path)) {
- out.downloads.emplace(
- std::pair<Path, FileDownload>{
- path,
- FileDownload(to.sources.at(iter->second.hash), iter->second.executable)
- }
- );
- }
- }
-
- // Folders
- std::set<Path, deep_first_sort> remove_folders;
- std::set<Path, shallow_first_sort> make_folders;
- for(auto from_path: from.folders) {
- auto iter = to.folders.find(from_path);
- if(iter == to.folders.end()) {
- remove_folders.insert(from_path);
- }
- }
- for(auto & rmdir: remove_folders) {
- out.rmdirs.push_back(rmdir);
- }
- for(auto to_path: to.folders) {
- auto iter = from.folders.find(to_path);
- if(iter == from.folders.end()) {
- make_folders.insert(to_path);
- }
- }
- for(auto & mkdir: make_folders) {
- out.mkdirs.push_back(mkdir);
- }
-
- // Symlinks
- for(auto iter = from.symlinks.begin(); iter != from.symlinks.end(); iter++) {
- const auto &current_target = iter->second;
- const auto &path = iter->first;
-
- auto iter2 = to.symlinks.find(path);
- if(iter2 == to.symlinks.end()) {
- // removed
- out.deletes.push_back(path);
- continue;
- }
- const auto &new_target = iter2->second;
- if (current_target != new_target) {
- out.deletes.push_back(path);
- out.mklinks[path] = iter2->second;
- }
- }
- for(auto iter = to.symlinks.begin(); iter != to.symlinks.end(); iter++) {
- auto path = iter->first;
- if(!from.symlinks.count(path)) {
- out.mklinks[path] = iter->second;
- }
- }
- out.valid = true;
- return out;
-}
-
-}