mirror of
https://github.com/isledecomp/SIEdit.git
synced 2024-11-27 09:35:45 -05:00
lib: start re-weaving implementation
This commit is contained in:
parent
4d05dc8ac8
commit
7968e70031
6 changed files with 203 additions and 11 deletions
|
@ -65,7 +65,7 @@ void Core::DeleteChildren()
|
|||
}
|
||||
}
|
||||
|
||||
size_t Core::IndexOfChild(Core *chunk)
|
||||
size_t Core::IndexOfChild(Core *chunk) const
|
||||
{
|
||||
return std::find(children_.begin(), children_.end(), chunk) - children_.begin();
|
||||
}
|
||||
|
|
11
lib/core.h
11
lib/core.h
|
@ -21,11 +21,12 @@ public:
|
|||
|
||||
bool FindParent(Core *p) const;
|
||||
|
||||
LIBWEAVER_EXPORT void AppendChild(Core *Core);
|
||||
LIBWEAVER_EXPORT bool RemoveChild(Core *Core);
|
||||
LIBWEAVER_EXPORT size_t IndexOfChild(Core *Core);
|
||||
LIBWEAVER_EXPORT void InsertChild(size_t index, Core *Core);
|
||||
LIBWEAVER_EXPORT Core *RemoveChild(size_t index);
|
||||
void AppendChild(Core *Core);
|
||||
bool RemoveChild(Core *Core);
|
||||
void InsertChild(size_t index, Core *Core);
|
||||
Core *RemoveChild(size_t index);
|
||||
|
||||
LIBWEAVER_EXPORT size_t IndexOfChild(Core *Core) const;
|
||||
LIBWEAVER_EXPORT Core *GetChildAt(size_t index) const { return children_.at(index); }
|
||||
LIBWEAVER_EXPORT size_t GetChildCount() const { return children_.size(); }
|
||||
LIBWEAVER_EXPORT bool HasChildren() const { return !children_.empty(); }
|
||||
|
|
|
@ -46,14 +46,139 @@ bool Interleaf::Parse(Chunk *riff)
|
|||
return false;
|
||||
}
|
||||
} else {
|
||||
//Object *nullobj = new Object();
|
||||
//AppendChild(nullobj);
|
||||
Object *nullobj = new Object();
|
||||
AppendChild(nullobj);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct ChunkStatus {
|
||||
ChunkStatus()
|
||||
{
|
||||
index = 0;
|
||||
time = 0;
|
||||
}
|
||||
|
||||
size_t index;
|
||||
uint32_t time;
|
||||
};
|
||||
|
||||
Chunk *Interleaf::Export() const
|
||||
{
|
||||
Chunk *riff = new Chunk(Chunk::TYPE_RIFF);
|
||||
riff->data("Format") = RIFF::OMNI;
|
||||
|
||||
Chunk *mxhd = new Chunk(Chunk::TYPE_MxHd);
|
||||
mxhd->data("Version") = version_;
|
||||
mxhd->data("BufferSize") = buffer_size_;
|
||||
mxhd->data("BufferCount") = buffer_count_;
|
||||
riff->AppendChild(mxhd);
|
||||
|
||||
Chunk *mxof = new Chunk(Chunk::TYPE_MxOf);
|
||||
|
||||
// FIXME: This appears to not always be correct, sometimes an MxOf with only one entry will have
|
||||
// a count of 3, seemingly due to embedded objects (e.g. a movie with an SMK + WAV)?
|
||||
uint32_t obj_count = this->GetChildCount();
|
||||
for (Children::const_iterator it=GetChildren().begin(); it!=GetChildren().end(); it++) {
|
||||
Object *obj = static_cast<Object*>(*it);
|
||||
obj_count += obj->GetChildCount();
|
||||
}
|
||||
mxof->data("Count") = obj_count;
|
||||
|
||||
// This however is correct.
|
||||
mxof->data("Offsets") = bytearray(this->GetChildCount() * sizeof(uint32_t));
|
||||
|
||||
riff->AppendChild(mxof);
|
||||
|
||||
Chunk *list = new Chunk(Chunk::TYPE_LIST);
|
||||
list->data("Format") = Chunk::TYPE_MxSt;
|
||||
riff->AppendChild(list);
|
||||
|
||||
for (Children::const_iterator it=GetChildren().begin(); it!=GetChildren().end(); it++) {
|
||||
Chunk *mxst = new Chunk(Chunk::TYPE_MxSt);
|
||||
list->AppendChild(mxst);
|
||||
|
||||
Object *obj = static_cast<Object*>(*it);
|
||||
Chunk *mxob = obj->Export();
|
||||
mxst->AppendChild(mxob);
|
||||
|
||||
Chunk *chunklst = new Chunk(Chunk::TYPE_LIST);
|
||||
chunklst->data("Format") = Chunk::TYPE_MxDa;
|
||||
mxst->AppendChild(chunklst);
|
||||
|
||||
// First, interleave all headers (first chunk)
|
||||
for (ssize_t i=-1; i<ssize_t(obj->GetChildCount()); i++) {
|
||||
Object *working_obj = static_cast<Object*>((i == -1) ? obj : obj->GetChildAt(i));
|
||||
if (!working_obj->data().empty()) {
|
||||
const bytearray &data = working_obj->data().front();
|
||||
Chunk *mxch = new Chunk(Chunk::TYPE_MxCh);
|
||||
mxch->data("Flags") = 0;
|
||||
mxch->data("Object") = working_obj->id();
|
||||
mxch->data("Time") = 0;
|
||||
mxch->data("DataSize") = data.size();
|
||||
mxch->data("Data") = data;
|
||||
chunklst->AppendChild(mxch);
|
||||
}
|
||||
}
|
||||
|
||||
// Next, interleave everything by time
|
||||
std::vector<ChunkStatus> chunk_status(obj->GetChildCount() + 1);
|
||||
bool all_done;
|
||||
do {
|
||||
all_done = true;
|
||||
for (ssize_t i=-1; i<ssize_t(obj->GetChildCount()); i++) {
|
||||
Object *working_obj = static_cast<Object*>((i == -1) ? obj : obj->GetChildAt(i));
|
||||
ChunkStatus &status = chunk_status[i+1];
|
||||
|
||||
if (status.index < working_obj->data().size()) {
|
||||
const bytearray &data = working_obj->data().at(status.index);
|
||||
|
||||
all_done = false;
|
||||
|
||||
Chunk *mxch = new Chunk(Chunk::TYPE_MxCh);
|
||||
mxch->data("Flags") = 0;
|
||||
mxch->data("Object") = working_obj->id();
|
||||
mxch->data("Time") = status.time;
|
||||
mxch->data("DataSize") = data.size();
|
||||
mxch->data("Data") = data;
|
||||
chunklst->AppendChild(mxch);
|
||||
|
||||
status.index++;
|
||||
|
||||
// Increment time
|
||||
switch (working_obj->filetype()) {
|
||||
case MxOb::WAV:
|
||||
status.time += 1000;
|
||||
break;
|
||||
case MxOb::STL:
|
||||
// Unaffected by time
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (!all_done);
|
||||
|
||||
// Finally interleave end chunks
|
||||
for (ssize_t i=obj->GetChildCount()-1; i>=-1; i--) {
|
||||
Object *working_obj = static_cast<Object*>((i == -1) ? obj : obj->GetChildAt(i));
|
||||
ChunkStatus &status = chunk_status[i+1];
|
||||
Chunk *mxch = new Chunk(Chunk::TYPE_MxCh);
|
||||
mxch->data("Flags") = MxCh::FLAG_END;
|
||||
mxch->data("Object") = working_obj->id();
|
||||
mxch->data("Time") = status.time;
|
||||
mxch->data("DataSize") = 0;
|
||||
chunklst->AppendChild(mxch);
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Fill in MxOf table
|
||||
// FIXME: Split MxCh chunks over alignment
|
||||
|
||||
return riff;
|
||||
}
|
||||
|
||||
bool Interleaf::ParseStream(Chunk *chunk)
|
||||
{
|
||||
if (chunk->type() != Chunk::TYPE_MxSt) {
|
||||
|
@ -77,13 +202,32 @@ bool Interleaf::ParseStream(Chunk *chunk)
|
|||
typedef std::map<uint32_t, Object::ChunkedData> ChunkMap;
|
||||
ChunkMap data;
|
||||
|
||||
uint32_t joining_chunk = 0;
|
||||
|
||||
for (Children::const_iterator it=list->GetChildren().begin(); it!=list->GetChildren().end(); it++) {
|
||||
Chunk *mxch = static_cast<Chunk*>(*it);
|
||||
if (mxch->id() == Chunk::TYPE_pad_) {
|
||||
// Ignore this chunk
|
||||
} else if (mxch->id() == Chunk::TYPE_MxCh) {
|
||||
uint16_t flags = mxch->data("Flags");
|
||||
if (!(flags & MxCh::FLAG_END)) {
|
||||
uint32_t obj_id = mxch->data("Object");
|
||||
data[obj_id].push_back(mxch->data("Data"));
|
||||
const Data &chunk_data = mxch->data("Data");
|
||||
|
||||
// For split chunks, join them together
|
||||
if (joining_chunk > 0) {
|
||||
data[obj_id].back().append(chunk_data);
|
||||
if (data[obj_id].back().size() == joining_chunk) {
|
||||
joining_chunk = 0;
|
||||
}
|
||||
} else {
|
||||
if (flags & MxCh::FLAG_SPLIT) {
|
||||
joining_chunk = mxch->data("DataSize");
|
||||
}
|
||||
|
||||
data[obj_id].push_back(chunk_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ public:
|
|||
LIBWEAVER_EXPORT Interleaf();
|
||||
|
||||
LIBWEAVER_EXPORT bool Parse(Chunk *riff);
|
||||
LIBWEAVER_EXPORT Chunk *Export() const;
|
||||
|
||||
private:
|
||||
bool ParseStream(Chunk *chunk);
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
#include "object.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace si {
|
||||
|
||||
Object::Object()
|
||||
{
|
||||
|
||||
type_ = MxOb::Null;
|
||||
id_ = 0;
|
||||
}
|
||||
|
||||
bool Object::Parse(Chunk *chunk)
|
||||
|
@ -47,6 +50,46 @@ bool Object::Parse(Chunk *chunk)
|
|||
return true;
|
||||
}
|
||||
|
||||
Chunk *Object::Export() const
|
||||
{
|
||||
Chunk *chunk = new Chunk(Chunk::TYPE_MxOb);
|
||||
|
||||
chunk->data("Type") = type_;
|
||||
chunk->data("Presenter") = presenter_;
|
||||
chunk->data("Unknown1") = unknown1_;
|
||||
chunk->data("Name") = name_;
|
||||
chunk->data("ID") = id_;
|
||||
chunk->data("Flags") = flags_;
|
||||
chunk->data("Unknown4") = unknown4_;
|
||||
chunk->data("Duration") = duration_;
|
||||
chunk->data("Loops") = loops_;
|
||||
chunk->data("Position") = position_;
|
||||
chunk->data("Direction") = direction_;
|
||||
chunk->data("Up") = up_;
|
||||
chunk->data("ExtraData") = extra_;
|
||||
chunk->data("FileName") = filename_;
|
||||
chunk->data("Unknown26") = unknown26_;
|
||||
chunk->data("Unknown27") = unknown27_;
|
||||
chunk->data("Unknown28") = unknown28_;
|
||||
chunk->data("FileType") = filetype_;
|
||||
chunk->data("Unknown29") = unknown29_;
|
||||
chunk->data("Unknown30") = unknown30_;
|
||||
chunk->data("Unknown31") = unknown31_;
|
||||
|
||||
if (HasChildren()) {
|
||||
Chunk *list = new Chunk(Chunk::TYPE_LIST);
|
||||
list->data("Format") = Chunk::TYPE_MxCh;
|
||||
chunk->AppendChild(list);
|
||||
|
||||
for (Children::const_iterator it=GetChildren().begin(); it!=GetChildren().end(); it++) {
|
||||
Object *child = static_cast<Object*>(*it);
|
||||
list->AppendChild(child->Export());
|
||||
}
|
||||
}
|
||||
|
||||
return chunk;
|
||||
}
|
||||
|
||||
bytearray Object::GetNormalizedData() const
|
||||
{
|
||||
return ToPackedData(filetype(), data_);
|
||||
|
|
|
@ -15,6 +15,8 @@ public:
|
|||
Object();
|
||||
|
||||
bool Parse(Chunk *chunk);
|
||||
Chunk *Export() const;
|
||||
|
||||
void SetChunkedData(const ChunkedData &cd) { data_ = cd; }
|
||||
|
||||
LIBWEAVER_EXPORT bytearray GetNormalizedData() const;
|
||||
|
@ -27,6 +29,7 @@ public:
|
|||
LIBWEAVER_EXPORT bytearray GetFileBody() const;
|
||||
LIBWEAVER_EXPORT size_t GetFileBodySize() const;
|
||||
|
||||
const MxOb::Type &type() const { return type_; }
|
||||
const MxOb::FileType &filetype() const { return filetype_; }
|
||||
const uint32_t &id() const { return id_; }
|
||||
const std::string &name() const { return name_; }
|
||||
|
|
Loading…
Reference in a new issue