Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ jobs:
- name: Build
shell: bash
run: |
cmake . -G Ninja -DCMAKE_BUILD_TYPE=Release -DFFMPEG_ROOT=$FFMPEG_DIR
cmake . -G Ninja -DCMAKE_BUILD_TYPE=Release -DFFMPEG_ROOT=$(cygpath -m "$PWD")/$FFMPEG_DIR
ninja

- name: Deploy
Expand Down
1 change: 1 addition & 0 deletions include/libweaver/interleaf.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ class Interleaf : public Core
uint32_t m_Version;
uint32_t m_BufferSize;
uint32_t m_BufferCount;
uint32_t m_ObjectCount;

std::map<uint32_t, Object*> m_ObjectOffsetTable;
std::map<uint32_t, Object*> m_ObjectIDTable;
Expand Down
5 changes: 5 additions & 0 deletions include/libweaver/object.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ class Object : public Core

uint32_t time_offset_;

/// Raw MxDSSelectAction child list extension (selector string, count and
/// value strings), empty for regular child lists. Preserved verbatim
/// between Read and Write.
bytearray list_extension_;

ChunkedData data_;

private:
Expand Down
60 changes: 42 additions & 18 deletions lib/interleaf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,14 @@ static const uint32_t kMinimumChunkSize = 8;

Interleaf::Interleaf()
{
m_ObjectCount = 0;
}

void Interleaf::Clear()
{
m_Info.clear();
m_BufferSize = 0;
m_ObjectCount = 0;
m_JoiningProgress = 0;
m_JoiningSize = 0;
m_ObjectOffsetTable.clear();
Expand Down Expand Up @@ -114,6 +116,7 @@ Interleaf::Error Interleaf::ReadChunk(Core *parent, FileBase *f, Info *info)
case RIFF::MxOf:
{
uint32_t offset_count = f->ReadU32();
m_ObjectCount = offset_count;

desc << "Count: " << offset_count;

Expand Down Expand Up @@ -144,23 +147,29 @@ Interleaf::Error Interleaf::ReadChunk(Core *parent, FileBase *f, Info *info)

list_count = f->ReadU32();
if (list_count == LIST::Act_ || list_count == LIST::RAND) {
desc << "Extension: ";
if (list_count == LIST::RAND) {
uint32_t rand_upper = f->ReadU32();
uint64_t rand_val = uint64_t(rand_upper) << 32 | list_count;
f->seek(1, File::SeekCurrent);
desc << ((const char *) &rand_val);
} else if (list_count == LIST::Act_) {
desc << ((const char *) &list_count);
}
desc << std::endl;
// MxDSSelectAction extension: instead of a count, the list starts
// with a null-terminated selector string (e.g. "RANDOM_3") whose
// first four characters were just read, followed by the actual count
// and one null-terminated value string per child. Retain the raw
// bytes on the parent object so Write can reproduce them.
bytearray ext;
ext.append((const char *) &list_count, sizeof(list_count));

std::string selector = f->ReadString();
ext.append(selector.c_str(), selector.size() + 1);
desc << "Extension: " << RIFF::PrintU32AsString(list_count) << selector << std::endl;

// Re-read list count
list_count = f->ReadU32();
ext.append((const char *) &list_count, sizeof(list_count));

for (uint32_t i=0; i<list_count; i++) {
// Read every short
uint16_t val = f->ReadU16();
desc << " " << ((const char *) &val) << std::endl;
std::string val = f->ReadString();
ext.append(val.c_str(), val.size() + 1);
desc << " " << val << std::endl;
}

if (parent != static_cast<Core*>(this)) {
static_cast<Object*>(parent)->list_extension_ = ext;
}
}
desc << "Count: " << list_count << std::endl;
Expand Down Expand Up @@ -435,7 +444,7 @@ Interleaf::Error Interleaf::Write(FileBase *f) const
// MxOf
RIFF::Chk mxof = RIFF::BeginChunk(f, RIFF::MxOf);

f->WriteU32(GetChildCount());
f->WriteU32(m_ObjectCount ? m_ObjectCount : uint32_t(GetChildCount()));

offset_table_pos = f->pos();

Expand All @@ -458,7 +467,9 @@ Interleaf::Error Interleaf::Write(FileBase *f) const
continue;
}

size_t maxSz = child->CalculateMaximumDiskSize() + kMinimumChunkSize;
// MxSt header + object tree + the MxDa LIST header that follows it,
// all of which must not straddle a buffer boundary
size_t maxSz = child->CalculateMaximumDiskSize() + kMinimumChunkSize * 2 + 4;
WritePaddingIfNecessary(f, maxSz);

uint32_t mxst_offset = f->pos();
Expand Down Expand Up @@ -551,7 +562,11 @@ void Interleaf::WriteObject(FileBase *f, const Object *o) const
RIFF::Chk list_mxch = RIFF::BeginChunk(f, RIFF::LIST);

f->WriteU32(RIFF::MxCh);
f->WriteU32(o->GetChildCount());
if (o->list_extension_.empty()) {
f->WriteU32(o->GetChildCount());
} else {
f->WriteBytes(o->list_extension_);
}

for (size_t i = 0; i < o->GetChildCount(); i++) {
WriteObject(f, static_cast<Object*>(o->GetChildAt(i)));
Expand Down Expand Up @@ -805,7 +820,16 @@ void Interleaf::WritePaddingIfNecessary(FileBase *f, size_t projectedWrite) cons
size_t this_buf = f->pos()/m_BufferSize;
size_t end_buf = projected_end/m_BufferSize;
if (this_buf != end_buf) {
WritePadding(f, (end_buf * m_BufferSize) - f->pos());
size_t pad = (end_buf * m_BufferSize) - f->pos();
if (pad < kMinimumChunkSize) {
// Too small for a pad_ chunk; fill with zeroes, which readers skip as
// part of the buffer alignment rule
bytearray b(pad);
b.fill(0);
f->WriteBytes(b);
} else {
WritePadding(f, pad);
}
}
}

Expand Down
7 changes: 5 additions & 2 deletions lib/object.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,8 @@ size_t Object::CalculateMaximumDiskSize() const
{
size_t s = 0;

s += 108;
// 108 bytes of fixed fields + 2 for RIFF odd-size padding of this chunk
s += 110;
s += presenter_.size() + 1;
s += name_.size() + 1;
s += extra_.size();
Expand All @@ -297,7 +298,9 @@ size_t Object::CalculateMaximumDiskSize() const
}

if (this->HasChildren()) {
s += 16;
// Child LIST header + 2 for RIFF odd-size padding
s += 18;
s += list_extension_.size();

for (size_t i = 0; i < this->GetChildCount(); i++) {
s += static_cast<Object*>(this->GetChildAt(i))->CalculateMaximumDiskSize();
Expand Down
Loading