SIEdit/lib/object.cpp

278 lines
5.3 KiB
C++
Raw Normal View History

2022-07-11 00:16:20 -04:00
#include "object.h"
2022-07-11 17:19:36 -04:00
#include <iostream>
2022-07-18 03:27:00 -04:00
#include "othertypes.h"
2022-07-17 21:51:16 -04:00
#include "util.h"
2022-07-11 00:16:20 -04:00
namespace si {
Object::Object()
{
2022-07-11 17:19:36 -04:00
type_ = MxOb::Null;
id_ = 0;
2022-07-11 00:16:20 -04:00
}
2022-07-18 12:49:27 -04:00
#ifdef _WIN32
bool Object::ReplaceWithFile(const wchar_t *f)
{
2022-07-18 14:25:00 -04:00
File is;
if (!is.Open(f, File::Read)) {
2022-07-18 12:49:27 -04:00
return false;
}
2022-07-18 14:25:00 -04:00
return ReplaceWithFile(&is);
2022-07-18 12:49:27 -04:00
}
bool Object::ExtractToFile(const wchar_t *f) const
{
2022-07-18 14:25:00 -04:00
File os;
if (!os.Open(f, File::Write)) {
2022-07-18 12:49:27 -04:00
return false;
}
2022-07-18 14:25:00 -04:00
return ExtractToFile(&os);
2022-07-18 12:49:27 -04:00
}
#endif
2022-07-18 03:27:00 -04:00
bool Object::ReplaceWithFile(const char *f)
2022-07-11 00:16:20 -04:00
{
2022-07-18 14:25:00 -04:00
File is;
if (!is.Open(f, File::Read)) {
2022-07-18 03:27:00 -04:00
return false;
2022-07-11 04:48:20 -04:00
}
2022-07-18 14:25:00 -04:00
return ReplaceWithFile(&is);
2022-07-18 03:27:00 -04:00
}
2022-07-11 04:48:20 -04:00
2022-07-18 03:27:00 -04:00
bool Object::ExtractToFile(const char *f) const
{
2022-07-18 14:25:00 -04:00
File os;
if (!os.Open(f, File::Write)) {
2022-07-18 03:27:00 -04:00
return false;
}
2022-07-18 14:25:00 -04:00
return ExtractToFile(&os);
2022-07-11 00:16:20 -04:00
}
2022-07-18 14:25:00 -04:00
bool Object::ReplaceWithFile(FileBase *f)
2022-07-11 17:19:36 -04:00
{
2022-07-18 03:27:00 -04:00
data_.clear();
switch (this->filetype()) {
case MxOb::WAV:
{
2022-07-18 14:25:00 -04:00
if (f->ReadU32() != RIFF::RIFF_) {
2022-07-18 03:27:00 -04:00
return false;
2022-07-11 17:19:36 -04:00
}
2022-07-18 03:27:00 -04:00
// Skip total size
2022-07-18 14:25:00 -04:00
f->ReadU32();
2022-07-11 17:19:36 -04:00
2022-07-18 14:25:00 -04:00
if (f->ReadU32() != RIFF::WAVE) {
2022-07-18 03:27:00 -04:00
return false;
}
2022-07-11 11:04:47 -04:00
2022-07-18 03:27:00 -04:00
bytearray fmt;
bytearray data;
2022-07-18 14:25:00 -04:00
while (!f->atEnd()) {
uint32_t id = f->ReadU32();
uint32_t sz = f->ReadU32();
2022-07-18 03:27:00 -04:00
if (id == RIFF::fmt_) {
2022-07-18 14:25:00 -04:00
fmt = f->ReadBytes(sz);
2022-07-18 03:27:00 -04:00
} else if (id == RIFF::data) {
2022-07-18 14:25:00 -04:00
data = f->ReadBytes(sz);
2022-07-18 03:27:00 -04:00
} else {
2022-07-18 14:25:00 -04:00
f->seek(sz, File::SeekCurrent);
2022-07-18 03:27:00 -04:00
}
}
if (fmt.empty() || data.empty()) {
return false;
}
data_.push_back(fmt);
WAVFmt *fmt_info = fmt.cast<WAVFmt>();
size_t second_in_bytes = fmt_info->Channels * fmt_info->SampleRate * (fmt_info->BitsPerSample/8);
size_t max;
for (size_t i=0; i<data.size(); i+=max) {
max = std::min(data.size() - i, second_in_bytes);
data_.push_back(bytearray(data.data() + i, max));
}
return true;
}
case MxOb::SMK:
{
// Read header
2022-07-18 14:25:00 -04:00
bytearray hdr = f->ReadBytes(sizeof(SMK2));
2022-07-18 03:27:00 -04:00
// Read frame sizes
SMK2 smk = *hdr.cast<SMK2>();
2022-07-18 14:25:00 -04:00
bytearray frame_sizes = f->ReadBytes(smk.Frames * sizeof(uint32_t));
2022-07-18 03:27:00 -04:00
hdr.append(frame_sizes);
// Read frame types
2022-07-18 14:25:00 -04:00
hdr.append(f->ReadBytes(smk.Frames));
2022-07-18 03:27:00 -04:00
// Read Huffman trees
2022-07-18 14:25:00 -04:00
hdr.append(f->ReadBytes(smk.TreesSize));
2022-07-18 03:27:00 -04:00
// Place header into data vector
data_.resize(smk.Frames + 1);
data_[0] = hdr;
uint32_t *real_sizes = frame_sizes.cast<uint32_t>();
for (uint32_t i=0; i<smk.Frames; i++) {
uint32_t sz = real_sizes[i];
if (sz > 0) {
2022-07-18 14:25:00 -04:00
data_[i+1] = f->ReadBytes(sz);
2022-07-18 03:27:00 -04:00
}
}
return true;
}
default:
LogWarning() << "Don't yet know how to chunk type " << RIFF::PrintU32AsString(this->filetype()) << std::endl;
break;
}
return false;
2022-07-11 11:04:47 -04:00
}
2022-07-18 14:25:00 -04:00
bool Object::ExtractToFile(FileBase *f) const
2022-07-11 11:04:47 -04:00
{
if (data_.empty()) {
return false;
}
2022-07-18 03:27:00 -04:00
switch (this->filetype()) {
2022-07-11 04:48:20 -04:00
case MxOb::WAV:
{
2022-07-18 03:27:00 -04:00
// Write RIFF header
2022-07-18 14:25:00 -04:00
RIFF::Chk riff = RIFF::BeginChunk(f, RIFF::RIFF_);
2022-07-18 03:27:00 -04:00
2022-07-18 14:25:00 -04:00
f->WriteU32(RIFF::WAVE);
2022-07-18 03:27:00 -04:00
{
2022-07-18 14:25:00 -04:00
RIFF::Chk fmt = RIFF::BeginChunk(f, RIFF::fmt_);
2022-07-18 03:27:00 -04:00
2022-07-18 14:25:00 -04:00
f->WriteBytes(data_.at(0));
2022-07-18 03:27:00 -04:00
2022-07-18 14:25:00 -04:00
RIFF::EndChunk(f, fmt);
2022-07-18 03:27:00 -04:00
}
2022-07-11 04:48:20 -04:00
2022-07-18 03:27:00 -04:00
{
2022-07-18 14:25:00 -04:00
RIFF::Chk data = RIFF::BeginChunk(f, RIFF::data);
2022-07-18 03:27:00 -04:00
// Merge all chunks after the first one
for (size_t i=1; i<data_.size(); i++) {
2022-07-18 14:25:00 -04:00
f->WriteBytes(data_.at(i));
2022-07-18 03:27:00 -04:00
}
2022-07-18 14:25:00 -04:00
RIFF::EndChunk(f, data);
2022-07-11 04:48:20 -04:00
}
2022-07-18 14:25:00 -04:00
RIFF::EndChunk(f, riff);
2022-07-11 04:48:20 -04:00
break;
}
case MxOb::STL:
{
2022-07-18 03:27:00 -04:00
static const uint32_t BMP_HDR_SZ = 14;
2022-07-11 04:48:20 -04:00
2022-07-18 03:27:00 -04:00
// Write BMP header
2022-07-18 14:25:00 -04:00
f->WriteU16(0x4D42);
2022-07-11 04:48:20 -04:00
2022-07-18 03:27:00 -04:00
// Write placeholder for size
2022-07-18 14:25:00 -04:00
size_t sz_loc = f->pos();
f->WriteU32(0);
2022-07-11 04:48:20 -04:00
2022-07-18 03:27:00 -04:00
// Write "reserved" bytes
2022-07-18 14:25:00 -04:00
f->WriteU32(0);
2022-07-11 04:48:20 -04:00
2022-07-18 03:27:00 -04:00
// Write data offset
2022-07-18 14:25:00 -04:00
f->WriteU32(data_.at(0).size() + BMP_HDR_SZ);
2022-07-18 03:27:00 -04:00
for (size_t i=0; i<data_.size(); i++) {
2022-07-18 14:25:00 -04:00
f->WriteBytes(data_.at(i));
2022-07-18 03:27:00 -04:00
}
2022-07-11 04:48:20 -04:00
2022-07-18 14:25:00 -04:00
size_t len = f->pos();
f->seek(sz_loc);
f->WriteU32(len);
2022-07-11 04:48:20 -04:00
break;
}
2022-07-11 17:20:56 -04:00
case MxOb::FLC:
{
// First chunk is a complete FLIC header, so add it as-is
2022-07-18 14:25:00 -04:00
f->WriteBytes(data_.at(0));
2022-07-11 17:20:56 -04:00
// Subsequent chunks are FLIC frames with an additional 20 byte header that needs to be stripped
const int CUSTOM_HEADER_SZ = 20;
2022-07-18 03:27:00 -04:00
for (size_t i=1; i<data_.size(); i++) {
2022-07-18 14:25:00 -04:00
f->WriteData(data_.at(i).data() + CUSTOM_HEADER_SZ, data_.at(i).size() - CUSTOM_HEADER_SZ);
2022-07-11 17:20:56 -04:00
}
break;
}
2022-07-18 03:27:00 -04:00
default:
LogWarning() << "Didn't know how to extract type '" << RIFF::PrintU32AsString(filetype()) << "', merging..." << std::endl;
/* fall-through */
case MxOb::SMK:
case MxOb::OBJ:
// Simply merge
2022-07-18 03:27:00 -04:00
for (size_t i=0; i<data_.size(); i++) {
2022-07-18 14:25:00 -04:00
f->WriteBytes(data_.at(i));
2022-07-11 17:20:56 -04:00
}
break;
2022-07-11 04:48:20 -04:00
}
2022-07-11 11:04:47 -04:00
2022-07-18 03:27:00 -04:00
return true;
2022-07-11 11:04:47 -04:00
}
2022-07-18 03:27:00 -04:00
bytearray Object::ExtractToMemory() const
2022-07-11 11:04:47 -04:00
{
2022-07-18 14:25:00 -04:00
MemoryBuffer buf;
2022-07-18 03:27:00 -04:00
2022-07-18 14:25:00 -04:00
ExtractToFile(&buf);
2022-07-18 03:27:00 -04:00
return buf.data();
2022-07-11 11:04:47 -04:00
}
const bytearray &Object::GetFileHeader() const
2022-07-11 11:04:47 -04:00
{
return data_.at(0);
2022-07-11 11:04:47 -04:00
}
bytearray Object::GetFileBody() const
{
bytearray b;
for (size_t i=1; i<data_.size(); i++) {
b.append(data_.at(i));
2022-07-11 11:04:47 -04:00
}
return b;
}
size_t Object::GetFileBodySize() const
{
size_t s = 0;
for (size_t i=1; i<data_.size(); i++) {
s += data_.at(i).size();
2022-07-11 11:04:47 -04:00
}
return s;
2022-07-11 04:48:20 -04:00
}
Object *Object::FindSubObjectWithID(uint32_t id)
{
if (this->id() == id) {
return this;
}
for (Children::const_iterator it=GetChildren().begin(); it!=GetChildren().end(); it++) {
if (Object *o = static_cast<Object*>(*it)->FindSubObjectWithID(id)) {
2022-07-11 04:48:20 -04:00
return o;
}
}
return NULL;
}
2022-07-11 00:16:20 -04:00
}