lib: implement abstract file handler

This commit is contained in:
itsmattkc 2022-07-18 11:25:00 -07:00
parent 180ead8188
commit 1ab22fd85c
11 changed files with 565 additions and 345 deletions

View file

@ -3,6 +3,8 @@ option(LIBWEAVER_BUILD_DOXYGEN "Build Doxygen documentation" OFF)
set(LIBWEAVER_SOURCES
core.cpp
core.h
file.cpp
file.h
info.h
interleaf.cpp
interleaf.h

234
lib/file.cpp Normal file
View file

@ -0,0 +1,234 @@
#include "file.h"
#include "util.h"
namespace si {
bool File::Open(const char *c, Mode mode)
{
std::ios::open_mode m = std::ios::binary;
if (mode == Read) {
m |= std::ios::in;
} else {
m |= std::ios::out;
}
m_Stream.open(c, m);
if (m_Stream.good() && m_Stream.is_open()) {
m_Mode = mode;
return true;
}
return false;
}
#ifdef _WIN32
bool File::Open(const wchar_t *c, Mode mode)
{
std::ios::open_mode m = std::ios::binary;
if (mode == Read) {
m |= std::ios::in;
} else {
m |= std::ios::out;
}
m_Stream.open(c, m);
if (m_Stream.good() && m_Stream.is_open()) {
m_Mode = mode;
return true;
}
return false;
}
#endif
size_t File::pos()
{
if (m_Mode == Read) {
return m_Stream.tellg();
} else {
return m_Stream.tellp();
}
}
void File::seek(size_t p, SeekMode s)
{
std::ios::seek_dir d;
switch (s) {
case SeekStart:
d = std::ios::beg;
break;
case SeekCurrent:
d = std::ios::cur;
break;
case SeekEnd:
d = std::ios::end;
break;
}
if (m_Mode == Read) {
m_Stream.seekg(p, d);
} else {
m_Stream.seekp(p, d);
}
}
bool File::atEnd()
{
return !m_Stream.good();
}
void File::CloseHandle()
{
m_Stream.close();
}
void File::ReadData(char *data, size_t size)
{
m_Stream.read(data, size);
}
void File::WriteData(const char *data, size_t size)
{
m_Stream.write(data, size);
}
uint8_t FileBase::ReadU8()
{
uint8_t u;
ReadData((char *) &u, sizeof(u));
return u;
}
void FileBase::WriteU8(uint8_t u)
{
WriteData((const char *) &u, sizeof(u));
}
uint16_t FileBase::ReadU16()
{
uint16_t u;
ReadData((char *) &u, sizeof(u));
return u;
}
void FileBase::WriteU16(uint16_t u)
{
WriteData((const char *) &u, sizeof(u));
}
uint32_t FileBase::ReadU32()
{
uint32_t u;
ReadData((char *) &u, sizeof(u));
return u;
}
void FileBase::WriteU32(uint32_t u)
{
WriteData((const char *) &u, sizeof(u));
}
Vector3 FileBase::ReadVector3()
{
Vector3 u;
ReadData((char *) &u, sizeof(u));
return u;
}
void FileBase::WriteVector3(const Vector3 &v)
{
WriteData((const char *) &v, sizeof(v));
}
std::string FileBase::ReadString()
{
std::string d;
while (true) {
char c;
ReadData(&c, 1);
if (c == 0) {
break;
}
d.push_back(c);
}
return d;
}
void FileBase::WriteString(const std::string &d)
{
WriteData(d.c_str(), d.size());
// Ensure null terminator
WriteU8(0);
}
bytearray FileBase::ReadBytes(size_t size)
{
bytearray d;
d.resize(size);
ReadData(d.data(), size);
return d;
}
void FileBase::WriteBytes(const bytearray &ba)
{
WriteData(ba.data(), ba.size());
}
MemoryBuffer::MemoryBuffer()
{
m_Position = 0;
}
size_t MemoryBuffer::pos()
{
return m_Position;
}
void MemoryBuffer::seek(size_t p, SeekMode s)
{
switch (s) {
case SeekStart:
m_Position = p;
break;
case SeekCurrent:
m_Position += p;
break;
case SeekEnd:
m_Position = std::max(size_t(0), m_Internal.size() - p);
break;
}
}
bool MemoryBuffer::atEnd()
{
return m_Position == m_Internal.size();
}
void MemoryBuffer::ReadData(char *data, size_t size)
{
size = std::min(size, m_Internal.size() - m_Position);
memcpy(data, m_Internal.data() + m_Position, size);
m_Position += size;
}
void MemoryBuffer::WriteData(const char *data, size_t size)
{
LogDebug() << "writing " << size << " bytes to " << m_Position << std::endl;
size_t end = m_Position + size;
if (end > m_Internal.size()) {
m_Internal.resize(end);
}
memcpy(m_Internal.data() + m_Position, data, size);
m_Position += size;
}
}

104
lib/file.h Normal file
View file

@ -0,0 +1,104 @@
#ifndef FILE_H
#define FILE_H
#include <fstream>
#include "types.h"
namespace si {
class FileBase
{
public:
FileBase()
{
}
virtual ~FileBase()
{
}
enum Mode {
Read,
Write
};
uint8_t ReadU8();
uint16_t ReadU16();
uint32_t ReadU32();
std::string ReadString();
bytearray ReadBytes(size_t size);
Vector3 ReadVector3();
virtual void ReadData(char *data, size_t size) = 0;
void WriteU8(uint8_t u);
void WriteU16(uint16_t u);
void WriteU32(uint32_t u);
void WriteString(const std::string &s);
void WriteBytes(const bytearray &b);
void WriteVector3(const Vector3 &b);
virtual void WriteData(const char *data, size_t size) = 0;
virtual void Close() {}
enum SeekMode
{
SeekStart,
SeekCurrent,
SeekEnd
};
virtual size_t pos() = 0;
virtual void seek(size_t p, SeekMode s = SeekStart) = 0;
virtual bool atEnd() = 0;
};
class File : public FileBase
{
public:
bool Open(const char *c, Mode mode);
#ifdef _WIN32
bool Open(const wchar_t *c, Mode mode);
#endif
virtual size_t pos();
virtual void seek(size_t p, SeekMode s = SeekStart);
virtual bool atEnd();
protected:
virtual void CloseHandle();
virtual void ReadData(char *data, size_t size);
virtual void WriteData(const char *data, size_t size);
private:
std::fstream m_Stream;
Mode m_Mode;
};
class MemoryBuffer : public FileBase
{
public:
MemoryBuffer();
virtual size_t pos();
virtual void seek(size_t p, SeekMode s = SeekStart);
virtual bool atEnd();
const bytearray &data() const { return m_Internal; }
protected:
virtual void ReadData(char *data, size_t size);
virtual void WriteData(const char *data, size_t size);
private:
bytearray m_Internal;
size_t m_Position;
};
}
#endif // FILE_H

View file

@ -30,48 +30,48 @@ void Interleaf::Clear()
Interleaf::Error Interleaf::Read(const char *f)
{
std::ifstream is(f);
if (!is.is_open() || !is.good()) {
File is;
if (!is.Open(f, File::Read)) {
return ERROR_IO;
}
return Read(is);
return Read(&is);
}
Interleaf::Error Interleaf::Write(const char *f) const
{
std::ofstream os(f);
if (!os.is_open() || !os.good()) {
File os;
if (!os.Open(f, File::Write)) {
return ERROR_IO;
}
return Write(os);
return Write(&os);
}
#ifdef _WIN32
Interleaf::Error Interleaf::Read(const wchar_t *f)
{
std::ifstream is(f);
if (!is.is_open() || !is.good()) {
File is;
if (!is.Open(f, File::Read)) {
return ERROR_IO;
}
return Read(is);
return Read(&is);
}
Interleaf::Error Interleaf::Write(const wchar_t *f) const
{
std::ofstream os(f);
if (!os.is_open() || !os.good()) {
File os;
if (!os.Open(f, File::Write)) {
return ERROR_IO;
}
return Write(os);
return Write(&os);
}
#endif
Interleaf::Error Interleaf::ReadChunk(Core *parent, std::istream &is, Info *info)
Interleaf::Error Interleaf::ReadChunk(Core *parent, FileBase *f, Info *info)
{
uint32_t offset = is.tellg();
uint32_t id = ReadU32(is);
uint32_t size = ReadU32(is);
uint32_t end = uint32_t(is.tellg()) + size;
uint32_t offset = f->pos();
uint32_t id = f->ReadU32();
uint32_t size = f->ReadU32();
uint32_t end = uint32_t(f->pos()) + size;
info->SetType(id);
info->SetOffset(offset);
@ -83,7 +83,7 @@ Interleaf::Error Interleaf::ReadChunk(Core *parent, std::istream &is, Info *info
case RIFF::RIFF_:
{
// Require RIFF type to be OMNI
uint32_t riff_type = ReadU32(is);
uint32_t riff_type = f->ReadU32();
if (riff_type != RIFF::OMNI) {
return ERROR_INVALID_INPUT;
}
@ -93,24 +93,24 @@ Interleaf::Error Interleaf::ReadChunk(Core *parent, std::istream &is, Info *info
}
case RIFF::MxHd:
{
m_Version = ReadU32(is);
m_Version = f->ReadU32();
desc << "Version: " << m_Version << std::endl;
m_BufferSize = ReadU32(is);
m_BufferSize = f->ReadU32();
desc << "Buffer Size: 0x" << std::hex << m_BufferSize;
if (m_Version == 0x00020002) {
m_BufferCount = ReadU32(is);
m_BufferCount = f->ReadU32();
desc << std::endl << "Buffer Count: " << std::dec << m_BufferCount << std::endl;
}
break;
}
case RIFF::pad_:
is.seekg(size, std::ios::cur);
f->seek(size, File::SeekCurrent);
break;
case RIFF::MxOf:
{
uint32_t offset_count = ReadU32(is);
uint32_t offset_count = f->ReadU32();
desc << "Count: " << offset_count;
@ -120,7 +120,7 @@ Interleaf::Error Interleaf::ReadChunk(Core *parent, std::istream &is, Info *info
Object *o = new Object();
parent->AppendChild(o);
uint32_t choffset = ReadU32(is);
uint32_t choffset = f->ReadU32();
m_ObjectList[i] = choffset;
desc << std::endl << i << ": 0x" << std::hex << choffset;
}
@ -128,11 +128,11 @@ Interleaf::Error Interleaf::ReadChunk(Core *parent, std::istream &is, Info *info
}
case RIFF::LIST:
{
uint32_t list_type = ReadU32(is);
uint32_t list_type = f->ReadU32();
desc << "Type: " << RIFF::PrintU32AsString(list_type) << std::endl;
uint32_t list_count = 0;
if (list_type == RIFF::MxCh) {
list_count = ReadU32(is);
list_count = f->ReadU32();
desc << "Count: " << list_count << std::endl;
}
break;
@ -161,7 +161,7 @@ Interleaf::Error Interleaf::ReadChunk(Core *parent, std::istream &is, Info *info
parent->AppendChild(o);
}
ReadObject(is, o, desc);
ReadObject(f, o, desc);
info->SetObjectID(o->id());
@ -172,19 +172,19 @@ Interleaf::Error Interleaf::ReadChunk(Core *parent, std::istream &is, Info *info
}
case RIFF::MxCh:
{
uint16_t flags = ReadU16(is);
uint16_t flags = f->ReadU16();
desc << "Flags: 0x" << std::hex << flags << std::endl;
uint32_t object = ReadU32(is);
uint32_t object = f->ReadU32();
desc << "Object: " << std::dec << object << std::endl;
uint32_t time = ReadU32(is);
uint32_t time = f->ReadU32();
desc << "Time: " << time << std::endl;
uint32_t data_sz = ReadU32(is);
uint32_t data_sz = f->ReadU32();
desc << "Size: " << data_sz << std::endl;
bytearray data = ReadBytes(is, size - MxCh::HEADER_SIZE);
bytearray data = f->ReadBytes(size - MxCh::HEADER_SIZE);
info->SetObjectID(object);
info->SetData(data);
@ -217,19 +217,19 @@ Interleaf::Error Interleaf::ReadChunk(Core *parent, std::istream &is, Info *info
}
// Assume any remaining data is this chunk's children
while (is.good() && (size_t(is.tellg()) + kMinimumChunkSize) < end) {
while (!f->atEnd() && (f->pos() + kMinimumChunkSize) < end) {
// Check alignment, if there's not enough room to for another segment, skip ahead
if (m_BufferSize > 0) {
uint32_t offset_in_buffer = is.tellg()%m_BufferSize;
uint32_t offset_in_buffer = f->pos()%m_BufferSize;
if (offset_in_buffer + kMinimumChunkSize > m_BufferSize) {
is.seekg(m_BufferSize-offset_in_buffer, std::ios::cur);
f->seek(m_BufferSize-offset_in_buffer, File::SeekCurrent);
}
}
// Read next child
Info *subinfo = new Info();
info->AppendChild(subinfo);
Error e = ReadChunk(parent, is, subinfo);
Error e = ReadChunk(parent, f, subinfo);
if (e != ERROR_SUCCESS) {
return e;
}
@ -237,66 +237,66 @@ Interleaf::Error Interleaf::ReadChunk(Core *parent, std::istream &is, Info *info
info->SetDescription(desc.str());
if (is.tellg() < end) {
is.seekg(end, std::ios::beg);
if (f->pos() < end) {
f->seek(end, File::SeekStart);
}
if (size%2 == 1) {
is.seekg(1, std::ios::cur);
f->seek(1, File::SeekCurrent);
}
return ERROR_SUCCESS;
}
Object *Interleaf::ReadObject(std::istream &is, Object *o, std::stringstream &desc)
Object *Interleaf::ReadObject(FileBase *f, Object *o, std::stringstream &desc)
{
o->type_ = static_cast<MxOb::Type>(ReadU16(is));
o->type_ = static_cast<MxOb::Type>(f->ReadU16());
desc << "Type: " << o->type_ << std::endl;
o->presenter_ = ReadString(is);
o->presenter_ = f->ReadString();
desc << "Presenter: " << o->presenter_ << std::endl;
o->unknown1_ = ReadU32(is);
o->unknown1_ = f->ReadU32();
desc << "Unknown1: " << o->unknown1_ << std::endl;
o->name_ = ReadString(is);
o->name_ = f->ReadString();
desc << "Name: " << o->name_ << std::endl;
o->id_ = ReadU32(is);
o->id_ = f->ReadU32();
desc << "ID: " << o->id_ << std::endl;
o->flags_ = ReadU32(is);
o->flags_ = f->ReadU32();
desc << "Flags: " << o->flags_ << std::endl;
o->unknown4_ = ReadU32(is);
o->unknown4_ = f->ReadU32();
desc << "Unknown4: " << o->unknown4_ << std::endl;
o->duration_ = ReadU32(is);
o->duration_ = f->ReadU32();
desc << "Duration: " << o->duration_ << std::endl;
o->loops_ = ReadU32(is);
o->loops_ = f->ReadU32();
desc << "Loops: " << o->loops_ << std::endl;
o->position_ = ReadVector3(is);
o->position_ = f->ReadVector3();
desc << "Position: " << o->position_.x << " " << o->position_.y << " " << o->position_.z << std::endl;
o->direction_ = ReadVector3(is);
o->direction_ = f->ReadVector3();
desc << "Direction: " << o->direction_.x << " " << o->direction_.y << " " << o->direction_.z << std::endl;
o->up_ = ReadVector3(is);
o->up_ = f->ReadVector3();
desc << "Up: " << o->up_.x << " " << o->up_.y << " " << o->up_.z << std::endl;
uint16_t extra_sz = ReadU16(is);
uint16_t extra_sz = f->ReadU16();
desc << "Extra Size: " << extra_sz << std::endl;
o->extra_ = ReadBytes(is, extra_sz);
o->extra_ = f->ReadBytes(extra_sz);
if (o->type_ != MxOb::Presenter && o->type_ != MxOb::World) {
o->filename_ = ReadString(is);
o->filename_ = f->ReadString();
desc << "Filename: " << o->filename_ << std::endl;
o->unknown26_ = ReadU32(is);
o->unknown26_ = f->ReadU32();
desc << "Unknown26: " << o->unknown26_ << std::endl;
o->unknown27_ = ReadU32(is);
o->unknown27_ = f->ReadU32();
desc << "Unknown27: " << o->unknown27_ << std::endl;
o->unknown28_ = ReadU32(is);
o->unknown28_ = f->ReadU32();
desc << "Unknown28: " << o->unknown28_ << std::endl;
o->filetype_ = static_cast<MxOb::FileType>(ReadU32(is));
o->filetype_ = static_cast<MxOb::FileType>(f->ReadU32());
desc << "File Type: " << RIFF::PrintU32AsString(o->filetype_) << std::endl;
o->unknown29_ = ReadU32(is);
o->unknown29_ = f->ReadU32();
desc << "Unknown29: " << o->unknown29_ << std::endl;
o->unknown30_ = ReadU32(is);
o->unknown30_ = f->ReadU32();
desc << "Unknown30: " << o->unknown30_ << std::endl;
if (o->filetype_ == MxOb::WAV) {
o->unknown31_ = ReadU32(is);
o->unknown31_ = f->ReadU32();
desc << "Unknown31: " << o->unknown31_ << std::endl;
}
}
@ -304,81 +304,81 @@ Object *Interleaf::ReadObject(std::istream &is, Object *o, std::stringstream &de
return o;
}
Interleaf::Error Interleaf::Read(std::istream &is)
Interleaf::Error Interleaf::Read(FileBase *f)
{
Clear();
return ReadChunk(this, is, &m_Info);
return ReadChunk(this, f, &m_Info);
}
Interleaf::Error Interleaf::Write(std::ostream &os) const
Interleaf::Error Interleaf::Write(FileBase *f) const
{
if (m_BufferSize == 0) {
LogError() << "Buffer size must be set to write" << std::endl;
return ERROR_INVALID_BUFFER_SIZE;
}
RIFF::Chk riff = RIFF::BeginChunk(os, RIFF::RIFF_);
WriteU32(os, RIFF::OMNI);
RIFF::Chk riff = RIFF::BeginChunk(f, RIFF::RIFF_);
f->WriteU32(RIFF::OMNI);
std::ios::pos_type offset_table_pos;
size_t offset_table_pos;
{
// MxHd
RIFF::Chk mxhd = RIFF::BeginChunk(os, RIFF::MxHd);
RIFF::Chk mxhd = RIFF::BeginChunk(f, RIFF::MxHd);
WriteU32(os, m_Version);
WriteU32(os, m_BufferSize);
f->WriteU32(m_Version);
f->WriteU32(m_BufferSize);
if (m_Version == 0x00020002) {
WriteU32(os, m_BufferCount);
f->WriteU32(m_BufferCount);
}
RIFF::EndChunk(os, mxhd);
RIFF::EndChunk(f, mxhd);
}
{
// MxOf
RIFF::Chk mxof = RIFF::BeginChunk(os, RIFF::MxOf);
RIFF::Chk mxof = RIFF::BeginChunk(f, RIFF::MxOf);
WriteU32(os, GetChildCount());
f->WriteU32(GetChildCount());
offset_table_pos = os.tellp();
offset_table_pos = f->pos();
for (size_t i = 0; i < GetChildCount(); i++) {
WriteU32(os, 0);
f->WriteU32(0);
}
RIFF::EndChunk(os, mxof);
RIFF::EndChunk(f, mxof);
}
{
// LIST
RIFF::Chk list_mxst = RIFF::BeginChunk(os, RIFF::LIST);
RIFF::Chk list_mxst = RIFF::BeginChunk(f, RIFF::LIST);
WriteU32(os, RIFF::MxSt);
f->WriteU32(RIFF::MxSt);
for (size_t i = 0; i < GetChildCount(); i++) {
Object *child = static_cast<Object*>(GetChildAt(i));
uint32_t mxst_offset = os.tellp();
uint32_t mxst_offset = f->pos();
os.seekp(size_t(offset_table_pos) + i * sizeof(uint32_t));
WriteU32(os, mxst_offset);
os.seekp(mxst_offset);
f->seek(size_t(offset_table_pos) + i * sizeof(uint32_t));
f->WriteU32(mxst_offset);
f->seek(mxst_offset);
// MxSt
RIFF::Chk mxst = RIFF::BeginChunk(os, RIFF::MxSt);
RIFF::Chk mxst = RIFF::BeginChunk(f, RIFF::MxSt);
{
// MxOb
WriteObject(os, child);
WriteObject(f, child);
}
{
// LIST
RIFF::Chk list_mxda = RIFF::BeginChunk(os, RIFF::LIST);
RIFF::Chk list_mxda = RIFF::BeginChunk(f, RIFF::LIST);
WriteU32(os, RIFF::MxDa);
f->WriteU32(RIFF::MxDa);
// First, interleave headers
std::vector<Object*> objects;
@ -388,79 +388,79 @@ Interleaf::Error Interleaf::Write(std::ostream &os) const
objects.push_back(static_cast<Object*>(child->GetChildAt(j)));
}
InterleaveObjects(os, objects);
InterleaveObjects(f, objects);
RIFF::EndChunk(os, list_mxda);
RIFF::EndChunk(f, list_mxda);
}
RIFF::EndChunk(os, mxst);
RIFF::EndChunk(f, mxst);
}
// Fill remainder with padding
if (os.tellp()%m_BufferSize != 0) {
uint32_t current_buf = os.tellp() / m_BufferSize;
if (f->pos()%m_BufferSize != 0) {
uint32_t current_buf = f->pos() / m_BufferSize;
uint32_t target_sz = (current_buf + 1) * m_BufferSize;
WritePadding(os, target_sz - os.tellp());
WritePadding(f, target_sz - f->pos());
}
RIFF::EndChunk(os, list_mxst);
RIFF::EndChunk(f, list_mxst);
}
RIFF::EndChunk(os, riff);
RIFF::EndChunk(f, riff);
return ERROR_SUCCESS;
}
void Interleaf::WriteObject(std::ostream &os, const Object *o) const
void Interleaf::WriteObject(FileBase *f, const Object *o) const
{
RIFF::Chk mxob = RIFF::BeginChunk(os, RIFF::MxOb);
RIFF::Chk mxob = RIFF::BeginChunk(f, RIFF::MxOb);
WriteU16(os, o->type_);
WriteString(os, o->presenter_);
WriteU32(os, o->unknown1_);
WriteString(os, o->name_);
WriteU32(os, o->id_);
WriteU32(os, o->flags_);
WriteU32(os, o->unknown4_);
WriteU32(os, o->duration_);
WriteU32(os, o->loops_);
WriteVector3(os, o->position_);
WriteVector3(os, o->direction_);
WriteVector3(os, o->up_);
f->WriteU16(o->type_);
f->WriteString(o->presenter_);
f->WriteU32(o->unknown1_);
f->WriteString(o->name_);
f->WriteU32(o->id_);
f->WriteU32(o->flags_);
f->WriteU32(o->unknown4_);
f->WriteU32(o->duration_);
f->WriteU32(o->loops_);
f->WriteVector3(o->position_);
f->WriteVector3(o->direction_);
f->WriteVector3(o->up_);
WriteU16(os, o->extra_.size());
WriteBytes(os, o->extra_);
f->WriteU16(o->extra_.size());
f->WriteBytes(o->extra_);
if (o->type_ != MxOb::Presenter && o->type_ != MxOb::World) {
WriteString(os, o->filename_);
WriteU32(os, o->unknown26_);
WriteU32(os, o->unknown27_);
WriteU32(os, o->unknown28_);
WriteU32(os, o->filetype_);
WriteU32(os, o->unknown29_);
WriteU32(os, o->unknown30_);
f->WriteString(o->filename_);
f->WriteU32(o->unknown26_);
f->WriteU32(o->unknown27_);
f->WriteU32(o->unknown28_);
f->WriteU32(o->filetype_);
f->WriteU32(o->unknown29_);
f->WriteU32(o->unknown30_);
if (o->filetype_ == MxOb::WAV) {
WriteU32(os, o->unknown31_);
f->WriteU32(o->unknown31_);
}
}
if (o->HasChildren()) {
// Child list
RIFF::Chk list_mxch = RIFF::BeginChunk(os, RIFF::LIST);
RIFF::Chk list_mxch = RIFF::BeginChunk(f, RIFF::LIST);
WriteU32(os, RIFF::MxCh);
WriteU32(os, o->GetChildCount());
f->WriteU32(RIFF::MxCh);
f->WriteU32(o->GetChildCount());
for (size_t i = 0; i < o->GetChildCount(); i++) {
WriteObject(os, static_cast<Object*>(o->GetChildAt(i)));
WriteObject(f, static_cast<Object*>(o->GetChildAt(i)));
}
RIFF::EndChunk(os, list_mxch);
RIFF::EndChunk(f, list_mxch);
}
RIFF::EndChunk(os, mxob);
RIFF::EndChunk(f, mxob);
}
struct ChunkStatus
@ -481,7 +481,7 @@ bool HasChildrenThatNeedPriority(Object *parent, uint32_t parent_time, const std
return false;
}
void Interleaf::InterleaveObjects(std::ostream &os, const std::vector<Object *> &objects) const
void Interleaf::InterleaveObjects(FileBase *f, const std::vector<Object *> &objects) const
{
std::vector<ChunkStatus> status(objects.size());
@ -497,7 +497,7 @@ void Interleaf::InterleaveObjects(std::ostream &os, const std::vector<Object *>
ChunkStatus &s = status[i];
Object *o = s.object;
if (!o->data().empty()) {
WriteSubChunk(os, 0, o->id(), 0xFFFFFFFF, o->data().front());
WriteSubChunk(f, 0, o->id(), 0xFFFFFFFF, o->data().front());
s.index++;
}
}
@ -528,7 +528,7 @@ void Interleaf::InterleaveObjects(std::ostream &os, const std::vector<Object *>
}
if (s->index == s->object->data_.size()) {
WriteSubChunk(os, MxCh::FLAG_END, s->object->id(), s->time);
WriteSubChunk(f, MxCh::FLAG_END, s->object->id(), s->time);
status.erase(s);
continue;
}
@ -536,7 +536,7 @@ void Interleaf::InterleaveObjects(std::ostream &os, const std::vector<Object *>
Object *obj = s->object;
const bytearray &data = obj->data().at(s->index);
WriteSubChunk(os, 0, obj->id(), s->time, data);
WriteSubChunk(f, 0, obj->id(), s->time, data);
s->index++;
@ -583,7 +583,7 @@ void Interleaf::InterleaveObjects(std::ostream &os, const std::vector<Object *>
}
}
void Interleaf::WriteSubChunk(std::ostream &os, uint16_t flags, uint32_t object, uint32_t time, const bytearray &data) const
void Interleaf::WriteSubChunk(FileBase *f, uint16_t flags, uint32_t object, uint32_t time, const bytearray &data) const
{
static const uint32_t total_hdr = MxCh::HEADER_SIZE + kMinimumChunkSize;
@ -593,20 +593,20 @@ void Interleaf::WriteSubChunk(std::ostream &os, uint16_t flags, uint32_t object,
uint32_t data_sz = data.size() - data_offset;
// Calculate whether this chunk will overrun the buffer
uint32_t start_buffer = os.tellp() / m_BufferSize;
uint32_t stop_buffer = (uint32_t(os.tellp()) - 1 + data_sz + total_hdr) / m_BufferSize;
uint32_t start_buffer = f->pos() / m_BufferSize;
uint32_t stop_buffer = (uint32_t(f->pos()) - 1 + data_sz + total_hdr) / m_BufferSize;
size_t max_chunk = data_sz;
if (start_buffer != stop_buffer) {
size_t remaining = ((start_buffer + 1) * m_BufferSize) - os.tellp();
size_t remaining = ((start_buffer + 1) * m_BufferSize) - f->pos();
max_chunk = remaining - total_hdr;
if (!(flags & MxCh::FLAG_SPLIT)) {
if (remaining < 9882) {
// This chunk won't fit in our buffer alignment. We must make a decision to either insert
// padding or split the clip.
WritePadding(os, remaining);
WritePadding(f, remaining);
// Do loop over again
continue;
@ -617,7 +617,7 @@ void Interleaf::WriteSubChunk(std::ostream &os, uint16_t flags, uint32_t object,
}
bytearray chunk = data.mid(data_offset, max_chunk);
WriteSubChunkInternal(os, flags, object, time, data_sz, chunk);
WriteSubChunkInternal(f, flags, object, time, data_sz, chunk);
data_offset += chunk.size();
if (data.size() == 0) {
@ -626,20 +626,20 @@ void Interleaf::WriteSubChunk(std::ostream &os, uint16_t flags, uint32_t object,
}
}
void Interleaf::WriteSubChunkInternal(std::ostream &os, uint16_t flags, uint32_t object, uint32_t time, uint32_t data_sz, const bytearray &data) const
void Interleaf::WriteSubChunkInternal(FileBase *f, uint16_t flags, uint32_t object, uint32_t time, uint32_t data_sz, const bytearray &data) const
{
RIFF::Chk mxch = RIFF::BeginChunk(os, RIFF::MxCh);
RIFF::Chk mxch = RIFF::BeginChunk(f, RIFF::MxCh);
WriteU16(os, flags);
WriteU32(os, object);
WriteU32(os, time);
WriteU32(os, data_sz);
WriteBytes(os, data);
f->WriteU16(flags);
f->WriteU32(object);
f->WriteU32(time);
f->WriteU32(data_sz);
f->WriteBytes(data);
RIFF::EndChunk(os, mxch);
RIFF::EndChunk(f, mxch);
}
void Interleaf::WritePadding(std::ostream &os, uint32_t size) const
void Interleaf::WritePadding(FileBase *f, uint32_t size) const
{
if (size < kMinimumChunkSize) {
return;
@ -647,12 +647,12 @@ void Interleaf::WritePadding(std::ostream &os, uint32_t size) const
size -= kMinimumChunkSize;
WriteU32(os, RIFF::pad_);
WriteU32(os, size);
f->WriteU32(RIFF::pad_);
f->WriteU32(size);
bytearray b(size);
b.fill(0xCD);
WriteBytes(os, b);
f->WriteBytes(b);
}
}

View file

@ -4,6 +4,7 @@
#include <fstream>
#include "core.h"
#include "file.h"
#include "info.h"
#include "object.h"
@ -32,24 +33,23 @@ public:
LIBWEAVER_EXPORT Error Write(const wchar_t *f) const;
#endif
Error Read(std::istream &is);
Error Write(std::ostream &os) const;
Error Read(FileBase *is);
Error Write(FileBase *os) const;
Info *GetInformation() { return &m_Info; }
private:
Error ReadChunk(Core *parent, FileBase *f, Info *info);
Error ReadChunk(Core *parent, std::istream &is, Info *info);
Object *ReadObject(FileBase *f, Object *o, std::stringstream &desc);
void WriteObject(FileBase *f, const Object *o) const;
Object *ReadObject(std::istream &is, Object *o, std::stringstream &desc);
void WriteObject(std::ostream &os, const Object *o) const;
void InterleaveObjects(FileBase *f, const std::vector<Object*> &objects) const;
void InterleaveObjects(std::ostream &os, const std::vector<Object*> &objects) const;
void WriteSubChunk(FileBase *f, uint16_t flags, uint32_t object, uint32_t time, const bytearray &data = bytearray()) const;
void WriteSubChunkInternal(FileBase *f, uint16_t flags, uint32_t object, uint32_t time, uint32_t data_sz, const bytearray &data) const;
void WriteSubChunk(std::ostream &os, uint16_t flags, uint32_t object, uint32_t time, const bytearray &data = bytearray()) const;
void WriteSubChunkInternal(std::ostream &os, uint16_t flags, uint32_t object, uint32_t time, uint32_t data_sz, const bytearray &data) const;
void WritePadding(std::ostream &os, uint32_t size) const;
void WritePadding(FileBase *f, uint32_t size) const;
Info m_Info;

View file

@ -16,73 +16,71 @@ Object::Object()
#ifdef _WIN32
bool Object::ReplaceWithFile(const wchar_t *f)
{
std::ifstream is(f);
if (!is.is_open() || !is.good()) {
File is;
if (!is.Open(f, File::Read)) {
return false;
}
return ReplaceWithFile(is);
return ReplaceWithFile(&is);
}
bool Object::ExtractToFile(const wchar_t *f) const
{
std::ofstream os(f);
if (!os.is_open() || !os.good()) {
File os;
if (!os.Open(f, File::Write)) {
return false;
}
return ExtractToFile(os);
return ExtractToFile(&os);
}
#endif
bool Object::ReplaceWithFile(const char *f)
{
std::ifstream is(f);
if (!is.is_open() || !is.good()) {
File is;
if (!is.Open(f, File::Read)) {
return false;
}
return ReplaceWithFile(is);
return ReplaceWithFile(&is);
}
bool Object::ExtractToFile(const char *f) const
{
std::ofstream os(f);
if (!os.is_open() || !os.good()) {
File os;
if (!os.Open(f, File::Write)) {
return false;
}
return ExtractToFile(os);
return ExtractToFile(&os);
}
bool Object::ReplaceWithFile(std::istream &is)
bool Object::ReplaceWithFile(FileBase *f)
{
data_.clear();
switch (this->filetype()) {
case MxOb::WAV:
{
if (ReadU32(is) != RIFF::RIFF_) {
if (f->ReadU32() != RIFF::RIFF_) {
return false;
}
// Skip total size
ReadU32(is);
f->ReadU32();
if (ReadU32(is) != RIFF::WAVE) {
if (f->ReadU32() != RIFF::WAVE) {
return false;
}
bytearray fmt;
bytearray data;
while (is.good()) {
uint32_t id = ReadU32(is);
uint32_t sz = ReadU32(is);
while (!f->atEnd()) {
uint32_t id = f->ReadU32();
uint32_t sz = f->ReadU32();
if (id == RIFF::fmt_) {
fmt.resize(sz);
is.read(fmt.data(), fmt.size());
fmt = f->ReadBytes(sz);
} else if (id == RIFF::data) {
data.resize(sz);
is.read(data.data(), data.size());
data = f->ReadBytes(sz);
} else {
is.seekg(sz, std::ios::cur);
f->seek(sz, File::SeekCurrent);
}
}
@ -104,24 +102,18 @@ bool Object::ReplaceWithFile(std::istream &is)
case MxOb::SMK:
{
// Read header
bytearray hdr(sizeof(SMK2));
is.read(hdr.data(), hdr.size());
bytearray hdr = f->ReadBytes(sizeof(SMK2));
// Read frame sizes
SMK2 smk = *hdr.cast<SMK2>();
bytearray frame_sizes(smk.Frames * sizeof(uint32_t));
is.read(frame_sizes.data(), frame_sizes.size());
bytearray frame_sizes = f->ReadBytes(smk.Frames * sizeof(uint32_t));
hdr.append(frame_sizes);
// Read frame types
bytearray frame_types(smk.Frames);
is.read(frame_types.data(), frame_types.size());
hdr.append(frame_types);
hdr.append(f->ReadBytes(smk.Frames));
// Read Huffman trees
bytearray huffman(smk.TreesSize);
is.read(huffman.data(), huffman.size());
hdr.append(huffman);
hdr.append(f->ReadBytes(smk.TreesSize));
// Place header into data vector
data_.resize(smk.Frames + 1);
@ -131,9 +123,7 @@ bool Object::ReplaceWithFile(std::istream &is)
for (uint32_t i=0; i<smk.Frames; i++) {
uint32_t sz = real_sizes[i];
if (sz > 0) {
bytearray &d = data_[i+1];
d.resize(sz);
is.read(d.data(), d.size());
data_[i+1] = f->ReadBytes(sz);
}
}
return true;
@ -146,34 +136,34 @@ bool Object::ReplaceWithFile(std::istream &is)
return false;
}
bool Object::ExtractToFile(std::ostream &os) const
bool Object::ExtractToFile(FileBase *f) const
{
switch (this->filetype()) {
case MxOb::WAV:
{
// Write RIFF header
RIFF::Chk riff = RIFF::BeginChunk(os, RIFF::RIFF_);
RIFF::Chk riff = RIFF::BeginChunk(f, RIFF::RIFF_);
WriteU32(os, RIFF::WAVE);
f->WriteU32(RIFF::WAVE);
{
RIFF::Chk fmt = RIFF::BeginChunk(os, RIFF::fmt_);
RIFF::Chk fmt = RIFF::BeginChunk(f, RIFF::fmt_);
WriteBytes(os, data_.at(0));
f->WriteBytes(data_.at(0));
RIFF::EndChunk(os, fmt);
RIFF::EndChunk(f, fmt);
}
{
RIFF::Chk data = RIFF::BeginChunk(os, RIFF::data);
RIFF::Chk data = RIFF::BeginChunk(f, RIFF::data);
// Merge all chunks after the first one
for (size_t i=1; i<data_.size(); i++) {
WriteBytes(os, data_.at(i));
f->WriteBytes(data_.at(i));
}
RIFF::EndChunk(os, data);
RIFF::EndChunk(f, data);
}
RIFF::EndChunk(os, riff);
RIFF::EndChunk(f, riff);
break;
}
case MxOb::STL:
@ -181,36 +171,36 @@ bool Object::ExtractToFile(std::ostream &os) const
static const uint32_t BMP_HDR_SZ = 14;
// Write BMP header
WriteU16(os, 0x4D42);
f->WriteU16(0x4D42);
// Write placeholder for size
std::ios::pos_type sz_loc = os.tellp();
WriteU32(os, 0);
size_t sz_loc = f->pos();
f->WriteU32(0);
// Write "reserved" bytes
WriteU32(os, 0);
f->WriteU32(0);
// Write data offset
WriteU32(os, data_.at(0).size() + BMP_HDR_SZ);
f->WriteU32(data_.at(0).size() + BMP_HDR_SZ);
for (size_t i=0; i<data_.size(); i++) {
WriteBytes(os, data_.at(i));
f->WriteBytes(data_.at(i));
}
std::ios::pos_type len = os.tellp();
os.seekp(sz_loc);
WriteU32(os, len);
size_t len = f->pos();
f->seek(sz_loc);
f->WriteU32(len);
break;
}
case MxOb::FLC:
{
// First chunk is a complete FLIC header, so add it as-is
WriteBytes(os, data_.at(0));
f->WriteBytes(data_.at(0));
// Subsequent chunks are FLIC frames with an additional 20 byte header that needs to be stripped
const int CUSTOM_HEADER_SZ = 20;
for (size_t i=1; i<data_.size(); i++) {
os.write(data_.at(i).data() + CUSTOM_HEADER_SZ, data_.at(i).size() - CUSTOM_HEADER_SZ);
f->WriteData(data_.at(i).data() + CUSTOM_HEADER_SZ, data_.at(i).size() - CUSTOM_HEADER_SZ);
}
break;
}
@ -221,7 +211,7 @@ bool Object::ExtractToFile(std::ostream &os) const
case MxOb::OBJ:
// Simply merge
for (size_t i=0; i<data_.size(); i++) {
WriteBytes(os, data_.at(i));
f->WriteBytes(data_.at(i));
}
break;
}
@ -231,10 +221,9 @@ bool Object::ExtractToFile(std::ostream &os) const
bytearray Object::ExtractToMemory() const
{
memorybuf buf;
std::ostream os(&buf);
MemoryBuffer buf;
ExtractToFile(os);
ExtractToFile(&buf);
return buf.data();
}

View file

@ -22,8 +22,8 @@ public:
LIBWEAVER_EXPORT bool ReplaceWithFile(const char *f);
LIBWEAVER_EXPORT bool ExtractToFile(const char *f) const;
LIBWEAVER_EXPORT bool ReplaceWithFile(std::istream &is);
LIBWEAVER_EXPORT bool ExtractToFile(std::ostream &os) const;
LIBWEAVER_EXPORT bool ReplaceWithFile(FileBase *f);
LIBWEAVER_EXPORT bool ExtractToFile(FileBase *f) const;
LIBWEAVER_EXPORT bytearray ExtractToMemory() const;

View file

@ -92,32 +92,31 @@ const char *RIFF::GetTypeDescription(Type t)
return "Unknown";
}
RIFF::Chk RIFF::BeginChunk(std::ostream &os, uint32_t type)
RIFF::Chk RIFF::BeginChunk(FileBase *f, uint32_t type)
{
Chk stat;
WriteU32(os, type);
stat.size_position = os.tellp();
WriteU32(os, 0);
stat.data_start = os.tellp();
f->WriteU32(type);
stat.size_position = f->pos();
f->WriteU32(0);
stat.data_start = f->pos();
return stat;
}
void RIFF::EndChunk(std::ostream &os, const Chk &stat)
void RIFF::EndChunk(FileBase *f, const Chk &stat)
{
std::ios::pos_type now = os.tellp();
std::ios::pos_type now = f->pos();
uint32_t sz = now - stat.data_start;
os.seekp(stat.size_position);
WriteU32(os, sz);
f->seek(stat.size_position);
f->WriteU32(sz);
os.seekp(now);
f->seek(now);
if (sz%2 == 1) {
char nullterm = 0;
os.write(&nullterm, 1);
f->WriteU8(0);
}
}

View file

@ -3,6 +3,7 @@
#include <fstream>
#include "file.h"
#include "types.h"
namespace si {
@ -39,8 +40,8 @@ public:
std::ios::pos_type data_start;
};
static Chk BeginChunk(std::ostream &os, uint32_t type);
static void EndChunk(std::ostream &os, const Chk &stat);
static Chk BeginChunk(FileBase *f, uint32_t type);
static void EndChunk(FileBase *f, const Chk &stat);
static inline std::string PrintU32AsString(uint32_t u)
{

View file

@ -120,27 +120,6 @@ public:
};
class memorybuf : public std::streambuf
{
public:
memorybuf(){}
virtual int_type overflow(int_type c)
{
if (c != EOF) {
char c2 = c;
m_Internal.append(&c2, 1);
}
return c;
}
const bytearray &data() const { return m_Internal; }
private:
bytearray m_Internal;
};
class Vector3
{
public:

View file

@ -8,94 +8,6 @@
namespace si {
inline uint32_t ReadU32(std::istream &is)
{
uint32_t u;
is.read((char *) &u, sizeof(u));
return u;
}
inline void WriteU32(std::ostream &os, uint32_t u)
{
os.write((const char *) &u, sizeof(u));
}
inline uint16_t ReadU16(std::istream &is)
{
uint16_t u;
is.read((char *) &u, sizeof(u));
return u;
}
inline void WriteU16(std::ostream &os, uint16_t u)
{
os.write((const char *) &u, sizeof(u));
}
inline uint8_t ReadU8(std::istream &is)
{
uint8_t u;
is.read((char *) &u, sizeof(u));
return u;
}
inline void WriteU8(std::ostream &os, uint8_t u)
{
os.write((const char *) &u, sizeof(u));
}
inline Vector3 ReadVector3(std::istream &is)
{
Vector3 u;
is.read((char *) &u, sizeof(u));
return u;
}
inline void WriteVector3(std::ostream &os, Vector3 v)
{
os.write((const char *) &v, sizeof(v));
}
inline std::string ReadString(std::istream &is)
{
std::string d;
while (true) {
char c;
is.read(&c, 1);
if (c == 0) {
break;
}
d.push_back(c);
}
return d;
}
inline void WriteString(std::ostream &os, const std::string &d)
{
os.write(d.c_str(), d.size());
// Ensure null terminator
const char nullterm = 0;
os.write(&nullterm, 1);
}
inline bytearray ReadBytes(std::istream &is, size_t size)
{
bytearray d;
d.resize(size);
is.read(d.data(), size);
return d;
}
inline void WriteBytes(std::ostream &os, const bytearray &ba)
{
os.write(ba.data(), ba.size());
}
inline std::ostream &LogDebug()
{
return std::cout << "[DEBUG] ";