mirror of
https://github.com/isledecomp/SIEdit.git
synced 2024-11-27 09:35:45 -05:00
265 lines
5.4 KiB
C++
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;
|
|
}
|
|
|
|
}
|