Add Resource as interface for in-memory resources
This commit is contained in:
14
IffFile.cc
14
IffFile.cc
@@ -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;
|
||||||
|
|||||||
21
IffFile.hh
21
IffFile.hh
@@ -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_;
|
||||||
}
|
}
|
||||||
@@ -139,6 +145,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_;
|
||||||
const size_t length_;
|
const size_t length_;
|
||||||
@@ -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_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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>;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
18
Resource.hh
Normal 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
|
||||||
13
TreFile.hh
13
TreFile.hh
@@ -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) {
|
||||||
}
|
}
|
||||||
@@ -51,18 +53,21 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t const* data() const {
|
~Object() override {
|
||||||
|
}
|
||||||
|
|
||||||
|
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_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
18
objdecode.cc
18
objdecode.cc
@@ -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));
|
||||||
|
|||||||
@@ -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
11
util.hh
@@ -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_;
|
||||||
|
|||||||
Reference in New Issue
Block a user