1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
|
auto Pak::create(string name) -> shared_pointer<Pak> {
auto pak = new Pak;
pak->pak = new vfs::directory;
pak->pak->setAttribute("name", name);
pak->pak->setAttribute("type", "Pak");
return pak;
}
auto Pak::name(string location) const -> string {
return Location::prefix(location);
}
auto Pak::read(string location) -> vector<u8> {
//attempt to match known extensions
auto extensions = this->extensions();
for(auto& extension : extensions) extension.prepend("*.");
auto memory = read(location, extensions);
//failing that, read whatever exists
if(!memory) memory = read(location, {"*"});
return memory;
}
auto Pak::read(string location, vector<string> match) -> vector<u8> {
vector<u8> memory;
vector<u8> patch;
if(file::exists(location)) {
//support BPS patches next to the file
patch = file::read({Location::notsuffix(location), ".bps"});
if(location.iendsWith(".zip")) {
Decode::ZIP archive;
if(archive.open(location)) {
for(auto& file : archive.file) {
for(auto& pattern : match) {
if(file.name.imatch(pattern)) {
memory = archive.extract(file);
break;
}
}
if(memory) break;
}
if(memory) {
//support BPS patches inside the ZIP archive
for(auto& file : archive.file) {
if(file.name.imatch("*.bps")) {
patch = archive.extract(file);
break;
}
}
}
}
} else {
for(auto& pattern : match) {
if(location.imatch(pattern)) {
memory = file::read(location);
break;
}
}
}
}
//attempt to apply BPS patch if one was found
if(patch) {
if(auto output = Beat::Single::apply(memory, patch)) {
memory = move(*output);
}
}
return memory;
}
auto Pak::append(vector<u8>& output, string filename) -> bool {
if(!file::exists(filename)) return false;
auto input = file::read(filename);
auto size = output.size();
output.resize(size + input.size());
memory::copy(output.data() + size, input.data(), input.size());
return true;
}
auto Pak::load(string name, string extension, string location) -> bool {
if(!pak) return false;
if(!location) location = this->location;
if(auto load = pak->write(name)) {
if(auto memory = file::read(saveLocation(location, name, extension))) {
load->write(memory);
load->setAttribute("loaded", true);
return true;
}
}
return false;
}
auto Pak::save(string name, string extension, string location) -> bool {
if(!pak) return false;
if(!location) location = this->location;
if(auto save = pak->read(name)) {
directory::create(Location::dir(saveLocation(location, name, extension)));
if(auto fp = file::open(saveLocation(location, name, extension), file::mode::write)) {
fp.write({save->data(), save->size()});
return true;
}
}
return true;
}
auto Pak::load(Markup::Node node, string extension, string location) -> bool {
string name;
if(auto architecture = node["architecture"].string()) name.append(architecture, ".");
name.append(node["content"].string(), ".");
name.append(node["type"].string());
name.downcase();
auto size = node["size"].natural();
pak->append(name, size);
if(auto fp = pak->write(name)) {
//pak->append() will allocate memory using 0x00 bytes.
//but it's more compatible to initialize RAM to 0xff bytes.
memory::fill<u8>(fp->data(), fp->size(), 0xff);
}
return load(name, extension, location);
}
auto Pak::save(Markup::Node node, string extension, string location) -> bool {
string name;
if(auto architecture = node["architecture"].string()) name.append(architecture, ".");
name.append(node["content"].string(), ".");
name.append(node["type"].string());
name.downcase();
auto size = node["size"].natural();
return save(name, extension, location);
}
auto Pak::saveLocation(string location, string name, string extension) -> string {
string saveLocation;
if(auto path = mia::saveLocation()) {
//if the user has chosen a specific location to save files to ...
saveLocation = {path, this->name(), "/", Location::prefix(location), extension};
} else if(directory::exists(location)) {
//if this is a pak ...
saveLocation = {location, name};
} else if(file::exists(location)) {
//if this is a ROM ...
saveLocation = {Location::notsuffix(location), extension};
} else {
//if no path information is available ...
saveLocation = {mia::homeLocation(), "Saves/", this->name(), ".", extension, "/", name};
}
//try to ensure the directory exists ...
directory::create(Location::path(saveLocation));
return saveLocation;
}
|