working decompression and extraction
This commit is contained in:
parent
582b2a1933
commit
35cabf05da
|
@ -0,0 +1,50 @@
|
|||
struct BoltHdr {
|
||||
char magic[6]; // BOLT\r\n
|
||||
|
||||
// have no idea what these are yet
|
||||
u8 unk2;
|
||||
u8 unk3;
|
||||
|
||||
// or these, they don't seem to be
|
||||
// directly referenced by bolt stuff
|
||||
u8 unk5;
|
||||
u8 unk6;
|
||||
u8 unk7;
|
||||
|
||||
u8 groupCount;
|
||||
|
||||
// in bytes
|
||||
u32 libSize;
|
||||
};
|
||||
|
||||
struct BoltGroupEnt {
|
||||
u32 unk;
|
||||
u32 fileSize;
|
||||
u32 fileOffset;
|
||||
u32 unk3;
|
||||
|
||||
u8 fileData[4] @ fileOffset;
|
||||
};
|
||||
|
||||
struct BoltGroupDesc {
|
||||
// flags?
|
||||
u8 unk;
|
||||
u8 unk2;
|
||||
u8 unk3;
|
||||
u8 groupEntCount;
|
||||
|
||||
// in bytes
|
||||
u32 groupSize;
|
||||
u32 groupOffset;
|
||||
|
||||
// ptr padding for ps2 code
|
||||
u32 resolvedptr;
|
||||
|
||||
if(groupEntCount == 0)
|
||||
BoltGroupEnt groupEntries[0x100] @ groupOffset;
|
||||
else
|
||||
BoltGroupEnt groupEntries[groupEntCount] @ groupOffset;
|
||||
};
|
||||
|
||||
BoltHdr hdr @0;
|
||||
BoltGroupDesc groupDescs[hdr.groupCount] @ $;
|
111
src/main.cpp
111
src/main.cpp
|
@ -5,48 +5,51 @@
|
|||
#include <structs/BoltStructs.hpp>
|
||||
#include <vector>
|
||||
|
||||
std::vector<u8> BoltDecompress(std::span<u8> data) {
|
||||
u8* inptr = data.data();
|
||||
#include <fstream>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
std::vector<u8> BoltDecompress(u8* input, usize decompressedSize) {
|
||||
u8* inptr = input;
|
||||
std::vector<u8> res;
|
||||
|
||||
i32 iVar3;
|
||||
i32 iVar6;
|
||||
u32 uVar5;
|
||||
u32 pbVar4; // outrun
|
||||
res.resize(decompressedSize);
|
||||
|
||||
for(u32 i = 0; i < data.size(); ++i) {
|
||||
auto uVar7 = inptr[i];
|
||||
u8* pOut = res.data();
|
||||
u8* pEnd = res.data() + decompressedSize;
|
||||
|
||||
if(uVar7 < 128) {
|
||||
i32 iVar3 = 0;
|
||||
i32 iVar6 = 0;
|
||||
u32 uVar5 = 0;
|
||||
u8* pbVar4 = nullptr; // outrun
|
||||
bool bVar1;
|
||||
|
||||
while(pOut < pEnd) {
|
||||
auto uVar7 = *inptr++;
|
||||
|
||||
if(uVar7 < 128) { // lookback/run?
|
||||
iVar3 = iVar3 + uVar5 * 8 + ((int)(uVar7 & 0x70) >> 4);
|
||||
pbVar4 = -(iVar6 * 0x10 + (uVar7 & 0xf) + 1);
|
||||
pbVar4 = pOut + -(iVar6 * 0x10 + (uVar7 & 0xf) + 1);
|
||||
iVar6 = iVar3 + 1;
|
||||
|
||||
|
||||
|
||||
if(iVar3 != -2) {
|
||||
do {
|
||||
//*pOut = *pbVar4;
|
||||
*pOut = *pbVar4;
|
||||
pbVar4 = pbVar4 + 1;
|
||||
//bVar1 = iVar6 != 0;
|
||||
// pOut = pOut + 1;
|
||||
bVar1 = iVar6 != 0;
|
||||
pOut = pOut + 1;
|
||||
iVar6 = iVar6 + -1;
|
||||
} while(iVar6 != 0);
|
||||
} while(bVar1);
|
||||
}
|
||||
iVar6 = 0;
|
||||
iVar3 = 0;
|
||||
uVar5 = 0;
|
||||
} else if(uVar7 < 144) {
|
||||
} else if(uVar7 < 144) { // literal copy from stream
|
||||
iVar3 = uVar5 * 0x10 + (uVar7 & 0xf) + 1;
|
||||
while(iVar3 != 0) {
|
||||
iVar3 = iVar3 + -1;
|
||||
//*pOut = *pbRam00590aa8;
|
||||
// pOut = pOut + 1;
|
||||
// pbRam00590aa8 = pbRam00590aa8 + 1;
|
||||
// iRam00590ab0 = iRam00590ab0 + -1;
|
||||
// if(iRam00590ab0 == 0) {
|
||||
// NextBlock();
|
||||
//}
|
||||
*pOut = *inptr++;
|
||||
pOut = pOut + 1;
|
||||
}
|
||||
iVar3 = 0;
|
||||
uVar5 = 0;
|
||||
|
@ -72,12 +75,26 @@ struct BoltReader {
|
|||
u16 index;
|
||||
u16 gid;
|
||||
|
||||
std::span<u8> uncompressedData;
|
||||
bool compressed;
|
||||
|
||||
u8* uncompressedData { nullptr };
|
||||
usize uncompressedSize;
|
||||
|
||||
fs::path pathify() {
|
||||
// Create a mutable copy of the filename
|
||||
std::string s = { filename.data(), filename.size() };
|
||||
|
||||
for(auto& c : s)
|
||||
if(c == '\\')
|
||||
c = '/';
|
||||
|
||||
return fs::current_path() / "ASSETS" / fs::path(s);
|
||||
}
|
||||
};
|
||||
|
||||
BoltReader() {}
|
||||
|
||||
ErrorOr<void> OpenBolt(const lightningbolt::fs::path& path) {
|
||||
ErrorOr<void> OpenBolt(const fs::path& path) {
|
||||
auto p = path;
|
||||
p.replace_filename("SLUS_201.14");
|
||||
|
||||
|
@ -110,7 +127,6 @@ struct BoltReader {
|
|||
if(te.filename == "")
|
||||
break;
|
||||
|
||||
// std::cout << std::format("te: {} {:04x} {:04x}\n", te.filename, te.index, te.gid);
|
||||
entryTable.emplace_back(te);
|
||||
|
||||
table++;
|
||||
|
@ -122,13 +138,16 @@ struct BoltReader {
|
|||
template <class F>
|
||||
void ForEachFile(F f) {
|
||||
for(auto& file : entryTable) {
|
||||
if(file.uncompressedData.empty()) {
|
||||
if(file.uncompressedData == nullptr) {
|
||||
auto gid = (file.gid >> 8);
|
||||
auto entries = lib->GroupDescriptors()[gid].Entries(boltFile.GetMapping());
|
||||
auto size = entries[file.index & 0x00ff].fileSize;
|
||||
auto offset = entries[file.index & 0x00ff].fileOffset;
|
||||
|
||||
file.uncompressedData = { std::bit_cast<u8*>(boltFile.GetMapping() + offset), size };
|
||||
file.compressed = !(entries[file.index & 0x00ff].unk & 0x8);
|
||||
|
||||
file.uncompressedData = std::bit_cast<u8*>(boltFile.GetMapping() + offset);
|
||||
file.uncompressedSize = size;
|
||||
}
|
||||
|
||||
if(!f(file))
|
||||
|
@ -146,13 +165,41 @@ struct BoltReader {
|
|||
|
||||
int main() {
|
||||
BoltReader reader;
|
||||
if(auto error = reader.OpenBolt(lightningbolt::fs::current_path() / "ASSETS.BLT"); error.HasError()) {
|
||||
if(auto error = reader.OpenBolt(fs::current_path() / "ASSETS.BLT"); error.HasError()) {
|
||||
std::cout << "Error opening Bolt file: " << error.Error();
|
||||
}
|
||||
|
||||
reader.ForEachFile([](BoltReader::ParsedTableEntry& ent) {
|
||||
std::cout << std::format("File: {} magic: ", ent.filename) << ent.uncompressedData[0] << ent.uncompressedData[1] << ent.uncompressedData[2]
|
||||
<< ent.uncompressedData[3] << '\n';
|
||||
std::cout << std::format("File: {}", ent.filename);
|
||||
|
||||
auto p = ent.pathify();
|
||||
|
||||
auto pathonly = p;
|
||||
pathonly.remove_filename();
|
||||
|
||||
if(!fs::exists(pathonly))
|
||||
fs::create_directories(pathonly);
|
||||
|
||||
std::ofstream ofs(p.string(), std::ofstream::binary);
|
||||
|
||||
if(!ofs) {
|
||||
std::cout << "... : Could not open " << p.string() << " for writing\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(ent.compressed) {
|
||||
std::cout << std::format(", compressed ({} bytes uncompressed)", ent.uncompressedSize);
|
||||
|
||||
auto decompressed = BoltDecompress(ent.uncompressedData, ent.uncompressedSize);
|
||||
|
||||
ofs.write((char*)decompressed.data(), ent.uncompressedSize);
|
||||
std::cout << std::format(", written to \"{}\"\n", p.string());
|
||||
} else {
|
||||
std::cout << std::format(", uncompressed ({} bytes)", ent.uncompressedSize);
|
||||
|
||||
ofs.write((char*)ent.uncompressedData, ent.uncompressedSize);
|
||||
std::cout << std::format(", written to \"{}\"\n", p.string());
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in New Issue