SIEdit/lib/object.cpp
2022-07-18 00:27:00 -07:00

265 lines
5.4 KiB
C++

#include "object.h"
#include <iostream>
#include "othertypes.h"
#include "util.h"
namespace si {
Object::Object()
{
type_ = MxOb::Null;
id_ = 0;
last_chunk_split_ = false;
}
bool Object::ReplaceWithFile(const char *f)
{
std::ifstream is(f);
if (!is.is_open() || !is.good()) {
return false;
}
return ReplaceWithFile(is);
}
bool Object::ExtractToFile(const char *f) const
{
std::ofstream os(f);
if (!os.is_open() || !os.good()) {
return false;
}
return ExtractToFile(os);
}
bool Object::ReplaceWithFile(std::istream &is)
{
data_.clear();
switch (this->filetype()) {
case MxOb::WAV:
{
if (ReadU32(is) != RIFF::RIFF_) {
return false;
}
// Skip total size
ReadU32(is);
if (ReadU32(is) != RIFF::WAVE) {
return false;
}
bytearray fmt;
bytearray data;
while (is.good()) {
uint32_t id = ReadU32(is);
uint32_t sz = ReadU32(is);
if (id == RIFF::fmt_) {
fmt.resize(sz);
is.read(fmt.data(), fmt.size());
} else if (id == RIFF::data) {
data.resize(sz);
is.read(data.data(), data.size());
} else {
is.seekg(sz, std::ios::cur);
}
}
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
bytearray hdr(sizeof(SMK2));
is.read(hdr.data(), hdr.size());
// Read frame sizes
SMK2 smk = *hdr.cast<SMK2>();
bytearray frame_sizes(smk.Frames * sizeof(uint32_t));
is.read(frame_sizes.data(), frame_sizes.size());
hdr.append(frame_sizes);
// Read frame types
bytearray frame_types(smk.Frames);
is.read(frame_types.data(), frame_types.size());
hdr.append(frame_types);
// Read Huffman trees
bytearray huffman(smk.TreesSize);
is.read(huffman.data(), huffman.size());
hdr.append(huffman);
// 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) {
bytearray &d = data_[i+1];
d.resize(sz);
is.read(d.data(), d.size());
}
}
return true;
}
default:
LogWarning() << "Don't yet know how to chunk type " << RIFF::PrintU32AsString(this->filetype()) << std::endl;
break;
}
return false;
}
bool Object::ExtractToFile(std::ostream &os) const
{
switch (this->filetype()) {
case MxOb::WAV:
{
// Write RIFF header
RIFF::Chk riff = RIFF::BeginChunk(os, RIFF::RIFF_);
WriteU32(os, RIFF::WAVE);
{
RIFF::Chk fmt = RIFF::BeginChunk(os, RIFF::fmt_);
WriteBytes(os, data_.at(0));
RIFF::EndChunk(os, fmt);
}
{
RIFF::Chk data = RIFF::BeginChunk(os, RIFF::data);
// Merge all chunks after the first one
for (size_t i=1; i<data_.size(); i++) {
WriteBytes(os, data_.at(i));
}
RIFF::EndChunk(os, data);
}
RIFF::EndChunk(os, riff);
break;
}
case MxOb::STL:
{
static const uint32_t BMP_HDR_SZ = 14;
// Write BMP header
WriteU16(os, 0x4D42);
// Write placeholder for size
std::ios::pos_type sz_loc = os.tellp();
WriteU32(os, 0);
// Write "reserved" bytes
WriteU32(os, 0);
// Write data offset
WriteU32(os, data_.at(0).size() + BMP_HDR_SZ);
for (size_t i=0; i<data_.size(); i++) {
WriteBytes(os, data_.at(i));
}
std::ios::pos_type len = os.tellp();
os.seekp(sz_loc);
WriteU32(os, len);
break;
}
case MxOb::FLC:
{
// First chunk is a complete FLIC header, so add it as-is
WriteBytes(os, data_.at(0));
// Subsequent chunks are FLIC frames with an additional 20 byte header that needs to be stripped
const int CUSTOM_HEADER_SZ = 20;
for (size_t i=1; i<data_.size(); i++) {
os.write(data_.at(i).data() + CUSTOM_HEADER_SZ, data_.at(i).size() - CUSTOM_HEADER_SZ);
}
break;
}
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
for (size_t i=0; i<data_.size(); i++) {
WriteBytes(os, data_.at(i));
}
break;
}
return true;
}
bytearray Object::ExtractToMemory() const
{
memorybuf buf;
std::ostream os(&buf);
ExtractToFile(os);
return buf.data();
}
const bytearray &Object::GetFileHeader() const
{
return data_.at(0);
}
bytearray Object::GetFileBody() const
{
bytearray b;
for (size_t i=1; i<data_.size(); i++) {
b.append(data_.at(i));
}
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();
}
return s;
}
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)) {
return o;
}
}
return NULL;
}
}