Commit 5f847f06 authored by David Gonçalves's avatar David Gonçalves 📖

add symbol name to tag on parsing so that we don't have to look it up later

parent fa23579e
Pipeline #219933984 passed with stages
in 3 minutes and 50 seconds
......@@ -38,7 +38,7 @@ map<int, string> SWF::tagTypeNames = {
{89, "StartSound2"}, {90, "DefineBitsJPEG4"}, {91, "DefineFont4"}, {93, "EnableTelemetry"}, {94, "PlaceObject4"}
};
SWF::SWF(const std::vector<uint8_t> &buffer) : tags(), version(),
SWF::SWF(const vector<uint8_t> &buffer) : tags(), version(),
frameSize(), frameRate(), frameCount(), projector() {
this->parseSwf(buffer);
}
......@@ -62,7 +62,7 @@ SWF::SWF(const std::vector<uint8_t> &buffer) : tags(), version(),
* 1 - zlib
* 2 - lzma
*/
vector<uint8_t> SWF::exportExe(const std::vector<uint8_t> &proj, int compression) {
vector<uint8_t> SWF::exportExe(const vector<uint8_t> &proj, int compression) {
vector<uint8_t> bytes = this->toBytes();
......@@ -139,7 +139,7 @@ vector<uint8_t> SWF::exportSwf(int compression) {
return bytes;
}
void SWF::parseSwf(const std::vector<uint8_t> &buffer) {
void SWF::parseSwf(const vector<uint8_t> &buffer) {
vector<uint8_t> swfBuf;
......@@ -161,7 +161,7 @@ void SWF::parseSwf(const std::vector<uint8_t> &buffer) {
* We read the tag id and length from these 2 bytes which are in little-endian,
* since we want to put them in a bitset we order them in big-endian.
*/
std::array<uint8_t, 2> tagCodeAndLength{swfBuf[++cur], swfBuf[cur - 1]};
array<uint8_t, 2> tagCodeAndLength{swfBuf[++cur], swfBuf[cur - 1]};
bitset<16> bs{};
bitset<10> tagType_bs;
......@@ -204,7 +204,7 @@ void SWF::parseSwf(const std::vector<uint8_t> &buffer) {
dbd->data.emplace_back(swfBuf[++cur]);
}
// Add tag to vector of tags
tags.emplace_back(std::move(dbd));
tags.emplace_back(move(dbd));
} else if (tagName(t->type) == "DefineSound") {
auto ds = make_unique<Tag_DefineSound>();
ds->tagCodeAndLength = t->tagCodeAndLength;
......@@ -227,7 +227,7 @@ void SWF::parseSwf(const std::vector<uint8_t> &buffer) {
ds->data.emplace_back(swfBuf[++cur]);
}
// Add tag to vector of tags
tags.emplace_back(std::move(ds));
tags.emplace_back(move(ds));
} else if (tagName(t->type) == "DefineBitsLossless" || tagName(t->type) == "DefineBitsLossless2") {
auto dbl = make_unique<Tag_DefineBitsLossless>();
dbl->tagCodeAndLength = t->tagCodeAndLength;
......@@ -257,7 +257,7 @@ void SWF::parseSwf(const std::vector<uint8_t> &buffer) {
}
// Add tag to vector of tags
tags.emplace_back(std::move(dbl));
tags.emplace_back(move(dbl));
} else if (tagName(t->type) == "SymbolClass") {
auto sc = make_unique<Tag_SymbolClass>();
......@@ -285,7 +285,7 @@ void SWF::parseSwf(const std::vector<uint8_t> &buffer) {
}
// Add tag to vector of tags
tags.emplace_back(std::move(sc));
tags.emplace_back(move(sc));
} else {
// Copy tag data
for (size_t i = 0; i < len; ++i) {
......@@ -293,7 +293,7 @@ void SWF::parseSwf(const std::vector<uint8_t> &buffer) {
}
// Add tag to vector of tags
tags.emplace_back(std::move(t));
tags.emplace_back(move(t));
}
/*SWF_DEBUG("Tag type: " << t.type << " (" << tagName(t.type) << ")\nTag length: " <<
......@@ -301,9 +301,34 @@ void SWF::parseSwf(const std::vector<uint8_t> &buffer) {
tagStart = ++cur;
}
fillTagsSymbolName();
}
size_t SWF::parseSwfHeader(std::vector<uint8_t> &buffer) {
void SWF::fillTagsSymbolName() {
/// Apparently there can be symbols with same ID (e.g. HF v0.3.0 has story04
/// and story05 both with ID=216), although this is likely a bug, as there is
/// no tag for story05 and tags can't have the same ID. But considering this,
/// we fill the tags' symbolName as if there could be tags with same ID.
std::map<size_t, size_t> duplicates;
for (auto &t : this->tags) {
auto names = this->getSymbolName(t->id);
if (names.empty()) {
continue;
} else if (names.size() == 1) {
t->symbolName = names[0];
} else if (names.size() > 1) {
if (duplicates.find(t->id) == duplicates.end()) {
duplicates[t->id] = 0;
} else {
++duplicates[t->id];
}
t->symbolName = names[duplicates[t->id]];
}
}
}
size_t SWF::parseSwfHeader(vector<uint8_t> &buffer) {
size_t cur = 0;
//Check if file is SWF and what compression is used
......@@ -418,8 +443,8 @@ Tag * SWF::getTagWithId(size_t id) {
return nullptr;
}
std::vector< std::pair<size_t, std::string> > SWF::getAllSymbols() const {
std::vector< std::pair<size_t, std::string> > symbols;
vector< pair<size_t, string> > SWF::getAllSymbols() const {
vector< pair<size_t, string> > symbols;
for (auto const &t : this->tags) {
if (t->type == tagId("SymbolClass")) {
auto *sc = static_cast<Tag_SymbolClass *>(t.get());
......@@ -429,18 +454,19 @@ std::vector< std::pair<size_t, std::string> > SWF::getAllSymbols() const {
return symbols;
}
string SWF::getSymbolName(size_t id) const {
vector<string> SWF::getSymbolName(size_t id) const {
vector<string> names;
for (auto const &t : this->tags) {
if (t->type == tagId("SymbolClass")) {
auto *sc = static_cast<Tag_SymbolClass *>(t.get());
auto it = find_if(sc->symbolClass.begin(), sc->symbolClass.end(),
[id](const std::pair<size_t, std::string> &p) -> bool { return p.first == id; });
[id](const pair<size_t, string> &p) -> bool { return p.first == id; });
if (it != sc->symbolClass.end()) {
return it->second;
names.emplace_back(it->second);
}
}
}
return "";
return names;
}
vector<uint8_t> SWF::toBytes() const {
......@@ -604,7 +630,7 @@ vector<uint8_t> SWF::exe2swf(const vector<uint8_t> &exe) {
*
* Using LodePNG: https://lodev.org/lodepng/
*/
std::vector<uint8_t> SWF::exportImage(size_t imageId) {
vector<uint8_t> SWF::exportImage(size_t imageId) {
/*vector<Tag *> db_v = this->getTagsOfType(SWF::tagId("DefineBits"));
vector<Tag *> dbj2_v = this->getTagsOfType(SWF::tagId("DefineBitsJPEG2"));
......@@ -794,7 +820,7 @@ std::vector<uint8_t> SWF::exportImage(size_t imageId) {
}
std::vector<uint8_t> SWF::exportBinary(size_t tagId) {
vector<uint8_t> SWF::exportBinary(size_t tagId) {
vector<Tag *> tv = this->getTagsOfType(SWF::tagId("DefineBinaryData"));
for (auto &t : tv) {
......@@ -807,7 +833,7 @@ std::vector<uint8_t> SWF::exportBinary(size_t tagId) {
}
void SWF::replaceBinary(const std::vector<uint8_t> &binBuf, size_t tagId) {
void SWF::replaceBinary(const vector<uint8_t> &binBuf, size_t tagId) {
vector<Tag *> tv = this->getTagsOfType(SWF::tagId("DefineBinaryData"));
for (auto &t : tv) {
......@@ -821,7 +847,7 @@ void SWF::replaceBinary(const std::vector<uint8_t> &binBuf, size_t tagId) {
}
std::vector<uint8_t> SWF::exportMp3(size_t soundId) {
vector<uint8_t> SWF::exportMp3(size_t soundId) {
vector<Tag *> tv = this->getTagsOfType(SWF::tagId("DefineSound"));
for (auto &t : tv) {
......@@ -850,7 +876,7 @@ std::vector<uint8_t> SWF::exportMp3(size_t soundId) {
*
* To-do: detect if it's PNG, JPEG, GIF or something else.
*/
void SWF::replaceImg(const std::vector<uint8_t> &imgBuf, size_t imgId) {
void SWF::replaceImg(const vector<uint8_t> &imgBuf, size_t imageId) {
/*vector<Tag *> db_v = this->getTagsOfType(SWF::tagId("DefineBits"));
vector<Tag *> dbj2_v = this->getTagsOfType(SWF::tagId("DefineBitsJPEG2"));
......@@ -862,7 +888,7 @@ void SWF::replaceImg(const std::vector<uint8_t> &imgBuf, size_t imgId) {
dbl_v.insert(dbl_v.end(), dbl2_v.begin(), dbl2_v.end());
for (auto &t : dbl_v) {
auto dbl = static_cast<Tag_DefineBitsLossless *>(t);
if (imgId == dbl->id) {
if (imageId == dbl->id) {
vector<uint8_t> argb;
unsigned width, height;
......@@ -910,7 +936,7 @@ void SWF::replaceImg(const std::vector<uint8_t> &imgBuf, size_t imgId) {
}
}
void SWF::replaceMp3(const std::vector<uint8_t> &mp3Buf, size_t soundId) {
void SWF::replaceMp3(const vector<uint8_t> &mp3Buf, size_t soundId) {
vector<Tag *> tv = this->getTagsOfType(SWF::tagId("DefineSound"));
for (auto &t : tv) {
......
......@@ -50,7 +50,7 @@ namespace swf {
public:
explicit SWF(const std::vector<uint8_t> &buffer);
std::vector <Tag *> getTagsOfType(int type);
Tag * getTagWithId(size_t id);
Tag * getTagWithId(size_t id); // Every definition tag must specify a unique ID. Duplicate IDs are not allowed.
inline static std::string tagName(int id) { return (tagTypeNames.find(id) == tagTypeNames.end()) ? "Unknown" : tagTypeNames[id]; }
inline static int tagId(const std::string &name) {
auto it = std::find_if(tagTypeNames.begin(), tagTypeNames.end(),
......@@ -68,15 +68,21 @@ namespace swf {
std::vector<uint8_t> exportBinary(size_t tagId);
std::vector<uint8_t> exportExe(const std::vector<uint8_t> &proj, int compression);
std::vector<uint8_t> exportSwf(int compression);
void replaceImg(const std::vector<uint8_t> &imgBuf, size_t imgId);
void replaceImg(const std::vector<uint8_t> &imgBuf, size_t imageId);
void replaceMp3(const std::vector<uint8_t> &mp3Buf, size_t soundId);
void replaceBinary(const std::vector<uint8_t> &binBuf, size_t tagId);
inline bool hasProjector() { return ! projector.buffer.empty(); }
inline bool isProjectorWindows() { return projector.windows; }
std::vector< std::pair<size_t, std::string> > getAllSymbols() const;
std::string getSymbolName(size_t id) const;
/// Apparently there can be symbols with same ID (e.g. HF v0.3.0 has story04
/// and story05 both with ID=216), although this is likely a bug, as there is
/// no tag for story05 and tags can't have the same ID. Regardless, we return
/// all symbols with the given ID, in case there is more than one.
std::vector<std::string> getSymbolName(size_t id) const;
private:
void parseSwf(const std::vector<uint8_t> &buffer);
void fillTagsSymbolName();
static std::map<int, std::string> tagTypeNames;
std::vector <std::unique_ptr<Tag>> tags;
uint8_t version; // 1 byte, after signature, followed by 4 bytes representing the SWF file length
......
......@@ -15,15 +15,22 @@ namespace swf {
class Tag {
public:
Tag() : i(0), id(0), type(), longTag(false), tagCodeAndLength(), data() {}
Tag() : i(0), id(0), type(), longTag(false), tagCodeAndLength(), data(), symbolName() {}
virtual ~Tag() {};
int i;
size_t i;
size_t id;
short type;
bool longTag;
std::array<uint8_t, 2> tagCodeAndLength; // we don't need to manipulate this as we don't mess with short tags
std::vector<uint8_t> data;
virtual std::vector<uint8_t> toBytes() const;
/// The symbol name is not saved directly in the tag, it is saved
/// in the SymbolClass tag, which contains a dictionary of symbols.
/// We thus full this parameter in every Tag object merely for the convenience
/// of not having to search for it later, especially since there can be
/// tags with.same ID, making this process more difficult.
std::string symbolName;
};
class Tag_DefineBinaryData : public Tag {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment