mirror of https://github.com/bsnes-emu/bsnes.git
118 lines
2.7 KiB
C++
118 lines
2.7 KiB
C++
#pragma once
|
|
|
|
#include <nall/file.hpp>
|
|
#include <nall/filemap.hpp>
|
|
#include <nall/stdint.hpp>
|
|
#include <nall/string.hpp>
|
|
|
|
namespace nall {
|
|
|
|
struct bpsmetadata {
|
|
inline auto load(const string& filename) -> bool;
|
|
inline auto save(const string& filename, const string& metadata) -> bool;
|
|
inline auto metadata() const -> string;
|
|
|
|
protected:
|
|
file sourceFile;
|
|
string metadataString;
|
|
};
|
|
|
|
auto bpsmetadata::load(const string& filename) -> bool {
|
|
if(sourceFile.open(filename, file::mode::read) == false) return false;
|
|
|
|
auto read = [&]() -> uint8_t {
|
|
return sourceFile.read();
|
|
};
|
|
|
|
auto decode = [&]() -> uint64_t {
|
|
uint64_t data = 0, shift = 1;
|
|
while(true) {
|
|
uint8_t x = read();
|
|
data += (x & 0x7f) * shift;
|
|
if(x & 0x80) break;
|
|
shift <<= 7;
|
|
data += shift;
|
|
}
|
|
return data;
|
|
};
|
|
|
|
if(read() != 'B') return false;
|
|
if(read() != 'P') return false;
|
|
if(read() != 'S') return false;
|
|
if(read() != '1') return false;
|
|
decode();
|
|
decode();
|
|
uint metadataSize = decode();
|
|
char data[metadataSize + 1];
|
|
for(uint n = 0; n < metadataSize; n++) data[n] = read();
|
|
data[metadataSize] = 0;
|
|
metadataString = (const char*)data;
|
|
|
|
return true;
|
|
}
|
|
|
|
auto bpsmetadata::save(const string& filename, const string& metadata) -> bool {
|
|
file targetFile;
|
|
if(targetFile.open(filename, file::mode::write) == false) return false;
|
|
if(sourceFile.open() == false) return false;
|
|
sourceFile.seek(0);
|
|
|
|
auto read = [&]() -> uint8_t {
|
|
return sourceFile.read();
|
|
};
|
|
|
|
auto decode = [&]() -> uint64_t {
|
|
uint64_t data = 0, shift = 1;
|
|
while(true) {
|
|
uint8_t x = read();
|
|
data += (x & 0x7f) * shift;
|
|
if(x & 0x80) break;
|
|
shift <<= 7;
|
|
data += shift;
|
|
}
|
|
return data;
|
|
};
|
|
|
|
Hash::CRC32 checksum;
|
|
|
|
auto write = [&](uint8_t data) {
|
|
targetFile.write(data);
|
|
checksum.input(data);
|
|
};
|
|
|
|
auto encode = [&](uint64_t data) {
|
|
while(true) {
|
|
uint64_t x = data & 0x7f;
|
|
data >>= 7;
|
|
if(data == 0) {
|
|
write(0x80 | x);
|
|
break;
|
|
}
|
|
write(x);
|
|
data--;
|
|
}
|
|
};
|
|
|
|
for(uint n = 0; n < 4; n++) write(read());
|
|
encode(decode());
|
|
encode(decode());
|
|
uint sourceLength = decode();
|
|
uint targetLength = metadata.length();
|
|
encode(targetLength);
|
|
sourceFile.seek(sourceLength, file::index::relative);
|
|
for(uint n = 0; n < targetLength; n++) write(metadata[n]);
|
|
uint length = sourceFile.size() - sourceFile.offset() - 4;
|
|
for(uint n = 0; n < length; n++) write(read());
|
|
uint32_t outputChecksum = checksum.digest().hex();
|
|
for(uint n = 0; n < 32; n += 8) write(outputChecksum >> n);
|
|
|
|
targetFile.close();
|
|
return true;
|
|
}
|
|
|
|
auto bpsmetadata::metadata() const -> string {
|
|
return metadataString;
|
|
}
|
|
|
|
}
|