mirror of
https://github.com/isledecomp/SIEdit.git
synced 2025-02-17 00:40:42 -05:00
lib: implement abstract file handler
This commit is contained in:
parent
180ead8188
commit
1ab22fd85c
11 changed files with 565 additions and 345 deletions
|
@ -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
234
lib/file.cpp
Normal 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
104
lib/file.h
Normal 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
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
113
lib/object.cpp
113
lib/object.cpp
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
21
lib/types.h
21
lib/types.h
|
@ -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:
|
||||
|
|
88
lib/util.h
88
lib/util.h
|
@ -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] ";
|
||||
|
|
Loading…
Reference in a new issue