mirror of
https://github.com/isledecomp/SIEdit.git
synced 2024-11-27 01:25:45 -05:00
start test changes
This commit is contained in:
parent
a976634681
commit
0a76066185
14 changed files with 509 additions and 752 deletions
|
@ -4,20 +4,20 @@ find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets Multimedia)
|
|||
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets Multimedia)
|
||||
|
||||
set(PROJECT_SOURCES
|
||||
siview/chunkmodel.cpp
|
||||
siview/chunkmodel.h
|
||||
siview/panels/mxch.cpp
|
||||
siview/panels/mxch.h
|
||||
siview/panels/mxhd.cpp
|
||||
siview/panels/mxhd.h
|
||||
siview/panels/mxob.cpp
|
||||
siview/panels/mxob.h
|
||||
siview/panels/mxof.cpp
|
||||
siview/panels/mxof.h
|
||||
siview/panels/riff.cpp
|
||||
siview/panels/riff.h
|
||||
siview/siview.cpp
|
||||
siview/siview.h
|
||||
# siview/chunkmodel.cpp
|
||||
# siview/chunkmodel.h
|
||||
# siview/panels/mxch.cpp
|
||||
# siview/panels/mxch.h
|
||||
# siview/panels/mxhd.cpp
|
||||
# siview/panels/mxhd.h
|
||||
# siview/panels/mxob.cpp
|
||||
# siview/panels/mxob.h
|
||||
# siview/panels/mxof.cpp
|
||||
# siview/panels/mxof.h
|
||||
# siview/panels/riff.cpp
|
||||
# siview/panels/riff.h
|
||||
# siview/siview.cpp
|
||||
# siview/siview.h
|
||||
|
||||
viewer/bitmappanel.cpp
|
||||
viewer/bitmappanel.h
|
||||
|
@ -52,7 +52,9 @@ endif()
|
|||
|
||||
target_link_libraries(si-edit PRIVATE Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::Multimedia libweaver)
|
||||
target_include_directories(si-edit PRIVATE "${CMAKE_SOURCE_DIR}/lib")
|
||||
target_compile_options(si-edit PRIVATE -Werror)
|
||||
if (NOT MSVC)
|
||||
target_compile_options(si-edit PRIVATE -Werror)
|
||||
endif()
|
||||
|
||||
set_target_properties(si-edit PROPERTIES
|
||||
MACOSX_BUNDLE_GUI_IDENTIFIER com.mattkc.SIEdit
|
||||
|
|
|
@ -6,8 +6,6 @@
|
|||
#include <QMessageBox>
|
||||
#include <QSplitter>
|
||||
|
||||
#include "siview/siview.h"
|
||||
|
||||
using namespace si;
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent) :
|
||||
|
@ -67,14 +65,18 @@ MainWindow::MainWindow(QWidget *parent) :
|
|||
|
||||
void MainWindow::OpenFilename(const QString &s)
|
||||
{
|
||||
Chunk si;
|
||||
if (si.Read(s.toStdString())) {
|
||||
SIViewDialog d(SIViewDialog::Import, &si, this);
|
||||
if (d.exec() == QDialog::Accepted) {
|
||||
model_.SetCore(nullptr);
|
||||
interleaf_.Parse(&si);
|
||||
|
||||
bool r =
|
||||
#ifdef Q_OS_WINDOWS
|
||||
interleaf_.Read(s.toStdWString().c_str());
|
||||
#else
|
||||
interleaf_.Read(s.toUtf8());
|
||||
#endif
|
||||
;
|
||||
|
||||
if (r) {
|
||||
model_.SetCore(&interleaf_);
|
||||
}
|
||||
} else {
|
||||
QMessageBox::critical(this, QString(), tr("Failed to load Interleaf file."));
|
||||
}
|
||||
|
@ -155,17 +157,6 @@ void MainWindow::OpenFile()
|
|||
|
||||
void MainWindow::ExportFile()
|
||||
{
|
||||
Chunk *c = interleaf_.Export();
|
||||
SIViewDialog d(SIViewDialog::Export, c, this);
|
||||
if (d.exec() == QDialog::Accepted) {
|
||||
QString s = QFileDialog::getSaveFileName(this);
|
||||
if (!s.isEmpty()) {
|
||||
if (!c->Write(s.toStdString())) {
|
||||
QMessageBox::critical(this, QString(), tr("Failed to write SI file."));
|
||||
}
|
||||
}
|
||||
}
|
||||
delete c;
|
||||
}
|
||||
|
||||
void MainWindow::SelectionChanged(const QModelIndex &index)
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
option(LIBWEAVER_BUILD_DOXYGEN "Build Doxygen documentation" OFF)
|
||||
|
||||
set(LIBWEAVER_SOURCES
|
||||
chunk.cpp
|
||||
chunk.h
|
||||
common.h
|
||||
core.cpp
|
||||
core.h
|
||||
|
@ -13,6 +11,7 @@ set(LIBWEAVER_SOURCES
|
|||
sitypes.cpp
|
||||
sitypes.h
|
||||
types.h
|
||||
util.h
|
||||
)
|
||||
|
||||
add_library(libweaver SHARED
|
||||
|
@ -20,7 +19,9 @@ add_library(libweaver SHARED
|
|||
)
|
||||
|
||||
target_compile_definitions(libweaver PRIVATE LIBWEAVER_LIBRARY)
|
||||
target_compile_options(libweaver PRIVATE -Werror -Wall -Wextra -Wno-unused-parameter)
|
||||
if (NOT MSVC)
|
||||
target_compile_options(libweaver PRIVATE -Werror -Wall -Wextra -Wno-unused-parameter)
|
||||
endif()
|
||||
set_target_properties(libweaver PROPERTIES
|
||||
CXX_STANDARD 98
|
||||
CXX_STANDARD_REQUIRED ON
|
||||
|
|
264
lib/chunk.cpp
264
lib/chunk.cpp
|
@ -1,264 +0,0 @@
|
|||
#include "chunk.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
|
||||
#include "sitypes.h"
|
||||
|
||||
namespace si {
|
||||
|
||||
Chunk::Chunk(uint32_t id) :
|
||||
id_(id),
|
||||
offset_(0)
|
||||
{
|
||||
}
|
||||
|
||||
Chunk::~Chunk()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
bool Chunk::Read(const std::string &f)
|
||||
{
|
||||
return Read(f.c_str());
|
||||
}
|
||||
|
||||
bool Chunk::Read(const char *f)
|
||||
{
|
||||
std::ifstream file(f, std::ios::in | std::ios::binary);
|
||||
if (!file.is_open() || !file.good()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t alignment = 0, version = 0;
|
||||
|
||||
return Read(file, version, alignment);
|
||||
}
|
||||
|
||||
bool Chunk::Read(std::ifstream &f, uint32_t &version, uint32_t &alignment)
|
||||
{
|
||||
uint32_t size;
|
||||
|
||||
offset_ = uint32_t(f.tellg());
|
||||
|
||||
// Read ID and size, which every chunk starts with
|
||||
f.read((char *) &id_, sizeof(id_));
|
||||
f.read((char *) &size, sizeof(size));
|
||||
|
||||
// Store end of this chunk
|
||||
uint32_t pos = uint32_t(f.tellg());
|
||||
uint32_t end = pos + size;
|
||||
|
||||
// Read custom data from this chunk
|
||||
Clear();
|
||||
|
||||
if (RIFF *reader = GetReaderFromType(type())) {
|
||||
reader->Read(f, data_, version, size);
|
||||
|
||||
if (type() == TYPE_MxHd) {
|
||||
version = data_["Version"];
|
||||
alignment = data_["BufferSize"];
|
||||
}
|
||||
|
||||
delete reader;
|
||||
}
|
||||
|
||||
// Assume any remaining data is this chunk's children
|
||||
while (f.good() && (size_t(f.tellg()) + 4) < end) {
|
||||
// Check alignment, if there's not enough room to for another segment, skip ahead
|
||||
if (alignment > 0) {
|
||||
uint32_t offset_in_buffer = f.tellg()%alignment;
|
||||
if (offset_in_buffer + sizeof(uint32_t)*2 > alignment) {
|
||||
f.seekg(alignment-offset_in_buffer, std::ios::cur);
|
||||
}
|
||||
}
|
||||
|
||||
Chunk *child = new Chunk();
|
||||
child->Read(f, version, alignment);
|
||||
this->AppendChild(child);
|
||||
}
|
||||
|
||||
if (f.tellg() < end) {
|
||||
f.seekg(end, std::ios::beg);
|
||||
}
|
||||
|
||||
if (size%2 == 1) {
|
||||
f.seekg(1, std::ios::cur);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Chunk::Write(std::ofstream &f, uint32_t &version, uint32_t &alignment) const
|
||||
{
|
||||
RIFF *writer = GetReaderFromType(type());
|
||||
|
||||
if (alignment != 0) {
|
||||
// Determine if we have enough space left to write this chunk without the alignment
|
||||
size_t expected_write = 8;
|
||||
for (DataMap::const_iterator it=data_.begin(); it!=data_.end(); it++) {
|
||||
expected_write += it->second.size();
|
||||
}
|
||||
|
||||
size_t start_chunk = f.tellp()/alignment;
|
||||
size_t end_chunk = (size_t(f.tellp())+expected_write)/alignment;
|
||||
if (start_chunk != end_chunk) {
|
||||
// This chunk is going to cross a boundary. We could write padding or split the chunk.
|
||||
// I'm not exactly sure how Weaver decides which, but I suppose it doesn't matter.
|
||||
size_t diff = (end_chunk * alignment) - f.tellp();
|
||||
pad_::WriteArbitraryPadding(f, diff - 8);
|
||||
/*if (id_ != Chunk::TYPE_MxCh || diff < 0x200) {
|
||||
// Make padding
|
||||
pad_::WriteArbitraryPadding(f, diff - 8);
|
||||
} else {
|
||||
// Attempt to split chunk
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
// Write 4-byte ID
|
||||
f.write((const char *) &id_, sizeof(id_));
|
||||
|
||||
// Write placeholder for size and store position so we can come back later
|
||||
uint32_t chunk_size = 0;
|
||||
std::ios::pos_type size_pos = f.tellp();
|
||||
f.write((const char *) &chunk_size, sizeof(chunk_size));
|
||||
|
||||
if (writer) {
|
||||
writer->Write(f, data_, version);
|
||||
|
||||
if (type() == TYPE_MxHd) {
|
||||
version = data_.at("Version");
|
||||
alignment = data_.at("BufferSize");
|
||||
}
|
||||
|
||||
delete writer;
|
||||
}
|
||||
|
||||
for (Children::const_iterator it=GetChildren().begin(); it!=GetChildren().end(); it++) {
|
||||
static_cast<Chunk*>(*it)->Write(f, version, alignment);
|
||||
}
|
||||
|
||||
// Backtrack and write chunk size
|
||||
chunk_size = uint32_t(f.tellp()) - (uint32_t(size_pos) + sizeof(uint32_t));
|
||||
f.seekp(size_pos);
|
||||
f.write((const char *) &chunk_size, sizeof(chunk_size));
|
||||
f.seekp(0, std::ios::end);
|
||||
|
||||
// Byte align to 2
|
||||
if (chunk_size%2 == 1) {
|
||||
const char nothing = 0;
|
||||
f.write(¬hing, 1);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
RIFF *Chunk::GetReaderFromType(Type type)
|
||||
{
|
||||
switch (type) {
|
||||
case TYPE_RIFF:
|
||||
return new RIFF();
|
||||
case TYPE_MxHd:
|
||||
return new MxHd();
|
||||
case TYPE_LIST:
|
||||
return new LIST();
|
||||
case TYPE_MxSt:
|
||||
return new MxSt();
|
||||
case TYPE_MxCh:
|
||||
return new MxCh();
|
||||
case TYPE_MxOf:
|
||||
return new MxOf();
|
||||
case TYPE_pad_:
|
||||
return new pad_();
|
||||
case TYPE_MxOb:
|
||||
return new MxOb();
|
||||
case TYPE_MxDa:
|
||||
break;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void Chunk::Clear()
|
||||
{
|
||||
// Delete data
|
||||
data_.clear();
|
||||
|
||||
// Delete children
|
||||
DeleteChildren();
|
||||
}
|
||||
|
||||
bool Chunk::Write(const std::string &f)
|
||||
{
|
||||
return Write(f.c_str());
|
||||
}
|
||||
|
||||
bool Chunk::Write(const char *f)
|
||||
{
|
||||
std::ofstream file(f, std::ios::out | std::ios::binary);
|
||||
if (!file.is_open() || !file.good()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t version = 0, alignment = 0;
|
||||
|
||||
return Write(file, version, alignment);
|
||||
}
|
||||
|
||||
const char *Chunk::GetTypeDescription(Type type)
|
||||
{
|
||||
switch (type) {
|
||||
case TYPE_RIFF:
|
||||
return "Resource Interchange File Format";
|
||||
case TYPE_LIST:
|
||||
return "List of sub-elements";
|
||||
case TYPE_MxSt:
|
||||
return "Stream";
|
||||
case TYPE_MxHd:
|
||||
return "Interleaf Header";
|
||||
case TYPE_MxCh:
|
||||
return "Data Chunk";
|
||||
case TYPE_MxOf:
|
||||
return "Offset Table";
|
||||
case TYPE_pad_:
|
||||
return "Padding";
|
||||
case TYPE_MxOb:
|
||||
return "Streamable Object";
|
||||
case TYPE_MxDa:
|
||||
return "Data";
|
||||
}
|
||||
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
Chunk *Chunk::FindChildWithType(Type type) const
|
||||
{
|
||||
for (Children::const_iterator it=GetChildren().begin(); it!=GetChildren().end(); it++) {
|
||||
Chunk *chunk = static_cast<Chunk*>(*it);
|
||||
if (chunk->type() == type) {
|
||||
return chunk;
|
||||
} else if (Chunk *grandchild = chunk->FindChildWithType(type)) {
|
||||
return grandchild;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Chunk *Chunk::FindChildWithOffset(uint32_t offset) const
|
||||
{
|
||||
for (Children::const_iterator it=GetChildren().begin(); it!=GetChildren().end(); it++) {
|
||||
Chunk *chunk = static_cast<Chunk*>(*it);
|
||||
if (chunk->offset() == offset) {
|
||||
return chunk;
|
||||
} else if (Chunk *grandchild = chunk->FindChildWithOffset(offset)) {
|
||||
return grandchild;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
}
|
71
lib/chunk.h
71
lib/chunk.h
|
@ -1,71 +0,0 @@
|
|||
#ifndef CHUNK_H
|
||||
#define CHUNK_H
|
||||
|
||||
#include <fstream>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
#include "common.h"
|
||||
#include "core.h"
|
||||
#include "sitypes.h"
|
||||
#include "types.h"
|
||||
|
||||
namespace si {
|
||||
|
||||
class Chunk : public Core
|
||||
{
|
||||
public:
|
||||
enum Type
|
||||
{
|
||||
TYPE_RIFF = 0x46464952,
|
||||
TYPE_LIST = 0x5453494c,
|
||||
TYPE_MxSt = 0x7453784d,
|
||||
TYPE_MxHd = 0x6448784d,
|
||||
TYPE_MxCh = 0x6843784d,
|
||||
TYPE_MxOf = 0x664f784d,
|
||||
TYPE_MxOb = 0x624f784d,
|
||||
TYPE_MxDa = 0x6144784d,
|
||||
TYPE_pad_ = 0x20646170
|
||||
};
|
||||
|
||||
LIBWEAVER_EXPORT Chunk(uint32_t id = 0);
|
||||
virtual LIBWEAVER_EXPORT ~Chunk();
|
||||
|
||||
LIBWEAVER_EXPORT bool Read(const std::string &f);
|
||||
LIBWEAVER_EXPORT bool Read(const char *f);
|
||||
LIBWEAVER_EXPORT void Clear();
|
||||
|
||||
LIBWEAVER_EXPORT bool Write(const std::string &f);
|
||||
LIBWEAVER_EXPORT bool Write(const char *f);
|
||||
|
||||
LIBWEAVER_EXPORT Type type() const { return static_cast<Type>(id_); }
|
||||
LIBWEAVER_EXPORT const uint32_t &id() const { return id_; }
|
||||
LIBWEAVER_EXPORT const uint32_t &offset() const { return offset_; }
|
||||
|
||||
LIBWEAVER_EXPORT Data &data(const std::string &key) { return data_[key]; }
|
||||
LIBWEAVER_EXPORT Data data(const std::string &key) const { return data_.at(key); }
|
||||
|
||||
LIBWEAVER_EXPORT static const char *GetTypeDescription(Type type);
|
||||
LIBWEAVER_EXPORT const char *GetTypeDescription() const
|
||||
{
|
||||
return GetTypeDescription(type());
|
||||
}
|
||||
|
||||
LIBWEAVER_EXPORT Chunk *FindChildWithType(Type type) const;
|
||||
LIBWEAVER_EXPORT Chunk *FindChildWithOffset(uint32_t offset) const;
|
||||
|
||||
private:
|
||||
bool Read(std::ifstream &f, uint32_t &version, uint32_t &alignment);
|
||||
bool Write(std::ofstream &f, uint32_t &version, uint32_t &alignment) const;
|
||||
|
||||
static RIFF *GetReaderFromType(Type type);
|
||||
|
||||
uint32_t id_;
|
||||
uint32_t offset_;
|
||||
DataMap data_;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // CHUNK_H
|
|
@ -5,6 +5,8 @@
|
|||
|
||||
#include "object.h"
|
||||
#include "othertypes.h"
|
||||
#include "sitypes.h"
|
||||
#include "util.h"
|
||||
|
||||
namespace si {
|
||||
|
||||
|
@ -12,7 +14,247 @@ Interleaf::Interleaf()
|
|||
{
|
||||
}
|
||||
|
||||
bool Interleaf::Parse(Chunk *riff)
|
||||
void Interleaf::Clear()
|
||||
{
|
||||
m_BufferSize = 0;
|
||||
m_OffsetTable.clear();
|
||||
m_ObjectIndexTable.clear();
|
||||
DeleteChildren();
|
||||
}
|
||||
|
||||
bool Interleaf::Read(const char *f)
|
||||
{
|
||||
std::ifstream is(f);
|
||||
if (!is.is_open() || !is.good()) {
|
||||
return false;
|
||||
}
|
||||
return Read(is);
|
||||
}
|
||||
|
||||
bool Interleaf::Read(const wchar_t *f)
|
||||
{
|
||||
std::ifstream is(f);
|
||||
if (!is.is_open() || !is.good()) {
|
||||
return false;
|
||||
}
|
||||
return Read(is);
|
||||
}
|
||||
|
||||
/*bool Interleaf::Write(const char *f) const
|
||||
{
|
||||
std::ofstream os(f);
|
||||
if (!os.is_open() || !os.good()) {
|
||||
return false;
|
||||
}
|
||||
return Write(os);
|
||||
}
|
||||
|
||||
bool Interleaf::Write(const wchar_t *f) const
|
||||
{
|
||||
std::ofstream os(f);
|
||||
if (!os.is_open() || !os.good()) {
|
||||
return false;
|
||||
}
|
||||
return Write(os);
|
||||
}*/
|
||||
|
||||
inline std::string PrintU32AsString(uint32_t u)
|
||||
{
|
||||
return std::string((const char *) &u, sizeof(u));
|
||||
}
|
||||
|
||||
bool Interleaf::ReadChunk(Core *parent, std::ifstream &is)
|
||||
{
|
||||
uint32_t offset = is.tellg();
|
||||
uint32_t id = ReadU32(is);
|
||||
uint32_t size = ReadU32(is);
|
||||
uint32_t end = uint32_t(is.tellg()) + size;
|
||||
|
||||
std::cout << PrintU32AsString(id)
|
||||
<< " Offset: 0x" << std::hex << offset
|
||||
<< " Size: " << std::dec << size << std::endl;
|
||||
|
||||
switch (static_cast<SI::Type>(id)) {
|
||||
case SI::RIFF:
|
||||
{
|
||||
// Require RIFF type to be OMNI
|
||||
uint32_t riff_type = ReadU32(is);
|
||||
std::cout << " Type: " << PrintU32AsString(riff_type) << std::endl;
|
||||
if (riff_type != RIFF::OMNI) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SI::MxHd:
|
||||
{
|
||||
m_Version = ReadU32(is);
|
||||
std::cout << " Version: " << m_Version << std::endl;
|
||||
|
||||
m_BufferSize = ReadU32(is);
|
||||
std::cout << " Buffer Size: " << m_BufferSize << std::endl;
|
||||
|
||||
if (m_Version < 0x00020002) {
|
||||
m_BufferCount = ReadU32(is);
|
||||
std::cout << " Buffer Count: " << m_BufferCount << std::endl;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SI::pad_:
|
||||
is.seekg(size, std::ios::cur);
|
||||
break;
|
||||
case SI::MxOf:
|
||||
{
|
||||
m_OffsetCount = ReadU32(is);
|
||||
std::cout << " Count: " << m_OffsetCount << std::endl;
|
||||
|
||||
uint32_t i = 0;
|
||||
while (is.tellg() < end) {
|
||||
uint32_t offset = ReadU32(is);
|
||||
std::cout << " " << i << ": 0x" << std::hex << offset << std::endl;
|
||||
m_OffsetTable.push_back(offset);
|
||||
i++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SI::LIST:
|
||||
{
|
||||
uint32_t list_type = ReadU32(is);
|
||||
std::cout << " Type: " << PrintU32AsString(list_type) << std::endl;
|
||||
uint32_t list_count = 0;
|
||||
if (list_type == SI::MxCh) {
|
||||
list_count = ReadU32(is);
|
||||
std::cout << " Count: " << list_count << std::endl;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SI::MxSt:
|
||||
case SI::MxDa:
|
||||
// Types with no data
|
||||
break;
|
||||
case SI::MxOb:
|
||||
{
|
||||
Object *o = ReadObject(is);
|
||||
parent->AppendChild(o);
|
||||
m_ObjectIndexTable[o->id()] = o;
|
||||
parent = o;
|
||||
break;
|
||||
}
|
||||
case SI::MxCh:
|
||||
{
|
||||
uint16_t flags = ReadU16(is);
|
||||
uint32_t object = ReadU32(is);
|
||||
uint32_t time = ReadU32(is);
|
||||
uint32_t data_sz = ReadU32(is);
|
||||
bytearray data = ReadBytes(is, size - MxCh::HEADER_SIZE);
|
||||
|
||||
Object *o = m_ObjectIndexTable.at(object);
|
||||
if (!o) {
|
||||
return false;
|
||||
}
|
||||
o->data_.push_back(data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "Reading children at 0x" << std::hex << is.tellg() << std::endl;
|
||||
|
||||
// Assume any remaining data is this chunk's children
|
||||
while (is.good() && (size_t(is.tellg()) + 4) < 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;
|
||||
if (offset_in_buffer + sizeof(uint32_t)*2 > m_BufferSize) {
|
||||
is.seekg(m_BufferSize-offset_in_buffer, std::ios::cur);
|
||||
}
|
||||
}
|
||||
|
||||
// Read next child
|
||||
if (!ReadChunk(parent, is)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (is.tellg() < end) {
|
||||
is.seekg(end, std::ios::beg);
|
||||
}
|
||||
|
||||
if (size%2 == 1) {
|
||||
is.seekg(1, std::ios::cur);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Object *Interleaf::ReadObject(std::ifstream &is)
|
||||
{
|
||||
Object *o = new Object();
|
||||
|
||||
o->type_ = static_cast<MxOb::Type>(ReadU16(is));
|
||||
std::cout << " Type: " << o->type_ << std::endl;
|
||||
o->presenter_ = ReadString(is);
|
||||
std::cout << " Presenter: " << o->presenter_ << std::endl;
|
||||
o->unknown1_ = ReadU32(is);
|
||||
std::cout << " Unknown1: " << o->unknown1_ << std::endl;
|
||||
o->name_ = ReadString(is);
|
||||
std::cout << " Name: " << o->name_ << std::endl;
|
||||
o->id_ = ReadU32(is);
|
||||
std::cout << " ID: " << o->id_ << std::endl;
|
||||
o->flags_ = ReadU32(is);
|
||||
std::cout << " Flags: " << o->flags_ << std::endl;
|
||||
o->unknown4_ = ReadU32(is);
|
||||
std::cout << " Unknown4: " << o->unknown4_ << std::endl;
|
||||
o->duration_ = ReadU32(is);
|
||||
std::cout << " Duration: " << o->duration_ << std::endl;
|
||||
o->loops_ = ReadU32(is);
|
||||
std::cout << " Loops: " << o->loops_ << std::endl;
|
||||
o->position_ = ReadVector3(is);
|
||||
std::cout << " Position: " << o->position_.x << " " << o->position_.y << " " << o->position_.z << std::endl;
|
||||
o->direction_ = ReadVector3(is);
|
||||
std::cout << " Direction: " << o->direction_.x << " " << o->direction_.y << " " << o->direction_.z << std::endl;
|
||||
o->up_ = ReadVector3(is);
|
||||
std::cout << " Up: " << o->up_.x << " " << o->up_.y << " " << o->up_.z << std::endl;
|
||||
|
||||
uint16_t extra_sz = ReadU16(is);
|
||||
std::cout << " Extra Size: " << extra_sz << std::endl;
|
||||
o->extra_ = ReadBytes(is, extra_sz);
|
||||
|
||||
if (o->type_ != MxOb::Presenter && o->type_ != MxOb::World) {
|
||||
o->filename_ = ReadString(is);
|
||||
std::cout << " Filename: " << o->filename_ << std::endl;
|
||||
o->unknown26_ = ReadU32(is);
|
||||
std::cout << " Unknown26: " << o->unknown26_ << std::endl;
|
||||
o->unknown27_ = ReadU32(is);
|
||||
std::cout << " Unknown27: " << o->unknown27_ << std::endl;
|
||||
o->unknown28_ = ReadU32(is);
|
||||
std::cout << " Unknown28: " << o->unknown28_ << std::endl;
|
||||
o->filetype_ = static_cast<MxOb::FileType>(ReadU32(is));
|
||||
std::cout << " File Type: " << PrintU32AsString(o->filetype_) << std::endl;
|
||||
o->unknown29_ = ReadU32(is);
|
||||
std::cout << " Unknown29: " << o->unknown29_ << std::endl;
|
||||
o->unknown30_ = ReadU32(is);
|
||||
std::cout << " Unknown30: " << o->unknown30_ << std::endl;
|
||||
|
||||
if (o->filetype_ == MxOb::WAV) {
|
||||
o->unknown31_ = ReadU32(is);
|
||||
std::cout << " Unknown31: " << o->unknown31_ << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
//std::cout << "Next ID: 0x" << std::hex << is.tellg() << " ";
|
||||
//std::cout << PrintU32AsString(ReadU32(is));
|
||||
//std::cout << " After: 0x" << std::hex << is.tellg() << std::endl;
|
||||
//is.seekg(-4, std::ios::cur);
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
bool Interleaf::Read(std::ifstream &is)
|
||||
{
|
||||
Clear();
|
||||
return ReadChunk(this, is);
|
||||
}
|
||||
|
||||
/*bool Interleaf::Parse(Chunk *riff)
|
||||
{
|
||||
if (riff->id() != Chunk::TYPE_RIFF) {
|
||||
return false;
|
||||
|
@ -213,16 +455,16 @@ Chunk *Interleaf::ExportStream(Object *obj) const
|
|||
for (std::vector<ChunkStatus>::iterator it=chunk_status.begin(); it!=chunk_status.end(); it++) {
|
||||
// Check if we've already written all these chunks
|
||||
if (it->index >= it->object->data().size()) {
|
||||
/*if (!it->end_chunk) {
|
||||
if (!it->end_chunk) {
|
||||
chunklst->AppendChild(ExportMxCh(MxCh::FLAG_END, it->object->id(), it->time));
|
||||
it->end_chunk = true;
|
||||
}*/
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Find earliest chunk to write
|
||||
if (!status || it->time < status->time) {
|
||||
status = it.base();
|
||||
status = &(*it);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -288,6 +530,6 @@ Chunk *Interleaf::ExportMxCh(uint16_t flags, uint32_t object_id, uint32_t time,
|
|||
mxch->data("DataSize") = data.size();
|
||||
mxch->data("Data") = data;
|
||||
return mxch;
|
||||
}
|
||||
}*/
|
||||
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
#ifndef INTERLEAF_H
|
||||
#define INTERLEAF_H
|
||||
|
||||
#include "chunk.h"
|
||||
#include <fstream>
|
||||
|
||||
#include "core.h"
|
||||
#include "object.h"
|
||||
|
||||
|
@ -12,17 +13,30 @@ class Interleaf : public Core
|
|||
public:
|
||||
LIBWEAVER_EXPORT Interleaf();
|
||||
|
||||
LIBWEAVER_EXPORT bool Parse(Chunk *riff);
|
||||
LIBWEAVER_EXPORT Chunk *Export() const;
|
||||
LIBWEAVER_EXPORT void Clear();
|
||||
|
||||
LIBWEAVER_EXPORT bool Read(const char *f);
|
||||
LIBWEAVER_EXPORT bool Read(const wchar_t *f);
|
||||
|
||||
//LIBWEAVER_EXPORT bool Write(const char *f) const;
|
||||
//LIBWEAVER_EXPORT bool Write(const wchar_t *f) const;
|
||||
|
||||
private:
|
||||
bool ParseStream(Chunk *chunk);
|
||||
Chunk *ExportStream(Object *obj) const;
|
||||
Chunk *ExportMxCh(uint16_t flags, uint32_t object_id, uint32_t time, const bytearray &data = bytearray()) const;
|
||||
bool Read(std::ifstream &is);
|
||||
//bool Write(std::ofstream &os) const;
|
||||
|
||||
uint32_t version_;
|
||||
uint32_t buffer_size_;
|
||||
uint32_t buffer_count_;
|
||||
bool ReadChunk(Core *parent, std::ifstream &is);
|
||||
|
||||
Object *ReadObject(std::ifstream &is);
|
||||
|
||||
uint32_t m_Version;
|
||||
uint32_t m_BufferSize;
|
||||
uint32_t m_BufferCount;
|
||||
|
||||
uint32_t m_OffsetCount;
|
||||
std::vector<uint32_t> m_OffsetTable;
|
||||
|
||||
std::map<uint32_t, Object*> m_ObjectIndexTable;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
#include <iostream>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
namespace si {
|
||||
|
||||
Object::Object()
|
||||
|
@ -10,29 +12,9 @@ Object::Object()
|
|||
id_ = 0;
|
||||
}
|
||||
|
||||
bool Object::Parse(Chunk *chunk)
|
||||
/*bool Object::Read(std::ifstream &is)
|
||||
{
|
||||
type_ = static_cast<MxOb::Type>(chunk->data("Type").toU16());
|
||||
presenter_ = chunk->data("Presenter").toString();
|
||||
unknown1_ = chunk->data("Unknown1");
|
||||
name_ = chunk->data("Name").toString();
|
||||
id_ = chunk->data("ID");
|
||||
flags_ = chunk->data("Flags");
|
||||
unknown4_ = chunk->data("Unknown4");
|
||||
duration_ = chunk->data("Duration");
|
||||
loops_ = chunk->data("Loops");
|
||||
position_ = chunk->data("Position");
|
||||
direction_ = chunk->data("Direction");
|
||||
up_ = chunk->data("Up");
|
||||
extra_ = chunk->data("ExtraData");
|
||||
filename_ = chunk->data("FileName").toString();
|
||||
unknown26_ = chunk->data("Unknown26");
|
||||
unknown27_ = chunk->data("Unknown27");
|
||||
unknown28_ = chunk->data("Unknown28");
|
||||
filetype_ = static_cast<MxOb::FileType>(chunk->data("FileType").toU32());
|
||||
unknown29_ = chunk->data("Unknown29");
|
||||
unknown30_ = chunk->data("Unknown30");
|
||||
unknown31_ = chunk->data("Unknown31");
|
||||
|
||||
|
||||
if (chunk->HasChildren()) {
|
||||
Chunk *child = static_cast<Chunk*>(chunk->GetChildAt(0));
|
||||
|
@ -50,31 +32,30 @@ bool Object::Parse(Chunk *chunk)
|
|||
return true;
|
||||
}
|
||||
|
||||
Chunk *Object::Export() const
|
||||
void Object::Write(std::ofstream &os) 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_;
|
||||
WriteU16(os, type_);
|
||||
WriteString(os, presenter_);
|
||||
WriteU32(os, unknown1_);
|
||||
WriteString(os, name_);
|
||||
WriteU32(os, id_);
|
||||
WriteU32(os, flags_);
|
||||
WriteU32(os, unknown4_);
|
||||
WriteU32(os, duration_);
|
||||
WriteU32(os, loops_);
|
||||
WriteVector3(os, position_);
|
||||
WriteVector3(os, direction_);
|
||||
WriteVector3(os, up_);
|
||||
WriteU16(os, extra_.size());
|
||||
WriteBytes(os, extra_);
|
||||
WriteString(os, filename_);
|
||||
WriteU32(os, unknown26_);
|
||||
WriteU32(os, unknown27_);
|
||||
WriteU32(os, unknown28_);
|
||||
WriteU32(os, filetype_);
|
||||
WriteU32(os, unknown29_);
|
||||
WriteU32(os, unknown30_);
|
||||
WriteU32(os, unknown31_);
|
||||
|
||||
if (HasChildren()) {
|
||||
Chunk *list = new Chunk(Chunk::TYPE_LIST);
|
||||
|
@ -89,7 +70,7 @@ Chunk *Object::Export() const
|
|||
}
|
||||
|
||||
return chunk;
|
||||
}
|
||||
}*/
|
||||
|
||||
bytearray Object::GetNormalizedData() const
|
||||
{
|
||||
|
@ -118,7 +99,7 @@ bytearray Object::ToPackedData(MxOb::FileType filetype, const ChunkedData &chunk
|
|||
|
||||
// Copy boilerplate bytes for header
|
||||
uint32_t *header = reinterpret_cast<uint32_t *>(data.data());
|
||||
header[0] = Chunk::TYPE_RIFF; // "RIFF"
|
||||
header[0] = SI::RIFF; // "RIFF"
|
||||
header[1] = data.size() - 8; // Size of total file
|
||||
header[2] = 0x45564157; // "WAVE"
|
||||
header[3] = 0x20746D66; // "fmt "
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#ifndef OBJECT_H
|
||||
#define OBJECT_H
|
||||
|
||||
#include "chunk.h"
|
||||
#include "core.h"
|
||||
#include "sitypes.h"
|
||||
#include "types.h"
|
||||
|
||||
namespace si {
|
||||
|
@ -14,9 +14,6 @@ public:
|
|||
|
||||
Object();
|
||||
|
||||
bool Parse(Chunk *chunk);
|
||||
Chunk *Export() const;
|
||||
|
||||
void SetChunkedData(const ChunkedData &cd) { data_ = cd; }
|
||||
|
||||
LIBWEAVER_EXPORT bytearray GetNormalizedData() const;
|
||||
|
@ -38,7 +35,6 @@ public:
|
|||
|
||||
Object *FindSubObjectWithID(uint32_t id);
|
||||
|
||||
private:
|
||||
MxOb::Type type_;
|
||||
std::string presenter_;
|
||||
uint32_t unknown1_;
|
||||
|
|
59
lib/ptr.h
Normal file
59
lib/ptr.h
Normal file
|
@ -0,0 +1,59 @@
|
|||
#ifndef PTR_H
|
||||
#define PTR_H
|
||||
|
||||
namespace si {
|
||||
|
||||
/**
|
||||
* @brief Smart pointer implementation for versions of C++ < 11
|
||||
*/
|
||||
template <typename T>
|
||||
class Ptr
|
||||
{
|
||||
public:
|
||||
Ptr(T *ptr = 0)
|
||||
{
|
||||
data_ = ptr;
|
||||
ref_count_ = new size_t;
|
||||
*ref_count_ = 1;
|
||||
}
|
||||
|
||||
~Ptr()
|
||||
{
|
||||
*ref_count_--;
|
||||
if (*ref_count_ == 0) {
|
||||
delete data_;
|
||||
delete ref_count_;
|
||||
}
|
||||
}
|
||||
|
||||
Ptr(const Ptr<T> &other)
|
||||
{
|
||||
data_ = other.data_;
|
||||
ref_count_ = other.ref_count_;
|
||||
*ref_count_++;
|
||||
}
|
||||
|
||||
Ptr<T> &operator=(const Ptr<T> &other)
|
||||
{
|
||||
if (this != other) {
|
||||
*ref_count_--;
|
||||
if (*ref_count_ == 0) {
|
||||
delete data_;
|
||||
delete ref_count_;
|
||||
}
|
||||
|
||||
data_ = other.data_;
|
||||
ref_count_ = other.ref_count_;
|
||||
*ref_count_++;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
T *data_;
|
||||
size_t *ref_count_;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // PTR_H
|
286
lib/sitypes.cpp
286
lib/sitypes.cpp
|
@ -1,217 +1,7 @@
|
|||
#include "sitypes.h"
|
||||
|
||||
#include "chunk.h"
|
||||
|
||||
namespace si {
|
||||
|
||||
Data ReadU32(std::ifstream &is)
|
||||
{
|
||||
uint32_t u;
|
||||
is.read((char *) &u, sizeof(u));
|
||||
return u;
|
||||
}
|
||||
|
||||
void WriteU32(std::ofstream &os, uint32_t u)
|
||||
{
|
||||
os.write((const char *) &u, sizeof(u));
|
||||
}
|
||||
|
||||
Data ReadU16(std::ifstream &is)
|
||||
{
|
||||
uint16_t u;
|
||||
is.read((char *) &u, sizeof(u));
|
||||
return u;
|
||||
}
|
||||
|
||||
void WriteU16(std::ofstream &os, uint16_t u)
|
||||
{
|
||||
os.write((const char *) &u, sizeof(u));
|
||||
}
|
||||
|
||||
Data ReadU8(std::ifstream &is)
|
||||
{
|
||||
uint8_t u;
|
||||
is.read((char *) &u, sizeof(u));
|
||||
return u;
|
||||
}
|
||||
|
||||
void WriteU8(std::ofstream &os, uint8_t u)
|
||||
{
|
||||
os.write((const char *) &u, sizeof(u));
|
||||
}
|
||||
|
||||
Data ReadVector3(std::ifstream &is)
|
||||
{
|
||||
Vector3 u;
|
||||
is.read((char *) &u, sizeof(u));
|
||||
return u;
|
||||
}
|
||||
|
||||
void WriteVector3(std::ofstream &os, Vector3 v)
|
||||
{
|
||||
os.write((const char *) &v, sizeof(v));
|
||||
}
|
||||
|
||||
Data ReadString(std::ifstream &is)
|
||||
{
|
||||
bytearray d;
|
||||
|
||||
while (true) {
|
||||
char c;
|
||||
is.read(&c, 1);
|
||||
if (c == 0) {
|
||||
break;
|
||||
}
|
||||
d.push_back(c);
|
||||
}
|
||||
|
||||
// Append null terminator
|
||||
d.push_back(0);
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
void WriteString(std::ofstream &os, const std::string &d)
|
||||
{
|
||||
if (!d.empty()) {
|
||||
// Write every byte that isn't null
|
||||
const char *s = &d[0];
|
||||
while ((*s) != 0) {
|
||||
os.write(s, 1);
|
||||
s++;
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure null terminator
|
||||
const char nullterm = 0;
|
||||
os.write(&nullterm, 1);
|
||||
}
|
||||
|
||||
Data ReadBytes(std::ifstream &is, size_t size)
|
||||
{
|
||||
bytearray d;
|
||||
|
||||
d.resize(size);
|
||||
is.read(d.data(), size);
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
void WriteBytes(std::ofstream &os, const bytearray &ba)
|
||||
{
|
||||
os.write(ba.data(), ba.size());
|
||||
}
|
||||
|
||||
void RIFF::Read(std::ifstream &is, DataMap &data, uint32_t version, uint32_t size)
|
||||
{
|
||||
data["Format"] = ReadU32(is);
|
||||
}
|
||||
|
||||
void RIFF::Write(std::ofstream &os, const DataMap &data, uint32_t version)
|
||||
{
|
||||
WriteU32(os, data.at("Format"));
|
||||
}
|
||||
|
||||
void LIST::Read(std::ifstream &is, DataMap &data, uint32_t version, uint32_t size)
|
||||
{
|
||||
data["Format"] = ReadU32(is);
|
||||
|
||||
if (data["Format"] == Chunk::TYPE_MxCh) {
|
||||
data["Count"] = ReadU32(is);
|
||||
}
|
||||
}
|
||||
|
||||
void LIST::Write(std::ofstream &os, const DataMap &data, uint32_t version)
|
||||
{
|
||||
WriteU32(os, data.at("Format"));
|
||||
|
||||
if (data.at("Format") == Chunk::TYPE_MxCh) {
|
||||
WriteU32(os, data.at("Count"));
|
||||
}
|
||||
}
|
||||
|
||||
void MxSt::Read(std::ifstream &is, DataMap &data, uint32_t version, uint32_t size)
|
||||
{
|
||||
// MxSt is a container type only and has no members, so nothing needs to be done here
|
||||
}
|
||||
|
||||
void MxSt::Write(std::ofstream &os, const DataMap &data, uint32_t version)
|
||||
{
|
||||
// MxSt is a container type only and has no members, so nothing needs to be done here
|
||||
}
|
||||
|
||||
void MxHd::Read(std::ifstream &is, DataMap &data, uint32_t version, uint32_t size)
|
||||
{
|
||||
Data v = ReadU32(is);
|
||||
data["Version"] = v;
|
||||
data["BufferSize"] = ReadU32(is);
|
||||
data["BufferCount"] = ReadU32(is);
|
||||
}
|
||||
|
||||
void MxHd::Write(std::ofstream &os, const DataMap &data, uint32_t version)
|
||||
{
|
||||
WriteU32(os, data.at("Version"));
|
||||
WriteU32(os, data.at("BufferSize"));
|
||||
WriteU32(os, data.at("BufferCount"));
|
||||
}
|
||||
|
||||
void MxCh::Read(std::ifstream &is, DataMap &data, uint32_t version, uint32_t size)
|
||||
{
|
||||
data["Flags"] = ReadU16(is);
|
||||
data["Object"] = ReadU32(is);
|
||||
data["Time"] = ReadU32(is);
|
||||
data["DataSize"] = ReadU32(is);
|
||||
data["Data"] = ReadBytes(is, size - 0xE);
|
||||
}
|
||||
|
||||
void MxCh::Write(std::ofstream &os, const DataMap &data, uint32_t version)
|
||||
{
|
||||
WriteU16(os, data.at("Flags"));
|
||||
WriteU32(os, data.at("Object"));
|
||||
WriteU32(os, data.at("Time"));
|
||||
WriteU32(os, data.at("DataSize"));
|
||||
WriteBytes(os, data.at("Data"));
|
||||
}
|
||||
|
||||
void MxOf::Read(std::ifstream &is, DataMap &data, uint32_t version, uint32_t size)
|
||||
{
|
||||
data["Count"] = ReadU32(is);
|
||||
data["Offsets"] = ReadBytes(is, size - sizeof(uint32_t));
|
||||
}
|
||||
|
||||
void MxOf::Write(std::ofstream &os, const DataMap &data, uint32_t version)
|
||||
{
|
||||
WriteU32(os, data.at("Count"));
|
||||
WriteBytes(os, data.at("Offsets"));
|
||||
}
|
||||
|
||||
void pad_::Read(std::ifstream &is, DataMap &data, uint32_t version, uint32_t size)
|
||||
{
|
||||
data["Size"] = size;
|
||||
is.seekg(size, std::ios::cur);
|
||||
}
|
||||
|
||||
void pad_::Write(std::ofstream &os, const DataMap &data, uint32_t version)
|
||||
{
|
||||
uint32_t sz = data.at("Size").toU32();
|
||||
if (sz > 0) {
|
||||
bytearray b;
|
||||
b.resize(sz);
|
||||
b.fill(0xCD);
|
||||
WriteBytes(os, b);
|
||||
}
|
||||
}
|
||||
|
||||
void pad_::WriteArbitraryPadding(std::ofstream &os, uint32_t size)
|
||||
{
|
||||
uint32_t pad_id = Chunk::TYPE_pad_;
|
||||
os.write((const char *) &pad_id, sizeof(uint32_t));
|
||||
os.write((const char *) &size, sizeof(uint32_t));
|
||||
bytearray b(size);
|
||||
b.fill(0xCD);
|
||||
WriteBytes(os, b);
|
||||
}
|
||||
|
||||
const char *MxOb::GetTypeName(Type type)
|
||||
{
|
||||
switch (type) {
|
||||
|
@ -266,80 +56,4 @@ std::vector<const char*> MxOb::GetFlagsName(Flags flags)
|
|||
return names;
|
||||
}
|
||||
|
||||
void MxOb::Read(std::ifstream &is, DataMap &data, uint32_t version, uint32_t size)
|
||||
{
|
||||
Data obj_type = ReadU16(is);
|
||||
data["Type"] = obj_type;
|
||||
data["Presenter"] = ReadString(is);
|
||||
data["Unknown1"] = ReadU32(is);
|
||||
data["Name"] = ReadString(is);
|
||||
data["ID"] = ReadU32(is);
|
||||
data["Flags"] = ReadU32(is);
|
||||
data["Unknown4"] = ReadU32(is);
|
||||
data["Duration"] = ReadU32(is);
|
||||
data["Loops"] = ReadU32(is);
|
||||
data["Position"] = ReadVector3(is);
|
||||
data["Direction"] = ReadVector3(is);
|
||||
data["Up"] = ReadVector3(is);
|
||||
|
||||
Data extra_sz = ReadU16(is);
|
||||
data["ExtraLength"] = extra_sz;
|
||||
data["ExtraData"] = ReadBytes(is, extra_sz);
|
||||
|
||||
if (obj_type != Presenter && obj_type != World) {
|
||||
data["FileName"] = ReadString(is);
|
||||
|
||||
data["Unknown26"] = ReadU32(is);
|
||||
data["Unknown27"] = ReadU32(is);
|
||||
data["Unknown28"] = ReadU32(is);
|
||||
|
||||
data["FileType"] = ReadU32(is);
|
||||
|
||||
data["Unknown29"] = ReadU32(is);
|
||||
data["Unknown30"] = ReadU32(is);
|
||||
|
||||
if (obj_type == MxOb::Sound) {
|
||||
data["Unknown31"] = ReadU32(is);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MxOb::Write(std::ofstream &os, const DataMap &data, uint32_t version)
|
||||
{
|
||||
const Data &obj_type = data.at("Type");
|
||||
WriteU16(os, obj_type);
|
||||
WriteString(os, data.at("Presenter"));
|
||||
WriteU32(os, data.at("Unknown1"));
|
||||
WriteString(os, data.at("Name"));
|
||||
WriteU32(os, data.at("ID"));
|
||||
WriteU32(os, data.at("Flags"));
|
||||
WriteU32(os, data.at("Unknown4"));
|
||||
WriteU32(os, data.at("Duration"));
|
||||
WriteU32(os, data.at("Loops"));
|
||||
WriteVector3(os, data.at("Position"));
|
||||
WriteVector3(os, data.at("Direction"));
|
||||
WriteVector3(os, data.at("Up"));
|
||||
|
||||
const Data &extra = data.at("ExtraData");
|
||||
WriteU16(os, extra.size());
|
||||
WriteBytes(os, extra);
|
||||
|
||||
if (obj_type != Presenter && obj_type != World) {
|
||||
WriteString(os, data.at("FileName"));
|
||||
|
||||
WriteU32(os, data.at("Unknown26"));
|
||||
WriteU32(os, data.at("Unknown27"));
|
||||
WriteU32(os, data.at("Unknown28"));
|
||||
|
||||
WriteU32(os, data.at("FileType"));
|
||||
|
||||
WriteU32(os, data.at("Unknown29"));
|
||||
WriteU32(os, data.at("Unknown30"));
|
||||
|
||||
if (obj_type == MxOb::Sound) {
|
||||
WriteU32(os, data.at("Unknown31"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -8,6 +8,23 @@
|
|||
|
||||
namespace si {
|
||||
|
||||
class SI
|
||||
{
|
||||
public:
|
||||
enum Type
|
||||
{
|
||||
RIFF = 0x46464952,
|
||||
LIST = 0x5453494c,
|
||||
MxSt = 0x7453784d,
|
||||
MxHd = 0x6448784d,
|
||||
MxCh = 0x6843784d,
|
||||
MxOf = 0x664f784d,
|
||||
MxOb = 0x624f784d,
|
||||
MxDa = 0x6144784d,
|
||||
pad_ = 0x20646170
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief RIFF chunk type
|
||||
*
|
||||
|
@ -21,12 +38,6 @@ public:
|
|||
enum {
|
||||
OMNI = 0x494e4d4f
|
||||
};
|
||||
|
||||
virtual ~RIFF(){}
|
||||
|
||||
virtual void Read(std::ifstream &is, DataMap &data, uint32_t version, uint32_t size);
|
||||
virtual void Write(std::ofstream &os, const DataMap &data, uint32_t version);
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -40,8 +51,6 @@ public:
|
|||
class LIST : public RIFF
|
||||
{
|
||||
public:
|
||||
virtual void Read(std::ifstream &is, DataMap &data, uint32_t version, uint32_t size);
|
||||
virtual void Write(std::ofstream &os, const DataMap &data, uint32_t version);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -56,8 +65,6 @@ public:
|
|||
class MxHd : public RIFF
|
||||
{
|
||||
public:
|
||||
virtual void Read(std::ifstream &is, DataMap &data, uint32_t version, uint32_t size);
|
||||
virtual void Write(std::ofstream &os, const DataMap &data, uint32_t version);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -68,8 +75,6 @@ public:
|
|||
class MxSt : public RIFF
|
||||
{
|
||||
public:
|
||||
virtual void Read(std::ifstream &is, DataMap &data, uint32_t version, uint32_t size);
|
||||
virtual void Write(std::ofstream &os, const DataMap &data, uint32_t version);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -92,9 +97,6 @@ public:
|
|||
};
|
||||
|
||||
static const uint32_t HEADER_SIZE = 14;
|
||||
|
||||
virtual void Read(std::ifstream &is, DataMap &data, uint32_t version, uint32_t size);
|
||||
virtual void Write(std::ofstream &os, const DataMap &data, uint32_t version);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -108,8 +110,6 @@ public:
|
|||
class MxOf : public RIFF
|
||||
{
|
||||
public:
|
||||
virtual void Read(std::ifstream &is, DataMap &data, uint32_t version, uint32_t size);
|
||||
virtual void Write(std::ofstream &os, const DataMap &data, uint32_t version);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -121,9 +121,6 @@ public:
|
|||
class pad_ : public RIFF
|
||||
{
|
||||
public:
|
||||
virtual void Read(std::ifstream &is, DataMap &data, uint32_t version, uint32_t size);
|
||||
virtual void Write(std::ofstream &os, const DataMap &data, uint32_t version);
|
||||
|
||||
static void WriteArbitraryPadding(std::ofstream &os, uint32_t size);
|
||||
};
|
||||
|
||||
|
@ -235,9 +232,6 @@ public:
|
|||
// probably be moved
|
||||
LIBWEAVER_EXPORT static const char *GetTypeName(Type type);
|
||||
LIBWEAVER_EXPORT static std::vector<const char*> GetFlagsName(Flags flags);
|
||||
|
||||
virtual void Read(std::ifstream &is, DataMap &data, uint32_t version, uint32_t size);
|
||||
virtual void Write(std::ofstream &os, const DataMap &data, uint32_t version);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -147,8 +147,6 @@ private:
|
|||
|
||||
};
|
||||
|
||||
typedef std::map<std::string, Data> DataMap;
|
||||
|
||||
}
|
||||
|
||||
#endif // TYPES_H
|
||||
|
|
100
lib/util.h
Normal file
100
lib/util.h
Normal file
|
@ -0,0 +1,100 @@
|
|||
#ifndef UTIL_H
|
||||
#define UTIL_H
|
||||
|
||||
#include <fstream>
|
||||
|
||||
#include "types.h"
|
||||
|
||||
namespace si {
|
||||
|
||||
inline uint32_t ReadU32(std::ifstream &is)
|
||||
{
|
||||
uint32_t u;
|
||||
is.read((char *) &u, sizeof(u));
|
||||
return u;
|
||||
}
|
||||
|
||||
inline void WriteU32(std::ofstream &os, uint32_t u)
|
||||
{
|
||||
os.write((const char *) &u, sizeof(u));
|
||||
}
|
||||
|
||||
inline uint16_t ReadU16(std::ifstream &is)
|
||||
{
|
||||
uint16_t u;
|
||||
is.read((char *) &u, sizeof(u));
|
||||
return u;
|
||||
}
|
||||
|
||||
inline void WriteU16(std::ofstream &os, uint16_t u)
|
||||
{
|
||||
os.write((const char *) &u, sizeof(u));
|
||||
}
|
||||
|
||||
inline uint8_t ReadU8(std::ifstream &is)
|
||||
{
|
||||
uint8_t u;
|
||||
is.read((char *) &u, sizeof(u));
|
||||
return u;
|
||||
}
|
||||
|
||||
inline void WriteU8(std::ofstream &os, uint8_t u)
|
||||
{
|
||||
os.write((const char *) &u, sizeof(u));
|
||||
}
|
||||
|
||||
inline Vector3 ReadVector3(std::ifstream &is)
|
||||
{
|
||||
Vector3 u;
|
||||
is.read((char *) &u, sizeof(u));
|
||||
return u;
|
||||
}
|
||||
|
||||
inline void WriteVector3(std::ofstream &os, Vector3 v)
|
||||
{
|
||||
os.write((const char *) &v, sizeof(v));
|
||||
}
|
||||
|
||||
inline std::string ReadString(std::ifstream &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::ofstream &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::ifstream &is, size_t size)
|
||||
{
|
||||
bytearray d;
|
||||
|
||||
d.resize(size);
|
||||
is.read(d.data(), size);
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
inline void WriteBytes(std::ofstream &os, const bytearray &ba)
|
||||
{
|
||||
os.write(ba.data(), ba.size());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // UTIL_H
|
Loading…
Reference in a new issue