mirror of
https://github.com/isledecomp/SIEdit.git
synced 2024-11-27 09:35: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)
|
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets Multimedia)
|
||||||
|
|
||||||
set(PROJECT_SOURCES
|
set(PROJECT_SOURCES
|
||||||
siview/chunkmodel.cpp
|
# siview/chunkmodel.cpp
|
||||||
siview/chunkmodel.h
|
# siview/chunkmodel.h
|
||||||
siview/panels/mxch.cpp
|
# siview/panels/mxch.cpp
|
||||||
siview/panels/mxch.h
|
# siview/panels/mxch.h
|
||||||
siview/panels/mxhd.cpp
|
# siview/panels/mxhd.cpp
|
||||||
siview/panels/mxhd.h
|
# siview/panels/mxhd.h
|
||||||
siview/panels/mxob.cpp
|
# siview/panels/mxob.cpp
|
||||||
siview/panels/mxob.h
|
# siview/panels/mxob.h
|
||||||
siview/panels/mxof.cpp
|
# siview/panels/mxof.cpp
|
||||||
siview/panels/mxof.h
|
# siview/panels/mxof.h
|
||||||
siview/panels/riff.cpp
|
# siview/panels/riff.cpp
|
||||||
siview/panels/riff.h
|
# siview/panels/riff.h
|
||||||
siview/siview.cpp
|
# siview/siview.cpp
|
||||||
siview/siview.h
|
# siview/siview.h
|
||||||
|
|
||||||
viewer/bitmappanel.cpp
|
viewer/bitmappanel.cpp
|
||||||
viewer/bitmappanel.h
|
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_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_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
|
set_target_properties(si-edit PROPERTIES
|
||||||
MACOSX_BUNDLE_GUI_IDENTIFIER com.mattkc.SIEdit
|
MACOSX_BUNDLE_GUI_IDENTIFIER com.mattkc.SIEdit
|
||||||
|
|
|
@ -6,8 +6,6 @@
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QSplitter>
|
#include <QSplitter>
|
||||||
|
|
||||||
#include "siview/siview.h"
|
|
||||||
|
|
||||||
using namespace si;
|
using namespace si;
|
||||||
|
|
||||||
MainWindow::MainWindow(QWidget *parent) :
|
MainWindow::MainWindow(QWidget *parent) :
|
||||||
|
@ -67,14 +65,18 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||||
|
|
||||||
void MainWindow::OpenFilename(const QString &s)
|
void MainWindow::OpenFilename(const QString &s)
|
||||||
{
|
{
|
||||||
Chunk si;
|
model_.SetCore(nullptr);
|
||||||
if (si.Read(s.toStdString())) {
|
|
||||||
SIViewDialog d(SIViewDialog::Import, &si, this);
|
bool r =
|
||||||
if (d.exec() == QDialog::Accepted) {
|
#ifdef Q_OS_WINDOWS
|
||||||
model_.SetCore(nullptr);
|
interleaf_.Read(s.toStdWString().c_str());
|
||||||
interleaf_.Parse(&si);
|
#else
|
||||||
model_.SetCore(&interleaf_);
|
interleaf_.Read(s.toUtf8());
|
||||||
}
|
#endif
|
||||||
|
;
|
||||||
|
|
||||||
|
if (r) {
|
||||||
|
model_.SetCore(&interleaf_);
|
||||||
} else {
|
} else {
|
||||||
QMessageBox::critical(this, QString(), tr("Failed to load Interleaf file."));
|
QMessageBox::critical(this, QString(), tr("Failed to load Interleaf file."));
|
||||||
}
|
}
|
||||||
|
@ -155,17 +157,6 @@ void MainWindow::OpenFile()
|
||||||
|
|
||||||
void MainWindow::ExportFile()
|
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)
|
void MainWindow::SelectionChanged(const QModelIndex &index)
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
option(LIBWEAVER_BUILD_DOXYGEN "Build Doxygen documentation" OFF)
|
option(LIBWEAVER_BUILD_DOXYGEN "Build Doxygen documentation" OFF)
|
||||||
|
|
||||||
set(LIBWEAVER_SOURCES
|
set(LIBWEAVER_SOURCES
|
||||||
chunk.cpp
|
|
||||||
chunk.h
|
|
||||||
common.h
|
common.h
|
||||||
core.cpp
|
core.cpp
|
||||||
core.h
|
core.h
|
||||||
|
@ -13,6 +11,7 @@ set(LIBWEAVER_SOURCES
|
||||||
sitypes.cpp
|
sitypes.cpp
|
||||||
sitypes.h
|
sitypes.h
|
||||||
types.h
|
types.h
|
||||||
|
util.h
|
||||||
)
|
)
|
||||||
|
|
||||||
add_library(libweaver SHARED
|
add_library(libweaver SHARED
|
||||||
|
@ -20,7 +19,9 @@ add_library(libweaver SHARED
|
||||||
)
|
)
|
||||||
|
|
||||||
target_compile_definitions(libweaver PRIVATE LIBWEAVER_LIBRARY)
|
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
|
set_target_properties(libweaver PROPERTIES
|
||||||
CXX_STANDARD 98
|
CXX_STANDARD 98
|
||||||
CXX_STANDARD_REQUIRED ON
|
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 "object.h"
|
||||||
#include "othertypes.h"
|
#include "othertypes.h"
|
||||||
|
#include "sitypes.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
namespace si {
|
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) {
|
if (riff->id() != Chunk::TYPE_RIFF) {
|
||||||
return false;
|
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++) {
|
for (std::vector<ChunkStatus>::iterator it=chunk_status.begin(); it!=chunk_status.end(); it++) {
|
||||||
// Check if we've already written all these chunks
|
// Check if we've already written all these chunks
|
||||||
if (it->index >= it->object->data().size()) {
|
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));
|
chunklst->AppendChild(ExportMxCh(MxCh::FLAG_END, it->object->id(), it->time));
|
||||||
it->end_chunk = true;
|
it->end_chunk = true;
|
||||||
}*/
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find earliest chunk to write
|
// Find earliest chunk to write
|
||||||
if (!status || it->time < status->time) {
|
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("DataSize") = data.size();
|
||||||
mxch->data("Data") = data;
|
mxch->data("Data") = data;
|
||||||
return mxch;
|
return mxch;
|
||||||
}
|
}*/
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
#ifndef INTERLEAF_H
|
#ifndef INTERLEAF_H
|
||||||
#define INTERLEAF_H
|
#define INTERLEAF_H
|
||||||
|
|
||||||
#include "chunk.h"
|
#include <fstream>
|
||||||
|
|
||||||
#include "core.h"
|
#include "core.h"
|
||||||
#include "object.h"
|
#include "object.h"
|
||||||
|
|
||||||
|
@ -12,17 +13,30 @@ class Interleaf : public Core
|
||||||
public:
|
public:
|
||||||
LIBWEAVER_EXPORT Interleaf();
|
LIBWEAVER_EXPORT Interleaf();
|
||||||
|
|
||||||
LIBWEAVER_EXPORT bool Parse(Chunk *riff);
|
LIBWEAVER_EXPORT void Clear();
|
||||||
LIBWEAVER_EXPORT Chunk *Export() const;
|
|
||||||
|
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:
|
private:
|
||||||
bool ParseStream(Chunk *chunk);
|
bool Read(std::ifstream &is);
|
||||||
Chunk *ExportStream(Object *obj) const;
|
//bool Write(std::ofstream &os) const;
|
||||||
Chunk *ExportMxCh(uint16_t flags, uint32_t object_id, uint32_t time, const bytearray &data = bytearray()) const;
|
|
||||||
|
|
||||||
uint32_t version_;
|
bool ReadChunk(Core *parent, std::ifstream &is);
|
||||||
uint32_t buffer_size_;
|
|
||||||
uint32_t buffer_count_;
|
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 <iostream>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
namespace si {
|
namespace si {
|
||||||
|
|
||||||
Object::Object()
|
Object::Object()
|
||||||
|
@ -10,29 +12,9 @@ Object::Object()
|
||||||
id_ = 0;
|
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()) {
|
if (chunk->HasChildren()) {
|
||||||
Chunk *child = static_cast<Chunk*>(chunk->GetChildAt(0));
|
Chunk *child = static_cast<Chunk*>(chunk->GetChildAt(0));
|
||||||
|
@ -50,31 +32,30 @@ bool Object::Parse(Chunk *chunk)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Chunk *Object::Export() const
|
void Object::Write(std::ofstream &os) const
|
||||||
{
|
{
|
||||||
Chunk *chunk = new Chunk(Chunk::TYPE_MxOb);
|
WriteU16(os, type_);
|
||||||
|
WriteString(os, presenter_);
|
||||||
chunk->data("Type") = type_;
|
WriteU32(os, unknown1_);
|
||||||
chunk->data("Presenter") = presenter_;
|
WriteString(os, name_);
|
||||||
chunk->data("Unknown1") = unknown1_;
|
WriteU32(os, id_);
|
||||||
chunk->data("Name") = name_;
|
WriteU32(os, flags_);
|
||||||
chunk->data("ID") = id_;
|
WriteU32(os, unknown4_);
|
||||||
chunk->data("Flags") = flags_;
|
WriteU32(os, duration_);
|
||||||
chunk->data("Unknown4") = unknown4_;
|
WriteU32(os, loops_);
|
||||||
chunk->data("Duration") = duration_;
|
WriteVector3(os, position_);
|
||||||
chunk->data("Loops") = loops_;
|
WriteVector3(os, direction_);
|
||||||
chunk->data("Position") = position_;
|
WriteVector3(os, up_);
|
||||||
chunk->data("Direction") = direction_;
|
WriteU16(os, extra_.size());
|
||||||
chunk->data("Up") = up_;
|
WriteBytes(os, extra_);
|
||||||
chunk->data("ExtraData") = extra_;
|
WriteString(os, filename_);
|
||||||
chunk->data("FileName") = filename_;
|
WriteU32(os, unknown26_);
|
||||||
chunk->data("Unknown26") = unknown26_;
|
WriteU32(os, unknown27_);
|
||||||
chunk->data("Unknown27") = unknown27_;
|
WriteU32(os, unknown28_);
|
||||||
chunk->data("Unknown28") = unknown28_;
|
WriteU32(os, filetype_);
|
||||||
chunk->data("FileType") = filetype_;
|
WriteU32(os, unknown29_);
|
||||||
chunk->data("Unknown29") = unknown29_;
|
WriteU32(os, unknown30_);
|
||||||
chunk->data("Unknown30") = unknown30_;
|
WriteU32(os, unknown31_);
|
||||||
chunk->data("Unknown31") = unknown31_;
|
|
||||||
|
|
||||||
if (HasChildren()) {
|
if (HasChildren()) {
|
||||||
Chunk *list = new Chunk(Chunk::TYPE_LIST);
|
Chunk *list = new Chunk(Chunk::TYPE_LIST);
|
||||||
|
@ -89,7 +70,7 @@ Chunk *Object::Export() const
|
||||||
}
|
}
|
||||||
|
|
||||||
return chunk;
|
return chunk;
|
||||||
}
|
}*/
|
||||||
|
|
||||||
bytearray Object::GetNormalizedData() const
|
bytearray Object::GetNormalizedData() const
|
||||||
{
|
{
|
||||||
|
@ -118,7 +99,7 @@ bytearray Object::ToPackedData(MxOb::FileType filetype, const ChunkedData &chunk
|
||||||
|
|
||||||
// Copy boilerplate bytes for header
|
// Copy boilerplate bytes for header
|
||||||
uint32_t *header = reinterpret_cast<uint32_t *>(data.data());
|
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[1] = data.size() - 8; // Size of total file
|
||||||
header[2] = 0x45564157; // "WAVE"
|
header[2] = 0x45564157; // "WAVE"
|
||||||
header[3] = 0x20746D66; // "fmt "
|
header[3] = 0x20746D66; // "fmt "
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
#ifndef OBJECT_H
|
#ifndef OBJECT_H
|
||||||
#define OBJECT_H
|
#define OBJECT_H
|
||||||
|
|
||||||
#include "chunk.h"
|
|
||||||
#include "core.h"
|
#include "core.h"
|
||||||
|
#include "sitypes.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
namespace si {
|
namespace si {
|
||||||
|
@ -14,9 +14,6 @@ public:
|
||||||
|
|
||||||
Object();
|
Object();
|
||||||
|
|
||||||
bool Parse(Chunk *chunk);
|
|
||||||
Chunk *Export() const;
|
|
||||||
|
|
||||||
void SetChunkedData(const ChunkedData &cd) { data_ = cd; }
|
void SetChunkedData(const ChunkedData &cd) { data_ = cd; }
|
||||||
|
|
||||||
LIBWEAVER_EXPORT bytearray GetNormalizedData() const;
|
LIBWEAVER_EXPORT bytearray GetNormalizedData() const;
|
||||||
|
@ -38,7 +35,6 @@ public:
|
||||||
|
|
||||||
Object *FindSubObjectWithID(uint32_t id);
|
Object *FindSubObjectWithID(uint32_t id);
|
||||||
|
|
||||||
private:
|
|
||||||
MxOb::Type type_;
|
MxOb::Type type_;
|
||||||
std::string presenter_;
|
std::string presenter_;
|
||||||
uint32_t unknown1_;
|
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 "sitypes.h"
|
||||||
|
|
||||||
#include "chunk.h"
|
|
||||||
|
|
||||||
namespace si {
|
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)
|
const char *MxOb::GetTypeName(Type type)
|
||||||
{
|
{
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
@ -266,80 +56,4 @@ std::vector<const char*> MxOb::GetFlagsName(Flags flags)
|
||||||
return names;
|
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 {
|
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
|
* @brief RIFF chunk type
|
||||||
*
|
*
|
||||||
|
@ -21,12 +38,6 @@ public:
|
||||||
enum {
|
enum {
|
||||||
OMNI = 0x494e4d4f
|
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
|
class LIST : public RIFF
|
||||||
{
|
{
|
||||||
public:
|
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
|
class MxHd : public RIFF
|
||||||
{
|
{
|
||||||
public:
|
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
|
class MxSt : public RIFF
|
||||||
{
|
{
|
||||||
public:
|
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;
|
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
|
class MxOf : public RIFF
|
||||||
{
|
{
|
||||||
public:
|
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
|
class pad_ : public RIFF
|
||||||
{
|
{
|
||||||
public:
|
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);
|
static void WriteArbitraryPadding(std::ofstream &os, uint32_t size);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -235,9 +232,6 @@ public:
|
||||||
// probably be moved
|
// probably be moved
|
||||||
LIBWEAVER_EXPORT static const char *GetTypeName(Type type);
|
LIBWEAVER_EXPORT static const char *GetTypeName(Type type);
|
||||||
LIBWEAVER_EXPORT static std::vector<const char*> GetFlagsName(Flags flags);
|
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
|
#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