initial commit

This commit is contained in:
itsmattkc 2022-06-23 18:36:00 -07:00
commit 6442e5d513
21 changed files with 692 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
*.user

8
CMakeLists.txt Normal file
View file

@ -0,0 +1,8 @@
cmake_minimum_required(VERSION 3.14)
project(libweaver VERSION 1.0 LANGUAGES CXX)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
add_subdirectory(lib)
add_subdirectory(app)

43
app/CMakeLists.txt Normal file
View file

@ -0,0 +1,43 @@
find_package(Qt5)
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets)
set(PROJECT_SOURCES
chunkmodel.cpp
chunkmodel.h
main.cpp
mainwindow.cpp
mainwindow.h
)
if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)
qt_add_executable(si-edit
MANUAL_FINALIZATION
${PROJECT_SOURCES}
)
else()
add_executable(si-edit
${PROJECT_SOURCES}
)
endif()
target_link_libraries(si-edit PRIVATE Qt${QT_VERSION_MAJOR}::Widgets libweaver)
target_include_directories(si-edit PRIVATE "${CMAKE_SOURCE_DIR}/lib")
set_target_properties(si-edit PROPERTIES
MACOSX_BUNDLE_GUI_IDENTIFIER com.mattkc.SIEdit
MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
MACOSX_BUNDLE TRUE
WIN32_EXECUTABLE TRUE
CXX_STANDARD 17
CXX_STANDARD_REQUIRED ON
AUTOUIC ON
AUTOMOC ON
AUTORCC ON
)
if(QT_VERSION_MAJOR EQUAL 6)
qt_finalize_executable(si-edit)
endif()

112
app/chunkmodel.cpp Normal file
View file

@ -0,0 +1,112 @@
#include "chunkmodel.h"
#include <data/riff.h>
#include <iostream>
#define super QAbstractItemModel
ChunkModel::ChunkModel(QObject *parent) :
super{parent},
chunk_(nullptr)
{
}
int ChunkModel::columnCount(const QModelIndex &parent) const
{
return kColCount;
}
QModelIndex ChunkModel::index(int row, int column, const QModelIndex &parent) const
{
Chunk *c = GetChunkFromIndex(parent);
if (!c) {
return QModelIndex();
}
return createIndex(row, column, c->GetChildAt(row));
}
QModelIndex ChunkModel::parent(const QModelIndex &index) const
{
Chunk *child = GetChunkFromIndex(index);
if (!child) {
return QModelIndex();
}
Chunk *parent = child->GetParent();
if (!parent) {
return QModelIndex();
}
Chunk *grandparent = parent->GetParent();
if (!grandparent) {
return QModelIndex();
}
size_t row = grandparent->IndexOfChild(parent);
return createIndex(row, index.column(), parent);
}
int ChunkModel::rowCount(const QModelIndex &parent) const
{
Chunk *c = GetChunkFromIndex(parent);
if (!c) {
return 0;
}
return c->GetChildCount();
}
QVariant ChunkModel::data(const QModelIndex &index, int role) const
{
Chunk *c = GetChunkFromIndex(index);
if (!c) {
return QVariant();
}
switch (role) {
case Qt::DisplayRole:
switch (index.column()) {
case kColType:
// Convert 4-byte ID to QString
return QString::fromLatin1(reinterpret_cast<const char *>(&c->id()), sizeof(u32));
case kColDesc:
return QString::fromUtf8(c->GetTypeDescription());
}
break;
}
return QVariant();
}
QVariant ChunkModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
switch (section) {
case kColType:
return tr("Type");
case kColDesc:
return tr("Description");
}
}
return super::headerData(section, orientation, role);
}
void ChunkModel::SetChunk(Chunk *c)
{
beginResetModel();
chunk_ = c;
endResetModel();
}
Chunk *ChunkModel::GetChunkFromIndex(const QModelIndex &index) const
{
if (!index.isValid()) {
return chunk_;
} else {
return static_cast<Chunk*>(index.internalPointer());
}
}

36
app/chunkmodel.h Normal file
View file

@ -0,0 +1,36 @@
#ifndef CHUNKMODEL_H
#define CHUNKMODEL_H
#include <chunk.h>
#include <QAbstractItemModel>
class ChunkModel : public QAbstractItemModel
{
public:
enum Columns
{
kColType,
kColDesc,
kColCount
};
explicit ChunkModel(QObject *parent = nullptr);
virtual int columnCount(const QModelIndex &parent = QModelIndex()) const override;
virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
virtual QModelIndex parent(const QModelIndex &index) const override;
virtual int rowCount(const QModelIndex &parent = QModelIndex()) const override;
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
void SetChunk(Chunk *c);
private:
Chunk *GetChunkFromIndex(const QModelIndex &index) const;
Chunk *chunk_;
};
#endif // CHUNKMODEL_H

11
app/main.cpp Normal file
View file

@ -0,0 +1,11 @@
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}

50
app/mainwindow.cpp Normal file
View file

@ -0,0 +1,50 @@
#include "mainwindow.h"
#include <iostream>
#include <QFileDialog>
#include <QMenuBar>
#include <QSplitter>
#include <QTreeWidget>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow{parent}
{
auto splitter = new QSplitter();
this->setCentralWidget(splitter);
model_.SetChunk(&chunk_);
auto tree = new QTreeView();
tree->setModel(&model_);
splitter->addWidget(tree);
InitializeMenuBar();
}
void MainWindow::InitializeMenuBar()
{
auto menubar = new QMenuBar();
auto file_menu = menubar->addMenu(tr("&File"));
auto open_action = file_menu->addAction(tr("&Open"), this, &MainWindow::OpenFile, tr("Ctrl+O"));
auto save_action = file_menu->addAction(tr("&Save"));
auto save_as_action = file_menu->addAction(tr("Save &As"));
file_menu->addSeparator();
auto exit_action = file_menu->addAction(tr("E&xit"));
connect(exit_action, &QAction::triggered, this, &MainWindow::close);
setMenuBar(menubar);
}
void MainWindow::OpenFile()
{
QString s = QFileDialog::getOpenFileName(this, QString(), QString(), tr("Interleaf Files (*.si)"));
if (!s.isEmpty()) {
chunk_.Read(s.toStdString());
model_.SetChunk(&chunk_);
}
}

32
app/mainwindow.h Normal file
View file

@ -0,0 +1,32 @@
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <chunk.h>
#include <QMainWindow>
#include "chunkmodel.h"
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
signals:
private:
//bool CloseFile();
void InitializeMenuBar();
ChunkModel model_;
Chunk chunk_;
private slots:
void OpenFile();
//bool SaveFile();
//bool SaveFileAs();
};
#endif // MAINWINDOW_H

25
lib/CMakeLists.txt Normal file
View file

@ -0,0 +1,25 @@
add_library(libweaver SHARED
# Data types
data/data.cpp
data/data.h
data/generic.cpp
data/generic.h
data/mxst.cpp
data/mxst.h
data/riff.cpp
data/riff.h
# Chunk
chunk.cpp
chunk.h
# Common
libweaver_global.h
types.h
)
target_compile_definitions(libweaver PRIVATE LIBWEAVER_LIBRARY)
set_target_properties(libweaver PROPERTIES
CXX_STANDARD 98
CXX_STANDARD_REQUIRED ON
)

162
lib/chunk.cpp Normal file
View file

@ -0,0 +1,162 @@
#include "chunk.h"
#include <algorithm>
#include <iostream>
#include "data/generic.h"
#include "data/mxst.h"
#include "data/riff.h"
Chunk::Chunk()
{
id_ = 0;
data_ = NULL;
parent_ = NULL;
}
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;
}
return Read(file);
}
bool Chunk::Read(std::ifstream &f)
{
u32 size;
// Read ID and size, which every chunk starts with
f.read((char *) &id_, sizeof(id_));
f.read((char *) &size, sizeof(size));
//std::string s(reinterpret_cast<const char*>(&id_), 4);
// Store end of this chunk
u32 pos = f.tellg();
u32 end = pos + size;
// Read custom data from this chunk
Clear();
data_ = CreateDataFromID(id_);
data_->Read(f, size);
// Assume any remaining data is this chunk's children
while (f.good() && f.tellg() < end) {
Chunk *child = new Chunk();
child->Read(f);
this->AppendChild(child);
}
if (f.tellg()%2 == 1) {
f.seekg(1, std::ios::cur);
}
return true;
}
void Chunk::Clear()
{
// Delete data
if (data_) {
delete data_;
data_ = NULL;
}
// Delete children
for (Children::iterator it = children_.begin(); it != children_.end(); it++) {
delete (*it);
}
children_.clear();
}
void Chunk::AppendChild(Chunk *chunk)
{
// If this chunk has another parent, remove it from that parent
if (chunk->parent_) {
chunk->parent_->RemoveChild(chunk);
}
// Append it to this chunk
chunk->parent_ = this;
children_.push_back(chunk);
}
bool Chunk::RemoveChild(Chunk *chunk)
{
// If this chunk's parent is not this, return
if (chunk->parent_ != this) {
return false;
}
// Find chunk in children, if doesn't exist, return false
Children::iterator it = std::find(children_.begin(), children_.end(), chunk);
if (it == children_.end()) {
return false;
}
chunk->parent_ = NULL;
children_.erase(it);
return true;
}
size_t Chunk::IndexOfChild(Chunk *chunk)
{
return std::find(children_.begin(), children_.end(), chunk) - children_.begin();
}
void Chunk::InsertChild(size_t index, Chunk *chunk)
{
// If this chunk has another parent, remove it from that parent
if (chunk->parent_) {
chunk->parent_->RemoveChild(chunk);
}
// Insert at position
chunk->parent_ = this;
children_.insert(children_.begin() + index, chunk);
}
Data *Chunk::CreateDataFromID(u32 id)
{
switch (static_cast<Type>(id)) {
case RIFF:
return new RIFFData();
case LIST:
return new RIFFData();
case MxSt:
return new MxStData();
}
return new GenericData();
}
const char *Chunk::GetTypeDescription(Type type)
{
switch (type) {
case RIFF:
return "Resource Interchange File Format";
case LIST:
return "List of sub-elements";
case MxSt:
return "MxStreamer";
}
return "Unknown";
}

64
lib/chunk.h Normal file
View file

@ -0,0 +1,64 @@
#ifndef CHUNK_H
#define CHUNK_H
#include <fstream>
#include <memory>
#include "data/data.h"
#include "types.h"
class Chunk
{
public:
enum Type
{
RIFF = 0x46464952,
LIST = 0x5453494c,
MxSt = 0x7453784d
};
Chunk();
virtual ~Chunk();
bool Read(const std::string &f);
bool Read(const char *f);
bool Read(std::ifstream &f);
void Clear();
typedef std::vector<Chunk*> Children;
Chunk *GetParent() const { return parent_; }
const Children &GetChildren() const { return children_; }
void AppendChild(Chunk *chunk);
bool RemoveChild(Chunk *chunk);
size_t IndexOfChild(Chunk *chunk);
void InsertChild(size_t index, Chunk *chunk);
Chunk *RemoveChild(size_t index);
Chunk *GetChildAt(size_t index) const { return children_.at(index); }
size_t GetChildCount() const { return children_.size(); }
Type type() const { return static_cast<Type>(id_); }
const u32 &id() const { return id_; }
static Data *CreateDataFromID(u32 id);
static const char *GetTypeDescription(Type type);
const char *GetTypeDescription() const
{
return GetTypeDescription(type());
}
private:
// Disable copy
Chunk(const Chunk& other);
Chunk& operator=(const Chunk& other);
u32 id_;
Data *data_;
Chunk *parent_;
Children children_;
};
#endif // CHUNK_H

9
lib/data/data.cpp Normal file
View file

@ -0,0 +1,9 @@
#include "data.h"
Data::Data()
{
}
Data::~Data()
{
}

19
lib/data/data.h Normal file
View file

@ -0,0 +1,19 @@
#ifndef DATA_H
#define DATA_H
#include <fstream>
#include "types.h"
class Chunk;
class Data
{
public:
Data();
virtual ~Data();
virtual void Read(std::ifstream &f, u32 sz) = 0;
};
#endif // DATA_H

11
lib/data/generic.cpp Normal file
View file

@ -0,0 +1,11 @@
#include "generic.h"
GenericData::GenericData()
{
}
void GenericData::Read(std::ifstream &f, u32 sz)
{
bytes.resize(sz);
f.read((char*) bytes.data(), sz);
}

17
lib/data/generic.h Normal file
View file

@ -0,0 +1,17 @@
#ifndef GENERICDATA_H
#define GENERICDATA_H
#include "data.h"
class GenericData : public Data
{
public:
GenericData();
virtual void Read(std::ifstream &f, u32 sz);
bytearray bytes;
};
#endif // GENERICDATA_H

11
lib/data/mxst.cpp Normal file
View file

@ -0,0 +1,11 @@
#include "mxst.h"
MxStData::MxStData()
{
}
void MxStData::Read(std::ifstream &f, u32 sz)
{
// MxSt has no members
}

15
lib/data/mxst.h Normal file
View file

@ -0,0 +1,15 @@
#ifndef MXSTDATA_H
#define MXSTDATA_H
#include "data.h"
class MxStData : public Data
{
public:
MxStData();
virtual void Read(std::ifstream &f, u32 sz);
};
#endif // MXSTDATA_H

11
lib/data/riff.cpp Normal file
View file

@ -0,0 +1,11 @@
#include "riff.h"
RIFFData::RIFFData()
{
}
void RIFFData::Read(std::ifstream &f, u32 sz)
{
f.read((char *) &id, sizeof(id));
}

17
lib/data/riff.h Normal file
View file

@ -0,0 +1,17 @@
#ifndef RIFFDATA_H
#define RIFFDATA_H
#include "chunk.h"
class RIFFData : public Data
{
public:
RIFFData();
virtual void Read(std::ifstream &f, u32 sz);
u32 id;
};
#endif // RIFFDATA_H

22
lib/libweaver_global.h Normal file
View file

@ -0,0 +1,22 @@
#ifndef LIBWEAVER_GLOBAL_H
#define LIBWEAVER_GLOBAL_H
#if defined(_MSC_VER) || defined(WIN64) || defined(_WIN64) || defined(__WIN64__) || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
# define Q_DECL_EXPORT __declspec(dllexport)
# define Q_DECL_IMPORT __declspec(dllimport)
#else
# define Q_DECL_EXPORT __attribute__((visibility("default")))
# define Q_DECL_IMPORT __attribute__((visibility("default")))
#endif
#if defined(LIBWEAVER_LIBRARY)
# define LIBWEAVER_EXPORT Q_DECL_EXPORT
#else
# define LIBWEAVER_EXPORT Q_DECL_IMPORT
#endif
#ifdef _WIN32
#define LIBWEAVER_OS_WINDOWS
#endif
#endif // LIBWEAVER_GLOBAL_H

16
lib/types.h Normal file
View file

@ -0,0 +1,16 @@
#ifndef TYPES_H
#define TYPES_H
#include <vector>
typedef unsigned char u8;
typedef char s8;
typedef unsigned short u16;
typedef short s16;
typedef unsigned int u32;
typedef int s32;
typedef u8 byte;
typedef std::vector<byte> bytearray;
#endif // TYPES_H