Skip to content
This repository has been archived by the owner on Apr 25, 2022. It is now read-only.

Commit

Permalink
Added support for TLG0; refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
Marcin Kurczewski committed Dec 7, 2014
1 parent 9ac690c commit 75f13e6
Show file tree
Hide file tree
Showing 16 changed files with 285 additions and 53 deletions.
5 changes: 5 additions & 0 deletions src-ruby/lib/image.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class Image
attr_accessor :width
attr_accessor :height
attr_accessor :pixels
end
57 changes: 57 additions & 0 deletions src-ruby/lib/tlg0_reader.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
require_relative 'tlg_reader'
require_relative 'tlg5_reader'
require_relative 'tlg6_reader'
require 'rubygems'
require 'RMagick'

class Tlg0Reader < TlgReader
MAGIC = "\x54\x4c\x47\x30\x2e\x30\x00\x73\x64\x73\x1a"

def read_stream(file)
assert_magic(file)
_raw_data_size = file.read(4).unpack('<L')[0]
magic2 = file.read(11)
file.seek(-11, 1)
image = reader_from_magic(magic2).new.read_stream(file)
process_chunks(file)
image
end

private

def process_chunks(file)
until file.eof?
chunk_name = file.read(4)
chunk_size = file.read(4).unpack('<L')[0]
chunk_data = file.read(chunk_size)
process_tag_chunk(chunk_data) if chunk_name == 'tags'
end
end

def process_tag_chunk(chunk_data)
until chunk_data.empty?
key, chunk_data = extract_string(chunk_data)
_, _, chunk_data = chunk_data.partition('=')
value, chunk_data = extract_string(chunk_data)
_, _, chunk_data = chunk_data.partition(',')
puts 'Tag found: ' + key + ' = ' + value
end
end

def extract_string(raw)
size, _colon, raw = raw.partition(':')
size = size.to_i
value = raw[0..(size - 1)]
raw = raw[size..-1]
[value, raw]
end

def assert_magic(file)
fail 'Not a TLG0 file ' if file.read(11) != MAGIC
end

def reader_from_magic(magic)
return Tlg5Reader if magic == Tlg5Reader::MAGIC
return Tlg6Reader if magic == Tlg6Reader::MAGIC
end
end
39 changes: 17 additions & 22 deletions src-ruby/lib/tlg5_reader.rb
Original file line number Diff line number Diff line change
@@ -1,32 +1,27 @@
require_relative 'image'
require_relative 'tlg_reader'
require 'stringio'

class Tlg5Reader
class Tlg5Reader < TlgReader
MAGIC = "\x54\x4c\x47\x35\x2e\x30\x00\x72\x61\x77\x1a"

attr_accessor :width
attr_accessor :height
attr_accessor :pixels
def read_stream(file)
assert_magic(file)
@header = Tlg5Header.new(file)
unless [3, 4].include?(@header.channel_count)
fail 'Unsupported channel count: ' + @header.channel_count.to_s
end
skip_block_information(file)

def self.read(input_path)
self.new(input_path)
image = Image.new
image.width = @header.image_width
image.height = @header.image_height
image.pixels = read_pixels(file)
image
end

private

def initialize(input_path)
open(input_path, 'rb') do |file|
assert_magic(file)
@header = Tlg5Header.new(file)
unless [3, 4].include?(@header.channel_count)
fail 'Unsupported channel count: ' + @header.channel_count.to_s
end
skip_block_information(file)
@width = @header.image_width
@height = @header.image_height
@pixels = read_pixels(file)
end
end

def assert_magic(file)
fail 'Not a TLG5 file ' if file.read(11) != MAGIC
end
Expand All @@ -51,7 +46,7 @@ def load_pixel_block_row(channel_data, block_y, output_pixels)
max_y = @header.image_height if max_y > @header.image_height
use_alpha = @header.channel_count == 4

(block_y..max_y-1).each do |y|
(block_y..(max_y - 1)).each do |y|
prev_red = 0
prev_green = 0
prev_blue = 0
Expand Down Expand Up @@ -129,7 +124,7 @@ def decompress_block(block_info)
i += 1
end
j = 0
while j < length do
while j < length
c = @compressor_state.text[position]
output_data << c
@compressor_state.text[@compressor_state.offset] = c
Expand Down
11 changes: 5 additions & 6 deletions src-ruby/lib/tlg6_reader.rb
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
class Tlg6Reader
MAGIC = "\x54\x4c\x47\x36\x2e\x30\x00\x72\x61\x77\x1a"
require_relative 'tlg_reader'

attr_accessor :width
attr_accessor :height
attr_accessor :pixels
class Tlg6Reader < TlgReader
MAGIC = "\x54\x4c\x47\x36\x2e\x30\x00\x72\x61\x77\x1a"

def self.read(_input_path)
def read_stream(file)
fail 'Not a TLG6 file ' if file.read(11) != MAGIC
fail 'Not implemented! Please send sample files to @rr- on github.'
end
end
9 changes: 6 additions & 3 deletions src-ruby/lib/tlg_converter.rb
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
require_relative 'tlg0_reader'
require_relative 'tlg5_reader'
require_relative 'tlg6_reader'
require 'rubygems'
require 'RMagick'

class TlgConverter
def self.read(input_path)
self.new(input_path)
new(input_path)
end

def save(output_path)
Expand All @@ -25,12 +26,14 @@ def save(output_path)

def initialize(input_path)
open(input_path, 'rb') do |file|
@reader = reader(file).read(file.path)
@reader = reader_type(file).new.read_stream(file)
end
end

def reader(file)
def reader_type(file)
magic = file.read(11)
file.seek(0, 0)
return Tlg0Reader if magic == Tlg0Reader::MAGIC
return Tlg5Reader if magic == Tlg5Reader::MAGIC
return Tlg6Reader if magic == Tlg6Reader::MAGIC
fail 'Not a TLG image file'
Expand Down
9 changes: 9 additions & 0 deletions src-ruby/lib/tlg_reader.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
class TlgReader
def read(input_path)
open(input_path, 'rb') { |file| read_stream(file) }
end

def read_stream(file)
fail 'Implement me'
end
end
65 changes: 58 additions & 7 deletions src/AbstractTlgReader.cc
Original file line number Diff line number Diff line change
@@ -1,31 +1,82 @@
#include <cstring>
#include <fstream>
#include <memory>
#include <stdexcept>
#include <vector>
#include "AbstractTlgReader.h"
#include "BadMagicException.h"
#include "Tlg0Reader.h"
#include "Tlg5Reader.h"
#include "Tlg6Reader.h"

std::unique_ptr<const AbstractTlgReader>
AbstractTlgReader::choose_reader(std::ifstream &ifs)
{
std::vector<AbstractTlgReader*> readers
{
new Tlg0Reader(),
new Tlg5Reader(),
new Tlg6Reader(),
};

off_t pos = ifs.tellg();
for (auto reader : readers)
{
try
{
ifs.seekg(pos, ifs.beg);
if (reader->is_magic_valid(ifs))
{
return std::unique_ptr<AbstractTlgReader>(reader);
}
}
catch (BadMagicException const &e)
{
continue;
}
}

throw std::runtime_error("Not a TLG image");
}

const Image AbstractTlgReader::read(std::string path) const
{
std::ifstream ifs(path, std::ifstream::in | std::ifstream::binary);
if (!ifs)
throw std::runtime_error("Can\'t open " + path + " for reading");

try
{
ifs.seekg(0, ifs.beg);
if (!is_magic_valid(ifs))
throw BadMagicException();
auto ret = read_raw_data(ifs);
ifs.close();
return ret;
}
catch (std::exception const &e)
{
ifs.close();
throw;
}
}

const bool AbstractTlgReader::is_magic_valid(std::ifstream &ifs) const
{
bool result = false;
auto magic_size = get_magic().size();
char *actual = new char[magic_size];
try
{
ifs.seekg(0, ifs.beg);
ifs.read(actual, magic_size);
if (std::strncmp(actual, get_magic().data(), magic_size) != 0)
if (std::strncmp(actual, get_magic().data(), magic_size) == 0)
{
throw BadMagicException();
result = true;
}
return read_from_stream(ifs);
}
catch (std::exception const &e)
{
delete[] actual;
ifs.close();
throw;
}
delete[] actual;
return result;
}
17 changes: 13 additions & 4 deletions src/AbstractTlgReader.h
Original file line number Diff line number Diff line change
@@ -1,17 +1,26 @@
#ifndef ABSTRACT_TLG_READER_H_
#define ABSTRACT_TLG_READER_H_
#include <cstdint>
#include <fstream>
#include <memory>
#include <string>
#include "Image.h"

class AbstractTlgReader
{
friend class Tlg0Reader;

public:
virtual const std::string get_magic() const = 0;
static std::unique_ptr<const AbstractTlgReader>
choose_reader(std::ifstream &ifs);

const Image read(std::string path) const;

protected:
virtual const Image read_from_stream(std::ifstream &stream) const = 0;
private:
virtual const Image read_raw_data(std::ifstream &stream) const = 0;

virtual const std::string get_magic() const = 0;

const bool is_magic_valid(std::ifstream &ifs) const;
};

#endif
80 changes: 80 additions & 0 deletions src/Tlg0Reader.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
#include <cstring>
#include <string>
#include <iostream>
#include <memory>
#include <stdexcept>
#include "Tlg0Reader.h"
#include "Tlg5Reader.h"
#include "Tlg6Reader.h"

namespace
{
std::string extract_string(char *&ptr)
{
int length = 0;
while (*ptr >= '0' && *ptr <= '9')
{
length *= 10;
length += *ptr++ - '0';
}

if (*ptr != ':')
return "";
ptr ++;

std::string value;
for (int i = 0; i < length; i ++)
value += *ptr ++;

return value;
}

void process_tag_chunk(std::unique_ptr<char> chunk_data, size_t chunk_size)
{
char *start = chunk_data.get();
char *ptr = start;
while (ptr < start + chunk_size)
{
auto key = extract_string(ptr);
ptr ++;
auto value = extract_string(ptr);
ptr ++;
std::cout << "Tag found: " << key << " = " << value << std::endl;
}
}

void process_chunks(std::ifstream &ifs)
{
char chunk_name[4];
while (ifs.read(chunk_name, 4))
{
uint32_t chunk_size;
ifs.read((char*) &chunk_size, 4);

auto chunk_data = std::unique_ptr<char>(new char[chunk_size]);
ifs.read(chunk_data.get(), chunk_size);
if (std::strncmp(chunk_name, "tags", 4) == 0)
{
process_tag_chunk(std::move(chunk_data), chunk_size);
}
}
}
}

const std::string Tlg0Reader::get_magic() const
{
return std::string("\x54\x4c\x47\x30\x2e\x30\x00\x73\x64\x73\x1a", 11);
}

const Image Tlg0Reader::read_raw_data(std::ifstream &ifs) const
{
uint32_t raw_data_size;
ifs.read((char*) &raw_data_size, 4);

auto reader = AbstractTlgReader::choose_reader(ifs);
auto ret = reader->read_raw_data(ifs);

process_chunks(ifs);

return ret;
}
Loading

0 comments on commit 75f13e6

Please sign in to comment.