Files
wc3re/ShapDecoder.cc

86 lines
2.6 KiB
C++

#include <cstring>
#include <vector>
#include <map>
#include <algorithm>
#include <exceptions.hh>
#include "util.hh"
#include "Resource.hh"
#include "ResourceProvider.hh"
#include "ShapDecoder.hh"
ShapDecoder::ShapDecoder(std::string const& path)
: ShapDecoder(ResourceProvider::getInstance().getResource(path)) {
}
ShapDecoder::ShapDecoder(Resource::Handle res)
: res_(std::move(res))
{
if (res_->size() < 8)
throw FormatException{"Object smaller than header size"};
if (memcmp(res_->data(), "1.11", 4) != 0)
throw FormatException{"Wrong magic, not a SHAP?"};
uint32_t numSubObjs = readU32LE(res_->data()+4);
if (res_->size() < 8+numSubObjs*8)
throw FormatException{"Object smaller than subobject table size"};
uint32_t lastofs = 0;
for (uint32_t i = 0;i < numSubObjs;++i) {
uint32_t ofs = readU32LE(res_->data()+8+i*8);
if (lastofs)
printf("\t%u bytes of data\n", ofs-(lastofs+24));
lastofs = ofs;
uint32_t flags = readU32LE(res_->data()+8+i*8+4);
printf("Subobject %u: Ofs %u (0x%x), flags %.8x\n",
i, ofs, ofs, flags);
if (res_->size() < ofs+24)
throw FormatException{"Subobject header exceeds resource"};
uint16_t unk1 = readU16LE(res_->data()+ofs), unk2 = readU16LE(res_->data()+ofs+2),
unk3 = readU16LE(res_->data()+ofs+4), unk4 = readU16LE(res_->data()+ofs+6);
int32_t unk5 = readU32LE(res_->data()+ofs+8), unk6 = readU32LE(res_->data()+ofs+12);
uint32_t unk7 = readU32LE(res_->data()+ofs+16), unk8 = readU32LE(res_->data()+ofs+20);
printf("\tunk: %hu, %hu, %hu, %hu, %d, %d, %u, %u\n",
unk1, unk2, unk3, unk4, unk5, unk6, unk7, unk8);
std::vector<unsigned> hist(256, 0);
std::map<uint16_t, unsigned> hist2;
uint32_t end;
if (i < numSubObjs-1)
end = readU32LE(res_->data()+8+(i+1)*8);
else
end = res_->size();
uint16_t sreg = 0;
for (uint8_t const* it = res_->data()+ofs+24;it < res_->data()+end;++it) {
++hist.at(*it);
sreg = (sreg<<8)|*it;
++hist2[sreg];
}
for (unsigned i = 0;i < 256;++i)
if (hist[i])
printf("\t%.2x: %u\n", i, hist[i]);
std::vector<std::pair<uint16_t, unsigned> > sortedHist2(20);
std::partial_sort_copy
(hist2.begin(), hist2.end(),
sortedHist2.begin(), sortedHist2.end(),
[](std::pair<uint16_t, unsigned> const& a, std::pair<uint16_t, unsigned> const& b) -> bool {
return a.second > b.second;
});
for (auto& ent: sortedHist2)
if (ent.second > 1)
printf("\t%.4x: %u\n", ent.first, ent.second);
}
printf("\t%zu bytes of data\n", res_->size()-(lastofs+24));
}