172 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			172 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #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;
 | |
| };
 | |
| 
 | |
| }
 |