Skip to content

Commit

Permalink
Move Chunk class to Lwo2Chunk and into separate file pair.
Browse files Browse the repository at this point in the history
Refactoring and cleanup.
Adjust Makefile.am.
  • Loading branch information
codereader committed Jul 29, 2017
1 parent 57ab1bd commit e68ba42
Show file tree
Hide file tree
Showing 7 changed files with 204 additions and 196 deletions.
94 changes: 94 additions & 0 deletions plugins/model/Lwo2Chunk.cpp
@@ -0,0 +1,94 @@
#include "Lwo2Chunk.h"

#include "bytestreamutils.h"

namespace model
{

Lwo2Chunk::Lwo2Chunk(const std::string& identifier_, Type type) :
_chunkType(type),
identifier(identifier_),
stream(std::ios_base::in | std::ios_base::out | std::ios_base::binary)
{
// FORM sub-chunks are normal chunks and have 4 bytes size info
// whereas subchunks of e.g. CLIP use 2 bytes of size info
_sizeDescriptorByteCount = _chunkType == Type::Chunk ? 4 : 2;
}

unsigned int Lwo2Chunk::getContentSize() const
{
unsigned int totalSize = 0;

// Start with the size of the contents
// (don't use seek as we don't know if the client still wants to write stuff)
totalSize += static_cast<unsigned int>(stream.str().length());

if (!subChunks.empty())
{
// Sum up the size of the subchunks
for (const Lwo2Chunk::Ptr& chunk : subChunks)
{
totalSize += 4; // ID (4 bytes)
totalSize += chunk->_sizeDescriptorByteCount; // Subchunk Size Info (can be 4 or 2 bytes)

// While the child chunk size itself doesn't include padding, we need to respect
// it when calculating the size of this parent chunk
unsigned int childChunkSize = chunk->getContentSize();
totalSize += childChunkSize + (childChunkSize % 2); // add 1 padding byte if odd
}
}

// Chunk size can be odd, padding must be handled by client code
return totalSize;
}

Lwo2Chunk::Ptr Lwo2Chunk::addChunk(const std::string& identifier_, Type type)
{
subChunks.push_back(std::make_shared<Lwo2Chunk>(identifier_, type));
return subChunks.back();
}

void Lwo2Chunk::flushBuffer()
{
stream.flush();

for (const Lwo2Chunk::Ptr& chunk : subChunks)
{
chunk->flushBuffer();
}
}

void Lwo2Chunk::writeToStream(std::ostream& output)
{
// Flush all buffers before writing to the output stream
flushBuffer();

output.write(identifier.c_str(), identifier.length());

if (_chunkType == Type::Chunk)
{
stream::writeBigEndian<uint32_t>(output, getContentSize());
}
else
{
stream::writeBigEndian<uint16_t>(output, getContentSize());
}

// Write the direct contents of this chunk
std::string str = stream.str();
output.write(str.c_str(), str.length());

// Write all subchunks
for (const Lwo2Chunk::Ptr& chunk : subChunks)
{
chunk->writeToStream(output);

// Add the padding byte after the chunk
if (chunk->getContentSize() % 2 == 1)
{
output.write("\0", 1);
}
}
}

}
54 changes: 54 additions & 0 deletions plugins/model/Lwo2Chunk.h
@@ -0,0 +1,54 @@
#pragma once

#include <string>
#include <memory>
#include <vector>
#include <sstream>

namespace model
{

// Represents a Chunk in the LWO2 file, accepting content
// through the public stream member.
// A Chunk can have contents and/or 1 or more subchunks.
class Lwo2Chunk
{
public:
typedef std::shared_ptr<Lwo2Chunk> Ptr;

enum class Type
{
Chunk,
SubChunk
};

private:
Type _chunkType;

// The number of bytes used for the size info of this chunk
unsigned int _sizeDescriptorByteCount;

public:
std::string identifier; // the 4-byte ID

// Child chunks
std::vector<Lwo2Chunk::Ptr> subChunks;

// Stream binary data into here
std::stringstream stream;

Lwo2Chunk(const std::string& identifier_, Type type);

// Returns the size of this Chunk's content
// excluding this Chunk's ID (4 bytes) and Size info (4 bytes)
unsigned int getContentSize() const;

// Adds the specified empty Chunk and returns its reference
Lwo2Chunk::Ptr addChunk(const std::string& identifier_, Type type);

void flushBuffer();

void writeToStream(std::ostream& output);
};

}

0 comments on commit e68ba42

Please sign in to comment.