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 <structs/BoltStructs.hpp>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
std::vector<u8> BoltDecompress(std::span<u8> data) {
|
#include <fstream>
|
||||||
u8* inptr = data.data();
|
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
|
std::vector<u8> BoltDecompress(u8* input, usize decompressedSize) {
|
||||||
|
u8* inptr = input;
|
||||||
std::vector<u8> res;
|
std::vector<u8> res;
|
||||||
|
|
||||||
i32 iVar3;
|
res.resize(decompressedSize);
|
||||||
i32 iVar6;
|
|
||||||
u32 uVar5;
|
|
||||||
u32 pbVar4; // outrun
|
|
||||||
|
|
||||||
for(u32 i = 0; i < data.size(); ++i) {
|
u8* pOut = res.data();
|
||||||
auto uVar7 = inptr[i];
|
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);
|
iVar3 = iVar3 + uVar5 * 8 + ((int)(uVar7 & 0x70) >> 4);
|
||||||
pbVar4 = -(iVar6 * 0x10 + (uVar7 & 0xf) + 1);
|
pbVar4 = pOut + -(iVar6 * 0x10 + (uVar7 & 0xf) + 1);
|
||||||
iVar6 = iVar3 + 1;
|
iVar6 = iVar3 + 1;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if(iVar3 != -2) {
|
if(iVar3 != -2) {
|
||||||
do {
|
do {
|
||||||
//*pOut = *pbVar4;
|
*pOut = *pbVar4;
|
||||||
pbVar4 = pbVar4 + 1;
|
pbVar4 = pbVar4 + 1;
|
||||||
//bVar1 = iVar6 != 0;
|
bVar1 = iVar6 != 0;
|
||||||
// pOut = pOut + 1;
|
pOut = pOut + 1;
|
||||||
iVar6 = iVar6 + -1;
|
iVar6 = iVar6 + -1;
|
||||||
} while(iVar6 != 0);
|
} while(bVar1);
|
||||||
}
|
}
|
||||||
iVar6 = 0;
|
iVar6 = 0;
|
||||||
iVar3 = 0;
|
iVar3 = 0;
|
||||||
uVar5 = 0;
|
uVar5 = 0;
|
||||||
} else if(uVar7 < 144) {
|
} else if(uVar7 < 144) { // literal copy from stream
|
||||||
iVar3 = uVar5 * 0x10 + (uVar7 & 0xf) + 1;
|
iVar3 = uVar5 * 0x10 + (uVar7 & 0xf) + 1;
|
||||||
while(iVar3 != 0) {
|
while(iVar3 != 0) {
|
||||||
iVar3 = iVar3 + -1;
|
iVar3 = iVar3 + -1;
|
||||||
//*pOut = *pbRam00590aa8;
|
*pOut = *inptr++;
|
||||||
// pOut = pOut + 1;
|
pOut = pOut + 1;
|
||||||
// pbRam00590aa8 = pbRam00590aa8 + 1;
|
|
||||||
// iRam00590ab0 = iRam00590ab0 + -1;
|
|
||||||
// if(iRam00590ab0 == 0) {
|
|
||||||
// NextBlock();
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
iVar3 = 0;
|
iVar3 = 0;
|
||||||
uVar5 = 0;
|
uVar5 = 0;
|
||||||
|
@ -72,12 +75,26 @@ struct BoltReader {
|
||||||
u16 index;
|
u16 index;
|
||||||
u16 gid;
|
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() {}
|
BoltReader() {}
|
||||||
|
|
||||||
ErrorOr<void> OpenBolt(const lightningbolt::fs::path& path) {
|
ErrorOr<void> OpenBolt(const fs::path& path) {
|
||||||
auto p = path;
|
auto p = path;
|
||||||
p.replace_filename("SLUS_201.14");
|
p.replace_filename("SLUS_201.14");
|
||||||
|
|
||||||
|
@ -110,7 +127,6 @@ struct BoltReader {
|
||||||
if(te.filename == "")
|
if(te.filename == "")
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// std::cout << std::format("te: {} {:04x} {:04x}\n", te.filename, te.index, te.gid);
|
|
||||||
entryTable.emplace_back(te);
|
entryTable.emplace_back(te);
|
||||||
|
|
||||||
table++;
|
table++;
|
||||||
|
@ -122,13 +138,16 @@ struct BoltReader {
|
||||||
template <class F>
|
template <class F>
|
||||||
void ForEachFile(F f) {
|
void ForEachFile(F f) {
|
||||||
for(auto& file : entryTable) {
|
for(auto& file : entryTable) {
|
||||||
if(file.uncompressedData.empty()) {
|
if(file.uncompressedData == nullptr) {
|
||||||
auto gid = (file.gid >> 8);
|
auto gid = (file.gid >> 8);
|
||||||
auto entries = lib->GroupDescriptors()[gid].Entries(boltFile.GetMapping());
|
auto entries = lib->GroupDescriptors()[gid].Entries(boltFile.GetMapping());
|
||||||
auto size = entries[file.index & 0x00ff].fileSize;
|
auto size = entries[file.index & 0x00ff].fileSize;
|
||||||
auto offset = entries[file.index & 0x00ff].fileOffset;
|
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))
|
if(!f(file))
|
||||||
|
@ -146,13 +165,41 @@ struct BoltReader {
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
BoltReader reader;
|
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();
|
std::cout << "Error opening Bolt file: " << error.Error();
|
||||||
}
|
}
|
||||||
|
|
||||||
reader.ForEachFile([](BoltReader::ParsedTableEntry& ent) {
|
reader.ForEachFile([](BoltReader::ParsedTableEntry& ent) {
|
||||||
std::cout << std::format("File: {} magic: ", ent.filename) << ent.uncompressedData[0] << ent.uncompressedData[1] << ent.uncompressedData[2]
|
std::cout << std::format("File: {}", ent.filename);
|
||||||
<< ent.uncompressedData[3] << '\n';
|
|
||||||
|
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;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue