Add Resource as interface for in-memory resources

This commit is contained in:
2015-06-08 22:44:07 +02:00
parent 584da2e3e8
commit ed32a1290e
15 changed files with 136 additions and 80 deletions

View File

@@ -9,13 +9,13 @@ struct ChunkHeader {
uint32_t length; uint32_t length;
}; };
IffFile::IffFile(uint8_t const* base, size_t length) IffFile::IffFile(Resource const& res)
: base_(base), length_(length) : res_(res)
{ {
size_t pos = 0; size_t pos = 0;
while (pos < length) { while (pos < res_.size()) {
roots_.push_back(parseObject(base+pos, length-pos)); roots_.push_back(parseObject(res_.data()+pos, res_.size()-pos));
pos += roots_.back()->getSize() + 8; pos += roots_.back()->size() + 8;
} }
} }
@@ -27,7 +27,7 @@ static void _printStructure(IffFile::Object const& obj, unsigned level)
{ {
for (unsigned i = 0;i < level;++i) for (unsigned i = 0;i < level;++i)
putchar('\t'); putchar('\t');
printf("%s Length %lu (0x%.lx)", obj.getType().c_str(), obj.getSize(), obj.getSize()); printf("%s Length %lu (0x%.lx)", obj.getType().c_str(), obj.size(), obj.size());
if (obj.isForm()) { if (obj.isForm()) {
auto& form = dynamic_cast<IffFile::Form const&>(obj); auto& form = dynamic_cast<IffFile::Form const&>(obj);
@@ -129,7 +129,7 @@ IffFile::Form::Form(std::string type, uint8_t const* base, size_t length)
size_t pos = 4; size_t pos = 4;
while (pos+8 < length) { while (pos+8 < length) {
children_.push_back(parseObject(base+pos, length-pos)); children_.push_back(parseObject(base+pos, length-pos));
pos += 8 + children_.back()->getSize(); pos += 8 + children_.back()->size();
if (pos%2 != 0) if (pos%2 != 0)
++pos; ++pos;

View File

@@ -7,9 +7,11 @@
#include <memory> #include <memory>
#include <typeinfo> #include <typeinfo>
#include "Resource.hh"
class IffFile { class IffFile {
public: public:
IffFile(uint8_t const* base, size_t length); IffFile(Resource const& res);
~IffFile(); ~IffFile();
@@ -109,12 +111,12 @@ public:
std::vector<std::unique_ptr<Object> >::const_iterator implIt_; std::vector<std::unique_ptr<Object> >::const_iterator implIt_;
}; };
class Object { class Object : public Resource {
public: public:
Object(std::string type, uint8_t const* base, size_t length); Object(std::string type, uint8_t const* base, size_t length);
Object(Object const& copy) = delete; Object(Object const& copy) = delete;
virtual ~Object() { ~Object() override {
} }
std::string const& getType() const { std::string const& getType() const {
@@ -125,10 +127,14 @@ public:
return (typeid(*this) == typeid(Form)); return (typeid(*this) == typeid(Form));
} }
size_t getSize() const { size_t size() const override {
return length_; return length_;
} }
uint8_t const* data() const override {
return base_;
}
uint8_t const* begin() const { uint8_t const* begin() const {
return base_; return base_;
} }
@@ -138,6 +144,10 @@ public:
} }
operator std::string() const; operator std::string() const;
operator bool() const override {
return true;
}
protected: protected:
uint8_t const* base_; uint8_t const* base_;
@@ -188,8 +198,7 @@ public:
private: private:
static std::unique_ptr<Object> parseObject(uint8_t const* base, size_t length); static std::unique_ptr<Object> parseObject(uint8_t const* base, size_t length);
uint8_t const* base_; Resource const& res_;
const size_t length_;
std::vector<std::unique_ptr<Object> > roots_; std::vector<std::unique_ptr<Object> > roots_;
}; };

View File

@@ -8,8 +8,8 @@
#include "decompress.hh" #include "decompress.hh"
#include "MveDecoder.hh" #include "MveDecoder.hh"
MveDecoder::MveDecoder(uint8_t const* base, size_t length) MveDecoder::MveDecoder(Resource const& res)
: iff_(base, length), width_(320), height_(165) : iff_(res), width_(320), height_(165)
{ {
//iff_.printStructure(); //iff_.printStructure();
@@ -26,7 +26,7 @@ MveDecoder::MveDecoder(uint8_t const* base, size_t length)
// Parse _PC_ chunk // Parse _PC_ chunk
auto& PC = *it++; auto& PC = *it++;
if ((PC.getType() != "_PC_") || if ((PC.getType() != "_PC_") ||
(PC.getSize() != 12)) (PC.size() != 12))
throw FormatException{"_PC_ chunk missing or wrong size"}; throw FormatException{"_PC_ chunk missing or wrong size"};
const uint32_t PC_PALTcount = readU32LE(PC.begin()+8); const uint32_t PC_PALTcount = readU32LE(PC.begin()+8);
@@ -37,7 +37,7 @@ MveDecoder::MveDecoder(uint8_t const* base, size_t length)
// // Parse SOND chunk // // Parse SOND chunk
// auto& SOND = *it++; // auto& SOND = *it++;
// if ((SOND.getType() != "SOND") || // if ((SOND.getType() != "SOND") ||
// (SOND.getSize() != 4)) // (SOND.size() != 4))
// throw FormatException{"SOND chunk missing or wrong size"}; // throw FormatException{"SOND chunk missing or wrong size"};
// const uint32_t SONDc = readU32LE(SOND.begin()); // const uint32_t SONDc = readU32LE(SOND.begin());
@@ -53,7 +53,7 @@ MveDecoder::MveDecoder(uint8_t const* base, size_t length)
for (;it != rootForm.childrenEnd();++it) { for (;it != rootForm.childrenEnd();++it) {
if (it->getType() == "SIZE") { if (it->getType() == "SIZE") {
if (it->getSize() != 8) if (it->size() != 8)
throw FormatException{"Unexpected SIZE size"}; throw FormatException{"Unexpected SIZE size"};
width_ = readU32LE(it->begin()); width_ = readU32LE(it->begin());
@@ -61,7 +61,7 @@ MveDecoder::MveDecoder(uint8_t const* base, size_t length)
} else if (it->getType() == "PALT") { } else if (it->getType() == "PALT") {
if (curPALT > PC_PALTcount) if (curPALT > PC_PALTcount)
throw FormatException{"Number of PALT chunks exceeds amount specified in _PC_"}; throw FormatException{"Number of PALT chunks exceeds amount specified in _PC_"};
if (it->getSize() != 768) if (it->size() != 768)
throw FormatException{"Unexpected PALT size"}; throw FormatException{"Unexpected PALT size"};
palts_.emplace_back(); palts_.emplace_back();
@@ -95,11 +95,11 @@ MveDecoder::MveDecoder(uint8_t const* base, size_t length)
throw FormatException{"INDX after SHOT"}; throw FormatException{"INDX after SHOT"};
haveIndex = true; haveIndex = true;
for(unsigned i = 0;i < it->getSize()/4;++i) for(unsigned i = 0;i < it->size()/4;++i)
branches.push_back(readU32LE(it->begin()+i*4)); branches.push_back(readU32LE(it->begin()+i*4));
branches_.resize(branches.size()); branches_.resize(branches.size());
} else if (it->getType() == "BRCH") { } else if (it->getType() == "BRCH") {
size_t ofs = it->begin()-base-8; size_t ofs = it->begin()-res.data()-8;
auto idxIt = std::find(branches.begin(), branches.end(), ofs); auto idxIt = std::find(branches.begin(), branches.end(), ofs);
if (idxIt == branches.end()) if (idxIt == branches.end())
throw FormatException{"Could not resolve branch " + std::to_string(ofs)}; throw FormatException{"Could not resolve branch " + std::to_string(ofs)};
@@ -276,13 +276,13 @@ unsigned MveDecoder::Movie::getHeight() const
void MveDecoder::Movie::parseVGA(IffFile::Object const& vga) void MveDecoder::Movie::parseVGA(IffFile::Object const& vga)
{ {
// Parse header // Parse header
if (vga.getSize() < 8) if (vga.size() < 8)
throw FormatException{"VGA chunk smaller than VGA header"}; throw FormatException{"VGA chunk smaller than VGA header"};
std::array<uint16_t, 4> segOfs; std::array<uint16_t, 4> segOfs;
for(unsigned i = 0;i < segOfs.size();++i) { for(unsigned i = 0;i < segOfs.size();++i) {
segOfs[i] = readU16LE(vga.begin()+i*2); segOfs[i] = readU16LE(vga.begin()+i*2);
if (segOfs[i] >= vga.getSize()) if (segOfs[i] >= vga.size())
throw FormatException{"Segment offset exceeds chunk"}; throw FormatException{"Segment offset exceeds chunk"};
} }
@@ -291,7 +291,7 @@ void MveDecoder::Movie::parseVGA(IffFile::Object const& vga)
((segOfs[1] && (segOfs[1] - segOfs[0]) < 45)) || ((segOfs[1] && (segOfs[1] - segOfs[0]) < 45)) ||
((segOfs[2] && (segOfs[2] - segOfs[0]) < 45)) || ((segOfs[2] && (segOfs[2] - segOfs[0]) < 45)) ||
((segOfs[3] && (segOfs[3] - segOfs[0]) < 45)) || ((segOfs[3] && (segOfs[3] - segOfs[0]) < 45)) ||
(vga.getSize() - segOfs[0] < 45)) (vga.size() - segOfs[0] < 45))
throw FormatException{"Segment 1 too small"}; throw FormatException{"Segment 1 too small"};
commandBuf_.clear(); commandBuf_.clear();
@@ -301,7 +301,7 @@ void MveDecoder::Movie::parseVGA(IffFile::Object const& vga)
size_t pixelCount = 0; size_t pixelCount = 0;
if (segOfs[3]) { if (segOfs[3]) {
pixelCount = parsePixels_(vga.begin()+segOfs[3], vga.getSize()-segOfs[3], pixelCount = parsePixels_(vga.begin()+segOfs[3], vga.size()-segOfs[3],
pixelBuf_.data(), pixelBuf_.size()); pixelBuf_.data(), pixelBuf_.size());
maxPixel_ = std::max(maxPixel_, pixelCount); maxPixel_ = std::max(maxPixel_, pixelCount);
} }
@@ -309,7 +309,7 @@ void MveDecoder::Movie::parseVGA(IffFile::Object const& vga)
#ifdef VIDDEBUG_ #ifdef VIDDEBUG_
printf("%lu commands, %lu pixel data, %u mvecs, %lu size data\n", printf("%lu commands, %lu pixel data, %u mvecs, %lu size data\n",
commands.size(), pixels.size(), (segOfs[2]?(segOfs[3]-segOfs[2]):0), commands.size(), pixels.size(), (segOfs[2]?(segOfs[3]-segOfs[2]):0),
segOfs[2]?(segOfs[2]-segOfs[1]):(segOfs[3]?(segOfs[3]-segOfs[1]):(vga.getSize()-segOfs[1]))); segOfs[2]?(segOfs[2]-segOfs[1]):(segOfs[3]?(segOfs[3]-segOfs[1]):(vga.size()-segOfs[1])));
#endif #endif
// Interpret command stream to render frame // Interpret command stream to render frame
@@ -352,7 +352,7 @@ void MveDecoder::Movie::parseVGA(IffFile::Object const& vga)
if (!segOfs[1] || if (!segOfs[1] ||
(segOfs[2] && (segOfs[1]+seg2Idx >= segOfs[2])) || (segOfs[2] && (segOfs[1]+seg2Idx >= segOfs[2])) ||
(segOfs[3] && (segOfs[1]+seg2Idx >= segOfs[3])) || (segOfs[3] && (segOfs[1]+seg2Idx >= segOfs[3])) ||
(segOfs[1]+seg2Idx >= vga.getSize())) (segOfs[1]+seg2Idx >= vga.size()))
throw FormatException{"Segment 2 overrun"}; throw FormatException{"Segment 2 overrun"};
size = vga.begin()[segOfs[1]+seg2Idx++]&0xff; size = vga.begin()[segOfs[1]+seg2Idx++]&0xff;
break; break;
@@ -361,7 +361,7 @@ void MveDecoder::Movie::parseVGA(IffFile::Object const& vga)
if (!segOfs[1] || if (!segOfs[1] ||
(segOfs[2] && (segOfs[1]+seg2Idx+1 >= segOfs[2])) || (segOfs[2] && (segOfs[1]+seg2Idx+1 >= segOfs[2])) ||
(segOfs[3] && (segOfs[1]+seg2Idx >= segOfs[3])) || (segOfs[3] && (segOfs[1]+seg2Idx >= segOfs[3])) ||
(segOfs[1]+seg2Idx+1 >= vga.getSize())) (segOfs[1]+seg2Idx+1 >= vga.size()))
throw FormatException{"Segment 2 overrun"}; throw FormatException{"Segment 2 overrun"};
size = readU16BE(vga.begin()+segOfs[1]+seg2Idx); size = readU16BE(vga.begin()+segOfs[1]+seg2Idx);
seg2Idx += 2; seg2Idx += 2;
@@ -371,7 +371,7 @@ void MveDecoder::Movie::parseVGA(IffFile::Object const& vga)
if (!segOfs[1] || if (!segOfs[1] ||
(segOfs[2] && (segOfs[1]+seg2Idx+2 >= segOfs[2])) || (segOfs[2] && (segOfs[1]+seg2Idx+2 >= segOfs[2])) ||
(segOfs[3] && (segOfs[1]+seg2Idx >= segOfs[3])) || (segOfs[3] && (segOfs[1]+seg2Idx >= segOfs[3])) ||
(segOfs[1]+seg2Idx+2 >= vga.getSize())) (segOfs[1]+seg2Idx+2 >= vga.size()))
throw FormatException{"Segment 2 overrun"}; throw FormatException{"Segment 2 overrun"};
size = readU24BE(vga.begin()+segOfs[1]+seg2Idx); size = readU24BE(vga.begin()+segOfs[1]+seg2Idx);
seg2Idx += 3; seg2Idx += 3;
@@ -410,7 +410,7 @@ void MveDecoder::Movie::parseVGA(IffFile::Object const& vga)
#endif #endif
if (!segOfs[2] || if (!segOfs[2] ||
(segOfs[3] && (segOfs[2]+seg3Idx > segOfs[3])) || (segOfs[3] && (segOfs[2]+seg3Idx > segOfs[3])) ||
(segOfs[2]+seg3Idx > vga.getSize())) (segOfs[2]+seg3Idx > vga.size()))
throw FormatException{"Segment 3 overrun"}; throw FormatException{"Segment 3 overrun"};
const uint8_t mpos = vga.begin()[segOfs[2]+seg3Idx++]; const uint8_t mpos = vga.begin()[segOfs[2]+seg3Idx++];
@@ -467,7 +467,7 @@ void audioCB_(void* userdata, uint8_t *buf, int len)
} }
while ((len > 0) && cbdata->cur) { while ((len > 0) && cbdata->cur) {
if (cbdata->pos >= (*cbdata->aCur)->getSize()) { if (cbdata->pos >= (*cbdata->aCur)->size()) {
cbdata->pos = 0; cbdata->pos = 0;
++cbdata->aCur; ++cbdata->aCur;
if (cbdata->aCur == cbdata->cur->AUDIs.end()) { if (cbdata->aCur == cbdata->cur->AUDIs.end()) {
@@ -484,8 +484,8 @@ void audioCB_(void* userdata, uint8_t *buf, int len)
auto& aCur = *cbdata->aCur; auto& aCur = *cbdata->aCur;
size_t toCopy = len; size_t toCopy = len;
if (cbdata->pos+toCopy > aCur->getSize()) if (cbdata->pos+toCopy > aCur->size())
toCopy = aCur->getSize()-cbdata->pos; toCopy = aCur->size()-cbdata->pos;
std::copy(aCur->begin()+cbdata->pos, aCur->begin()+cbdata->pos+toCopy, std::copy(aCur->begin()+cbdata->pos, aCur->begin()+cbdata->pos+toCopy,
buf); buf);
len -= toCopy; len -= toCopy;

View File

@@ -6,9 +6,11 @@
#include "IffFile.hh" #include "IffFile.hh"
class Resource;
class MveDecoder { class MveDecoder {
public: public:
MveDecoder(uint8_t const* base, size_t length); MveDecoder(Resource const& res);
size_t numBranches() const { size_t numBranches() const {
return branches_.size(); return branches_.size();

View File

@@ -4,8 +4,8 @@
#include "exceptions.hh" #include "exceptions.hh"
#include "util.hh" #include "util.hh"
ObjDecoder::ObjDecoder(uint8_t const* base, size_t length) ObjDecoder::ObjDecoder(Resource const& res)
: iff_(base, length) : iff_(res)
{ {
auto& root = iff_.getRoot(); auto& root = iff_.getRoot();
if (!root.isForm()) if (!root.isForm())
@@ -17,7 +17,7 @@ ObjDecoder::ObjDecoder(uint8_t const* base, size_t length)
for (auto realIt = rootForm.childrenBegin();realIt != rootForm.childrenEnd();++realIt) { for (auto realIt = rootForm.childrenBegin();realIt != rootForm.childrenEnd();++realIt) {
if (realIt->getType() == "INFO") { if (realIt->getType() == "INFO") {
name_ = *realIt; name_ = static_cast<std::string>(*realIt);
printf("Name: \"%s\"\n", name_.c_str()); printf("Name: \"%s\"\n", name_.c_str());
} else if (realIt->isForm()) { } else if (realIt->isForm()) {
auto& itForm = dynamic_cast<IffFile::Form const&>(*realIt); auto& itForm = dynamic_cast<IffFile::Form const&>(*realIt);
@@ -79,9 +79,9 @@ void ObjDecoder::parsePOLY_(IffFile::Form const& form)
for (auto it = form.childrenBegin();it != form.childrenEnd();++it) { for (auto it = form.childrenBegin();it != form.childrenEnd();++it) {
if (it->getType() == "INFO") { if (it->getType() == "INFO") {
} else if (it->getType() == "VERT") { } else if (it->getType() == "VERT") {
if (it->getSize()%12 != 0) if (it->size()%12 != 0)
throw FormatException{"Unexpected VERT size"}; throw FormatException{"Unexpected VERT size"};
for (size_t i = 0;i < it->getSize();i+=12) { for (size_t i = 0;i < it->size();i+=12) {
std::array<int32_t, 3> vertex; std::array<int32_t, 3> vertex;
for (size_t j = 0;j < 3;++j) for (size_t j = 0;j < 3;++j)
vertex[j] = readU32LE(it->begin()+i+j*4); vertex[j] = readU32LE(it->begin()+i+j*4);
@@ -137,10 +137,10 @@ void ObjDecoder::parseTRIS_(IffFile::Form const& form)
assert(face && maps); assert(face && maps);
if (face->getSize()%8 != 0) if (face->size()%8 != 0)
throw FormatException{"Unexpected FACE size"}; throw FormatException{"Unexpected FACE size"};
auto numTriangles = face->getSize()/8; auto numTriangles = face->size()/8;
if (maps->getSize() != numTriangles*16) if (maps->size() != numTriangles*16)
printf("WARNING: Unexpected MAPS size\n"); printf("WARNING: Unexpected MAPS size\n");
// throw FormatException{"Unexpected MAPS size"}; // throw FormatException{"Unexpected MAPS size"};
@@ -185,10 +185,10 @@ void ObjDecoder::parseQUAD_(IffFile::Form const& form)
assert(face && maps); assert(face && maps);
if (face->getSize()%10 != 0) if (face->size()%10 != 0)
throw FormatException{"Unexpected FACE size"}; throw FormatException{"Unexpected FACE size"};
auto numQuads = face->getSize()/10; auto numQuads = face->size()/10;
if (maps->getSize() != numQuads*20) if (maps->size() != numQuads*20)
printf("WARNING: Unexpected MAPS size\n"); printf("WARNING: Unexpected MAPS size\n");
//throw FormatException{"Unexpected MAPS size"}; //throw FormatException{"Unexpected MAPS size"};
@@ -225,12 +225,12 @@ void ObjDecoder::parseDETA_(IffFile::Form const& form)
if (std::stoi(it->getType().substr(3)) != lvl) if (std::stoi(it->getType().substr(3)) != lvl)
throw FormatException{"Unexpected detail level"}; throw FormatException{"Unexpected detail level"};
if (it->getSize() < 4) if (it->size() < 4)
throw FormatException{"DETA child too small"}; throw FormatException{"DETA child too small"};
// uint32_t unkown = readU32LE(it->begin()); // uint32_t unkown = readU32LE(it->begin());
detailLevels_.emplace_back(); detailLevels_.emplace_back();
for (size_t pos = 4;pos < it->getSize()-1;pos += 2) for (size_t pos = 4;pos < it->size()-1;pos += 2)
detailLevels_.back().push_back(readU16LE(it->begin()+pos)); detailLevels_.back().push_back(readU16LE(it->begin()+pos));
printf("LVL %u: %lu entries\n", lvl, detailLevels_.back().size()); printf("LVL %u: %lu entries\n", lvl, detailLevels_.back().size());
@@ -250,7 +250,7 @@ void ObjDecoder::parseTXMS_(IffFile::Form const& form)
auto& info = *it++; auto& info = *it++;
if (info.getType() != "INFO") if (info.getType() != "INFO")
throw FormatException{"Missing INFO in TXMS"}; throw FormatException{"Missing INFO in TXMS"};
if (info.getSize() != 4) if (info.size() != 4)
throw FormatException{"Unexpected INFO size in TXMS"}; throw FormatException{"Unexpected INFO size in TXMS"};
uint16_t numTXMP, numTXMA; uint16_t numTXMP, numTXMA;
@@ -263,7 +263,7 @@ void ObjDecoder::parseTXMS_(IffFile::Form const& form)
texAnims_.reserve(numTXMA); texAnims_.reserve(numTXMA);
for (;it != form.childrenEnd();++it) { for (;it != form.childrenEnd();++it) {
if (it->getType() == "TXMP") { if (it->getType() == "TXMP") {
if (it->getSize() < 12u) if (it->size() < 12u)
throw FormatException{"TXMP smaller than header"}; throw FormatException{"TXMP smaller than header"};
Texture tex; Texture tex;
@@ -277,12 +277,12 @@ void ObjDecoder::parseTXMS_(IffFile::Form const& form)
tex.height = readU16LE(it->begin()+10); tex.height = readU16LE(it->begin()+10);
printf("TXMP size %hux%hu\n", tex.width, tex.height); printf("TXMP size %hux%hu\n", tex.width, tex.height);
if (it->getSize() < 12u+tex.width*tex.height) if (it->size() < 12u+tex.width*tex.height)
throw FormatException{"TXMP too small for pixel data"}; throw FormatException{"TXMP too small for pixel data"};
tex.pixels = std::vector<uint8_t>(it->begin()+12, it->begin()+12+tex.width*tex.height); tex.pixels = std::vector<uint8_t>(it->begin()+12, it->begin()+12+tex.width*tex.height);
textures_.emplace_back(std::move(tex)); textures_.emplace_back(std::move(tex));
} else if (it->getType() == "TXMA") { } else if (it->getType() == "TXMA") {
if (it->getSize() < 14u) if (it->size() < 14u)
throw FormatException{"TXMA smaller than header"}; throw FormatException{"TXMA smaller than header"};
TextureAnimation tex; TextureAnimation tex;
@@ -297,7 +297,7 @@ void ObjDecoder::parseTXMS_(IffFile::Form const& form)
tex.frames = readU16LE(it->begin()+12); tex.frames = readU16LE(it->begin()+12);
printf("TXMA size %hux%hu, %hu frames\n", tex.width, tex.height, tex.frames); printf("TXMA size %hux%hu, %hu frames\n", tex.width, tex.height, tex.frames);
if (it->getSize() < 14u+tex.width*tex.height*tex.frames) if (it->size() < 14u+tex.width*tex.height*tex.frames)
throw FormatException{"TXMA too small for pixel data"}; throw FormatException{"TXMA too small for pixel data"};
tex.pixels.reserve(tex.frames); tex.pixels.reserve(tex.frames);

View File

@@ -8,9 +8,11 @@
#include "IffFile.hh" #include "IffFile.hh"
class Resource;
class ObjDecoder { class ObjDecoder {
public: public:
ObjDecoder(uint8_t const* base, size_t length); ObjDecoder(Resource const& res);
using Vertex = std::array<int32_t, 3>; using Vertex = std::array<int32_t, 3>;
using Vertices = std::vector<Vertex>; using Vertices = std::vector<Vertex>;

View File

@@ -3,8 +3,8 @@
#include "PaletteDecoder.hh" #include "PaletteDecoder.hh"
#include "exceptions.hh" #include "exceptions.hh"
PaletteDecoder::PaletteDecoder(uint8_t const* base, size_t length) PaletteDecoder::PaletteDecoder(Resource const& res)
: iff_(base, length) : iff_(res)
{ {
auto& root = iff_.getRoot(); auto& root = iff_.getRoot();
if (!root.isForm()) if (!root.isForm())
@@ -20,6 +20,21 @@ PaletteDecoder::PaletteDecoder(uint8_t const* base, size_t length)
std::transform(paltIt->begin()+4, paltIt->begin()+772, std::transform(paltIt->begin()+4, paltIt->begin()+772,
palette_.begin(), palette_.begin(),
[](const char& in) -> uint8_t {return (in << 2) | ((in >> 6)&0x3);}); [](const char& in) -> uint8_t {return (in << 2) | ((in >> 6)&0x3);});
uint8_t min = 0xff, max = 0;
for (auto it = paltIt->begin()+4;it != paltIt->end();++it) {
if (*it == 0xff)
continue;
min = std::min(min, *it);
max = std::max(max, *it);
}
printf("palt value range %hhu..%hhu\n", min, max);
} else if (paltIt->getType() == "BLWH") {
auto dstIt = palette_.begin();
for (auto it = paltIt->begin()+4;it != paltIt->end();++it) {
*dstIt = *dstIt * ((*it << 2) | ((*it >> 6)&0x3)) / 255u;
++dstIt;
}
} }
} }
} }

View File

@@ -8,7 +8,7 @@
class PaletteDecoder { class PaletteDecoder {
public: public:
PaletteDecoder(uint8_t const* base, size_t length); PaletteDecoder(Resource const& res);
using Palette = std::array<uint8_t, 768>; using Palette = std::array<uint8_t, 768>;

18
Resource.hh Normal file
View File

@@ -0,0 +1,18 @@
#ifndef WC3RE_RESOURCE_HH__
#define WC3RE_RESOURCE_HH__
// Interface for any memory-resident resource
// For example mmap'd data file, TRE object, IFF Object, ...
class Resource {
public:
virtual ~Resource() {}
virtual uint8_t const* data() const = 0;
virtual size_t size() const = 0;
virtual operator bool() const = 0;
};
#endif

View File

@@ -8,6 +8,8 @@
#include <tuple> #include <tuple>
#include <experimental/optional> #include <experimental/optional>
#include "Resource.hh"
class TreFile { class TreFile {
public: public:
TreFile(uint8_t const* base, size_t length); TreFile(uint8_t const* base, size_t length);
@@ -27,7 +29,7 @@ public:
'path' */ 'path' */
static uint32_t calcCRC(std::string const& path); static uint32_t calcCRC(std::string const& path);
class Object { class Object : public Resource {
public: public:
Object() : base_(nullptr), length_(0) { Object() : base_(nullptr), length_(0) {
} }
@@ -50,19 +52,22 @@ public:
move.length_ = 0; move.length_ = 0;
return *this; return *this;
} }
~Object() override {
}
uint8_t const* data() const { uint8_t const* data() const override {
if (data_) if (data_)
return data_->data(); return data_->data();
else else
return base_; return base_;
} }
size_t size() const { size_t size() const override {
return length_; return length_;
} }
operator bool() const { operator bool() const override {
return data_ || base_; return data_ || base_;
} }

View File

@@ -10,13 +10,13 @@
#include "util.hh" #include "util.hh"
#include "IffFile.hh" #include "IffFile.hh"
void blobDump(IffFile::Object const& obj, std::string const& filename) void blobDump(Resource const& obj, std::string const& filename)
{ {
FILEUPtr file{fopen(filename.c_str(), "wb")}; FILEUPtr file{fopen(filename.c_str(), "wb")};
if (!file) if (!file)
throw POSIXException{errno, "Could not open file: " + filename}; throw POSIXException{errno, "Could not open file: " + filename};
if (fwrite(obj.begin(), obj.getSize(), 1, file.get()) != 1) if (fwrite(obj.data(), obj.size(), 1, file.get()) != 1)
throw POSIXException{errno, "Could not write"}; throw POSIXException{errno, "Could not write"};
} }
@@ -25,7 +25,7 @@ void iffDumper(IffFile::Object const& obj, bool dumpBlobs, std::string dumpPath,
{ {
for (unsigned i = 0;i < level;++i) for (unsigned i = 0;i < level;++i)
putchar('\t'); putchar('\t');
printf("%s Length %lu (0x%.lx)", obj.getType().c_str(), obj.getSize(), obj.getSize()); printf("%s Length %lu (0x%.lx)", obj.getType().c_str(), obj.size(), obj.size());
if (obj.isForm()) { if (obj.isForm()) {
auto& form = dynamic_cast<IffFile::Form const&>(obj); auto& form = dynamic_cast<IffFile::Form const&>(obj);
@@ -88,7 +88,7 @@ int main(int argc, char *argv[])
try { try {
MmapFile mmap{iffFile}; MmapFile mmap{iffFile};
IffFile iff{mmap.data(), mmap.size()}; IffFile iff{mmap};
if (printStructure) { if (printStructure) {
unsigned blobCount = 0, subdoc = 0; unsigned blobCount = 0, subdoc = 0;

View File

@@ -87,9 +87,9 @@ int main(int argc, char *argv[]) {
if (!object) // Wasn't a CRC, try as name if (!object) // Wasn't a CRC, try as name
object = tre->openName(objectSpec); object = tre->openName(objectSpec);
mve = std::make_unique<MveDecoder>(object.data(), object.size()); mve = std::make_unique<MveDecoder>(object);
} else } else
mve = std::make_unique<MveDecoder>(mmap.data(), mmap.size()); mve = std::make_unique<MveDecoder>(mmap);
if (play) { if (play) {
Renderer renderer; Renderer renderer;

View File

@@ -17,21 +17,25 @@
#include "game/GSShowObject.hh" #include "game/GSShowObject.hh"
void usage(char *argv0) { void usage(char *argv0) {
fprintf(stderr, "Usage: %s [-h] (tre-file name/crc)/iff-file\n", argv0); fprintf(stderr, "Usage: %s [-h] [-ppalt] (tre-file name/crc)/iff-file\n", argv0);
fprintf(stderr, "\tAttempt to decode the object stored in iff-file, or in the\n\tiff-object \"name\"/\"crc\" contained in tre-file\n"); fprintf(stderr, "\tAttempt to decode the object stored in iff-file, or in the\n\tiff-object \"name\"/\"crc\" contained in tre-file\n");
fprintf(stderr, "\t-p palt\tUse palette \"palt\"");
fprintf(stderr, "\t-h\tPrint this help\n"); fprintf(stderr, "\t-h\tPrint this help\n");
} }
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
std::string inFile, objectSpec; std::string inFile, objectSpec, paltFile = "tmp/1DC61F50";
bool useTre = false; bool useTre = false;
{ {
int opt; int opt;
while ((opt = getopt(argc, argv, "h")) != -1) { while ((opt = getopt(argc, argv, "hp:")) != -1) {
switch (opt) { switch (opt) {
case 'h': case 'h':
usage(argv[0]); usage(argv[0]);
return 0; return 0;
case 'p':
paltFile = optarg;
break;
default: default:
usage(argv[0]); usage(argv[0]);
return 1; return 1;
@@ -52,8 +56,8 @@ int main(int argc, char *argv[]) {
} }
try { try {
MmapFile paltMmap{"tmp/1DC61F50"}; MmapFile paltMmap{paltFile};
PaletteDecoder palt{paltMmap.data(), paltMmap.size()}; PaletteDecoder palt{paltMmap};
MmapFile mmap{inFile}; MmapFile mmap{inFile};
@@ -77,9 +81,9 @@ int main(int argc, char *argv[]) {
if (!object) // Wasn't a CRC, try as name if (!object) // Wasn't a CRC, try as name
object = tre->openName(objectSpec); object = tre->openName(objectSpec);
obj = std::make_unique<ObjDecoder>(object.data(), object.size()); obj = std::make_unique<ObjDecoder>(object);
} else } else
obj = std::make_unique<ObjDecoder>(mmap.data(), mmap.size()); obj = std::make_unique<ObjDecoder>(mmap);
render::Renderer renderer; render::Renderer renderer;
renderer.pushGS(std::make_unique<game::GSShowObject>(renderer, *obj, palt)); renderer.pushGS(std::make_unique<game::GSShowObject>(renderer, *obj, palt));

View File

@@ -74,7 +74,7 @@ int main(int argc, char *argv[]) {
continue; continue;
auto f = file.openName(name); auto f = file.openName(name);
try { try {
IffFile iff{f.data(), f.size()}; IffFile iff{f};
printf("%s:\n", name.c_str()); printf("%s:\n", name.c_str());
iff.printStructure(1); iff.printStructure(1);
} catch(FormatException &ex) { } catch(FormatException &ex) {
@@ -85,7 +85,7 @@ int main(int argc, char *argv[]) {
for(auto crc : file.getCRCs()) { for(auto crc : file.getCRCs()) {
auto f = file.openCRC(crc); auto f = file.openCRC(crc);
try { try {
IffFile iff{f.data(), f.size()}; IffFile iff{f};
printf("%.8x:\n", crc); printf("%.8x:\n", crc);
iff.printStructure(1); iff.printStructure(1);
} catch(FormatException &ex) { } catch(FormatException &ex) {

11
util.hh
View File

@@ -5,23 +5,24 @@
#include <string> #include <string>
#include "common.hh" #include "common.hh"
#include "Resource.hh"
class MmapFile { class MmapFile : public Resource {
public: public:
MmapFile(std::string fileName); MmapFile(std::string fileName);
MmapFile(MmapFile const& copy) = delete; MmapFile(MmapFile const& copy) = delete;
MmapFile(MmapFile && move); MmapFile(MmapFile && move);
~MmapFile(); ~MmapFile() override;
MmapFile& operator=(MmapFile const& copy) = delete; MmapFile& operator=(MmapFile const& copy) = delete;
MmapFile& operator=(MmapFile && move); MmapFile& operator=(MmapFile && move);
std::string const& name() const; std::string const& name() const;
size_t size() const; size_t size() const override;
uint8_t const* data() const; uint8_t const* data() const override;
operator bool() const; operator bool() const override;
private: private:
std::string name_; std::string name_;
FILEUPtr fd_; FILEUPtr fd_;