他人の空似自作物置場

ilda_dll.zip/ilda.cpp

#define ILDA_EXPORTS
#include "ilda.h"

#include "boost/utility.hpp"
#include "boost/assert.hpp"
#include "boost/shared_ptr.hpp"
#include "boost/shared_array.hpp"
#include "boost/optional.hpp"
#include "boost/foreach.hpp"
#include "boost/function.hpp"
#include "boost/bind.hpp"

#include <stdio.h>
#include <vector>
#include <numeric>

#include <windows.h>

namespace {

void put32bit(char *data, int n){
	data[0] = ((char*)&n)[3];
	data[1] = ((char*)&n)[2];
	data[2] = ((char*)&n)[1];
	data[3] = ((char*)&n)[0];
}
void put32bit(char *data, unsigned int n){
	put32bit(data, *(int*)&n);
}
void put16bit(char *data, short n){
	data[0] = ((char*)&n)[1];
	data[1] = ((char*)&n)[0];
}
void put16bit(char *data, unsigned short n){
	put16bit(data, *(short*)&n);
}
void put16bit(char *data, int n){
	put16bit(data, *(short*)&n);
}
void put16bit(char *data, unsigned int n){
	put16bit(data, *(short*)&n);
}
void put8bit(char *data, char n){
	*data = n;
}
void put8bit(char *data, unsigned char n){
	put8bit(data, *(char*)&n);
}
void put8bit(char *data, int n){
	put8bit(data, *(char*)&n);
}
void put8bit(char *data, unsigned int n){
	put8bit(data, *(char*)&n);
}
int Read32Bit(const char *data){
	int ret;
	((char*)&ret)[0] = data[3];
	((char*)&ret)[1] = data[2];
	((char*)&ret)[2] = data[1];
	((char*)&ret)[3] = data[0];
	return ret;
}
short Read16Bit(const char *data){
	short ret;
	((char*)&ret)[0] = data[1];
	((char*)&ret)[1] = data[0];
	return ret;
}
char Read8Bit(const char *data){
	return *data;
}
unsigned int Read32BitU(const char *data) {
	int result = Read32Bit(data);
	return *(unsigned int*)&result;
}
unsigned short Read16BitU(const char *data) {
	short result = Read16Bit(data);
	return *(unsigned short*)&result;
}
unsigned char Read8BitU(const char *data) {
	char result = Read8Bit(data);
	return *(unsigned char*)&result;
}

void MyFClose(FILE *fp) {
	if(fp) {
		::fclose(fp);
	}
}

boost::shared_ptr<FILE> MyFOpen(const char *filename, const char *type) {
	return boost::shared_ptr<FILE>(::fopen(filename, type), &MyFClose);
}

} // anonymous

class Color : boost::noncopyable{
public:
	Color(unsigned char r, unsigned char g, unsigned char b) :
		r(r), g(g), b(b)
	{
	}

	~Color() {
	}

	static Color *Read(const char *data, unsigned int *length) {
		if(data == NULL || length == NULL) {
			return NULL;
		}
		const unsigned char r = Read8BitU(&data[0]);
		const unsigned char g = Read8BitU(&data[1]);
		const unsigned char b = Read8BitU(&data[2]);
		Color * const result = new Color(r, g, b);
		*length = result->Size();
		return result;
	}

	static Color *Read(boost::shared_ptr<FILE> fp) {
		if(!fp) {
			return NULL;
		}
		std::vector<char> data(Size());
		if(::fread(&data.front(), 1, data.size(), fp.get()) != data.size()) {
			return NULL;
		}
		unsigned int read_size;
		Color * const result = Read(&data.front(), &read_size);
		if(!result || read_size != data.size()) {
			return NULL;
		}
		return result;
	}

	unsigned char GetRed(void) const {
		return r;
	}
	unsigned char GetGreen(void) const {
		return g;
	}
	unsigned char GetBlue(void) const {
		return b;
	}

	bool Put(char *data, unsigned int *length) const {
		if(data == NULL || length == NULL) {
			return false;
		}
		((unsigned char*)data)[0] = r;
		((unsigned char*)data)[1] = g;
		((unsigned char*)data)[2] = b;
		*length = Size();
		return true;
	}

	bool Put(FILE *fp) const {
		if(fp == NULL) {
			return false;
		}
		char data[3];
		return (puts(data) && (fwrite(data,1,3,fp) == 3));
	}
	static unsigned int Size() {
		return 3;
	}
protected:
	const unsigned char r;
	const unsigned char g;
	const unsigned char b;
};

class PaletteHeader : boost::noncopyable {
public:
	PaletteHeader(unsigned int format_id, const std::string& name, const std::string& company, unsigned int color_count, unsigned int palette_id, unsigned int scan_head) :
		format_id(format_id), name(name), company(company), color_count(color_count), palette_id(palette_id), scan_head(scan_head)
	{
		BOOST_ASSERT(name.size() <= 8);
		BOOST_ASSERT(company.size() <= 8);
	}
	~PaletteHeader() {
	}

	static PaletteHeader *Read(const char *data, unsigned int *length) {
		if(data == NULL || length == NULL) {
			return NULL;
		}
		//CheckID
		if(strncmp(data, "ILDA", 4) != 0) {
			char Identity[5];
			strncpy(Identity, data, 4);
			Identity[4] = '\0';
			printf("Not Identity:%s\n", Identity);
			return NULL;
		}
		data += 4;

		const unsigned int format_id = Read32BitU(data);
		if(format_id != 2 && format_id != 3){
			printf("Undefind Format ID:%d\n", format_id);
			return NULL;
		}
		data += 4;

		std::string name(data, 8);
		data += 8;

		std::string company(data, 8);
		data += 8;

		const unsigned int color_count = Read16BitU(data);
		data += 2;

		const unsigned int palette_id = Read16BitU(data);
		data += 2;

		const unsigned short yoyaku = Read16BitU(data);
		if(yoyaku != 0){
			printf("yoyaku error:%d\n", yoyaku);
			return NULL;
		}
		data += 2;

		const unsigned int scan_head = Read8BitU(data);
		data += 1;

		const unsigned char yoyaku2 = Read8BitU(data);
		if(yoyaku2 != 0){
			printf("yoyaku2 error:%d\n", yoyaku2);
			return NULL;
		}
		data += 1;

		PaletteHeader * const result = new PaletteHeader(format_id, name, company, color_count, palette_id, scan_head);
		BOOST_ASSERT(result);
		*length = result->Size();
		return result;
	}

	bool Put(char *data, unsigned int *length) const {
		if(data == NULL || length == NULL) {
			return false;
		}
		strcpy(data, "ILDA");//ファイル識別子
		data += 4;
		put32bit(data, format_id);//フォーマットコード(カラーパレッド)
		data += 4;
		strncpy(data, name.c_str(), 8);//フレーム名
		data += 8;
		strncpy(data, company.c_str(), 8);//会社名
		data += 8;
		put16bit(data, color_count);//Total colors
		data += 2;
		put16bit(data, palette_id);//Palette number
		data += 2;
		put16bit(data, 0);//予備1
		data += 2;
		put16bit(data, scan_head);//スキャナーヘッド
		data += 1;
		put8bit(data, 0);//予備2
		*length = Size();
		return true;
	}

	bool Put(FILE *fp) const {
		if(fp == NULL) {
			return false;
		}
		std::vector<char> header(Size());
		unsigned int head_size;
		if(!Put(&header.front(), &head_size) || head_size != header.size() || fwrite(&header.front(), 1, head_size, fp) != head_size){
			return false;
		}
		return true;
	}

	static unsigned int Size() {
		return 32;
	}

	const unsigned int format_id;
	const std::string name;
	const std::string company;
	const unsigned int color_count;
	const unsigned int palette_id;
	const unsigned int scan_head;
};

class Palette : boost::noncopyable {
public:
	Palette(boost::shared_ptr<PaletteHeader> header, const std::vector<boost::shared_ptr<const Color> >& color_list) :
		header(header), color_list(color_list)
	{
		BOOST_ASSERT(header);
		BOOST_FOREACH(boost::shared_ptr<const Color> color, color_list) {
			BOOST_ASSERT(color);
		}
	}

	~Palette() {
	}

	static Palette *Read(const char *data, unsigned int *length) {
		if(data == NULL || length == NULL) {
			return NULL;
		}
		unsigned int header_size;
		boost::shared_ptr<PaletteHeader> header(PaletteHeader::Read(data, &header_size));
		data += header_size;

		std::vector<boost::shared_ptr<const Color> > color_list;
		for(unsigned int i = 0; i < header->color_count; i++){
			unsigned int color_size;
			boost::shared_ptr<Color> color(Color::Read(data, &color_size));
			if(!color) {
				return NULL;
			}
			data += color_size;
			color_list.push_back(color);
		}

		Palette * const result = new Palette(header, color_list);
		BOOST_ASSERT(result);
		*length = result->Size();
		return result;
	}

	static Palette *Read(boost::shared_ptr<FILE> fp, std::vector<char> readed_data = std::vector<char>()) {
		if(!fp) {
			return NULL;
		}
		boost::shared_ptr<PaletteHeader> header;
		{
			std::vector<char> data(readed_data);
			data.resize(PaletteHeader::Size());
			if(data.size() > readed_data.size()) {
				const unsigned int read_size = data.size() - readed_data.size();
				if(::fread(&data[readed_data.size()], 1, read_size, fp.get()) != read_size) {
					return NULL;
				}
			} else if(data.size() < readed_data.size()) {
				int pos = readed_data.size() - data.size();
				fseek(fp.get(), pos, SEEK_CUR);
			}
			unsigned int header_size;
			header.reset(PaletteHeader::Read(&data.front(), &header_size));
			if(!header || data.size() != header_size) {
				return NULL;
			}
		}

		std::vector<boost::shared_ptr<const Color> > color_list;
		for(unsigned int i = 0; i < header->color_count; i++){
			boost::shared_ptr<Color> color(Color::Read(fp));
			if(!color) {
				return NULL;
			}
			color_list.push_back(color);
		}

		Palette * const result = new Palette(header, color_list);
		BOOST_ASSERT(result);
		return result;
	}

	bool Put(char *data, unsigned int *length) const {
		if(data == NULL || length == NULL) {
			return false;
		}
		unsigned int head_size;
		if(!header->Put(data, &head_size)){
			return false;
		}
		data += head_size;

		*length = head_size;
		BOOST_FOREACH(boost::shared_ptr<const Color> color, color_list) {
			unsigned int color_size;
			if(!color->Put(data, &color_size)){
				return false;
			}
			data += color_size;
			*length += color_size;
		}
		return true;
	}

	bool Put(FILE *fp) const {
		if(fp == NULL) {
			return false;
		}
		if(!header->Put(fp)){
			return false;
		}
		BOOST_FOREACH(boost::shared_ptr<const Color> color, color_list) {
			if(!color->Put(fp)){
				return false;
			}
		}
		return true;
	}

	unsigned int Size() const {
		unsigned int result = header->Size();
		BOOST_FOREACH(boost::shared_ptr<const Color> color, color_list) {
			result += color->Size();
		}
		return result;
	}

	const boost::shared_ptr<PaletteHeader> header;
	const std::vector<boost::shared_ptr<const Color> > color_list;
};

class Point : boost::noncopyable {
public:
	Point(short x, short y, short z, unsigned char status, unsigned char color_id) :
		is_xy_only(false), x(x), y(y), z(z), status(status), color_id(color_id)
	{
		BOOST_ASSERT((status&0x3F) == 0);
	}
	Point(short x, short y, unsigned char status, unsigned char color_id) :
		is_xy_only(true), x(x), y(y), z(0), status(status), color_id(color_id)
	{
		BOOST_ASSERT((status&0x3F) == 0);
	}
	~Point() {
	}

	static Point *Read(const char *data, unsigned int *length, bool is_xy_only = false) {
		if(data == NULL || length == NULL) {
			return NULL;
		}
		const short x = Read16Bit(data);
		data += 2;
		const short y = Read16Bit(data);
		data += 2;
		short z;
		if(!is_xy_only){
			z = Read16Bit(data);
			data += 2;
		}
		const unsigned char status = Read8BitU(data);
		if((status&0x3F) != 0) {
			printf("invalid status flag %08x\n", status);
			return NULL;
		}
		data += 1;
		const unsigned char color_id = Read8BitU(data);
		data += 1;

		Point *result;
		if(is_xy_only) {
			result = new Point(x, y, status, color_id);
		} else {
			result = new Point(x, y, z, status, color_id);
		}
		BOOST_ASSERT(result);
		*length = result->Size();
		return result;
	}

	static Point *Read(boost::shared_ptr<FILE> fp, bool is_xy_only = false) {
		if(!fp) {
			return NULL;
		}
		std::vector<char> data(Size(is_xy_only));
		if(::fread(&data.front(), 1, data.size(), fp.get()) != data.size()) {
			return NULL;
		}
		unsigned int read_size;
		Point * const result = Read(&data.front(), &read_size, is_xy_only);
		if(!result || data.size() != read_size) {
			return NULL;
		}
		return result;
	}

	bool Put(char *data, unsigned int *length) const {
		if(data == NULL || length == NULL) {
			return false;
		}
		put16bit(data, x);
		data += 2;
		put16bit(data, y);
		data += 2;
		if(!is_xy_only){
			put16bit(data, z);
			data += 2;
		}
		put8bit(data, status);
		data += 1;
		put8bit(data, color_id);
		*length = Size();
		return true;
	}

	bool Put(FILE *fp) const {
		if(fp == NULL) {
			return false;
		}
		std::vector<char> data(Size());
		unsigned int put_size;
		if(!Put(&data.front(), &put_size) || put_size != data.size() || fwrite(&data.front(), 1, put_size, fp) != put_size){
			return false;
		}
		return true;
	}

	unsigned int Size() const {
		return Size(is_xy_only);
	}

	static unsigned int Size(bool is_xy_only) {
		return 6 + (is_xy_only ? 0 : 2);
	}

	const bool is_xy_only;
	const short x;
	const short y;
	const short z;
	const unsigned char status;
	const unsigned char color_id;
};

class FrameHeader {
public:
	FrameHeader(const std::string& name, const std::string& company, unsigned int format_id, unsigned int point_count, unsigned int frame_number, unsigned int all_frame_count, unsigned int scan_head) :
		name(name), company(company), format_id(format_id), point_count(point_count), frame_number(frame_number), all_frame_count(all_frame_count), scan_head(scan_head)
	{
		BOOST_ASSERT(name.size() <= 8);
		BOOST_ASSERT(company.size() <= 8);
		BOOST_ASSERT(frame_number < all_frame_count);
	}

	~FrameHeader() {
	}

	static FrameHeader *Read(const char *data, unsigned int *length) {
		if(data == NULL || length == NULL) {
			return NULL;
		}
		//check id
		if(strncmp(data, "ILDA", 4) != 0) {
			char Identity[5];
			strncpy(Identity, data, 4);
			Identity[4] = '\0';
			printf("Not Identity:%s\n", Identity);
			return NULL;
		}
		data += 4;

		const unsigned int format_id = Read32BitU(data);
		if(format_id != 0 && format_id != 1){
			printf("invalid format_id &d\n", format_id);
			return NULL;
		}
		data += 4;

		const std::string name(data, 8);
		data += 8;

		const std::string company(data, 8);
		data += 8;

		const unsigned int point_count = Read16BitU(data);
		data += 2;

		const unsigned int frame_number = Read16BitU(data);
		data += 2;

		const unsigned int all_frame_count = Read16BitU(data);
		data += 2;

		const unsigned char scan_head = Read8BitU(data);
		data += 1;

		const unsigned char yoyaku = Read8BitU(data);
		if(yoyaku != 0){
			return NULL;
		}
		data += 1;

		FrameHeader * const result = new FrameHeader(name, company, format_id, point_count, frame_number, all_frame_count, scan_head);
		BOOST_ASSERT(result);
		*length = result->Size();
		return result;
	}

	static unsigned int Size(void) {
		return 32;
	}

	bool Put(char *data, unsigned int *length) const {
		if(data == NULL || length == NULL) {
			return false;
		}
		strcpy(data, "ILDA");
		data += 4;
		put32bit(data, format_id);
		data += 4;
		strncpy(data, name.c_str(), 8);//フレーム名
		data += 8;
		strncpy(data, company.c_str(), 8);//会社名
		data += 8;
		put16bit(data, point_count);//総ポイント数
		data += 2;
		put16bit(data, frame_number);//フレーム番号
		data += 2;
		put16bit(data, all_frame_count);//総フレーム数
		data += 2;
		put8bit(data, scan_head);//スキャナヘッド
		data += 1;
		put8bit(data, 0);//予約
		*length = Size();
		return true;
	}

	const std::string name;
	const std::string company;
	const unsigned int format_id;
	const unsigned int point_count;
	const unsigned int frame_number;
	const unsigned int all_frame_count;
	const unsigned int scan_head;
};

class Frame {
public:
	Frame(boost::shared_ptr<const FrameHeader> header, boost::shared_ptr<FILE> fp) :
		header(header), fp(fp), point_addr(ftell(fp.get())), point_list(boost::none)
	{
		BOOST_ASSERT(header);
		BOOST_ASSERT(fp);
	}

	Frame(boost::shared_ptr<const FrameHeader> header, const std::vector<boost::shared_ptr<const Point> >& point_list) :
		header(header), point_addr(0), point_list(point_list)
	{
		BOOST_ASSERT(header);
	}

	~Frame() {
	}

	static Frame *Read(const char *data, unsigned int *length) {
		if(data == NULL || length == NULL) {
			return NULL;
		}
		unsigned int header_size;
		boost::shared_ptr<const FrameHeader> header(FrameHeader::Read(data, &header_size));
		if(!header) {
			return NULL;
		}

		const bool is_xy_only = (header->format_id == 1);
		std::vector<boost::shared_ptr<const Point> > point_list;
		for(unsigned int i = 0; i < header->point_count; i++) {
			unsigned int point_size;
			boost::shared_ptr<const Point> point(Point::Read(data, &point_size, is_xy_only));
			if(!point){
				return NULL;
			}
			data += point_size;
			point_list.push_back(point);
		}

		Frame * const result = new Frame(header, point_list);
		BOOST_ASSERT(result);
		*length = result->Size();
		return result;
	}

	static Frame *Read(boost::shared_ptr<FILE> fp, const std::vector<char>& readed_data = std::vector<char>()) {
		if(!fp) {
			return NULL;
		}
		boost::shared_ptr<const FrameHeader> header;
		{
			std::vector<char> data(readed_data);
			data.resize(FrameHeader::Size());
			if(readed_data.size() < data.size()) {
				const unsigned int read_size = data.size() - readed_data.size();
				if(::fread(&data[readed_data.size()], 1, read_size, fp.get()) != read_size) {
					return NULL;
				}
			} else if(data.size() < readed_data.size()) {
				int pos = readed_data.size() - data.size();
				fseek(fp.get(), pos, SEEK_CUR);
			}
			unsigned int header_size;
			header.reset(FrameHeader::Read(&data.front(), &header_size));
			if(!header || header_size != data.size()) {
				return NULL;
			}
		}

		Frame * const result = new Frame(header, fp);
		BOOST_ASSERT(result);
		const bool is_xy_only = (header->format_id == 1);
		::fseek(fp.get(), Point::Size(is_xy_only) * header->point_count, SEEK_CUR);
		return result;
	}

	bool Put(char *data, unsigned int *length) const {
		if(data == NULL || length == NULL) {
			return false;
		}
		unsigned int header_size;
		if(!header->Put(data, &header_size)){
			return false;
		}
		data += header_size;

		BOOST_FOREACH(boost::shared_ptr<const Point> point, GetPointList()) {
			unsigned int point_size;
			if(!point->Put(data, &point_size)){
				return false;
			}
			data += point_size;
		}
		*length = Size();
		return true;
	}

	bool Put(FILE *fp) const {
		if(fp == NULL) {
			return false;
		}
		std::vector<char> data(FrameHeader::Size());
		unsigned int header_size;
		if(!header->Put(&data.front(), &header_size) || header_size != data.size() || fwrite(&data.front(), 1, header_size, fp) != header_size){
			return false;
		}
		BOOST_FOREACH(boost::shared_ptr<const Point> point, GetPointList()) {
			if(!point->Put(fp)){
				return false;
			}
		}
		return true;
	}

	unsigned int Size() const {
		unsigned int result = header->Size();
		const bool is_xy_only = (header->format_id == 1);
		result += Point::Size(is_xy_only) * header->point_count;
		return result;
	}

	std::vector<boost::shared_ptr<const Point> > GetPointList(void) const {
		if(point_list) {
			return point_list.get();
		}

		::fseek(fp.get(), point_addr, SEEK_SET);
		const bool is_xy_only = (header->format_id == 1);
		std::vector<boost::shared_ptr<const Point> > point_list;
		for(unsigned int i = 0; i < header->point_count; i++) {
			boost::shared_ptr<const Point> point(Point::Read(fp, is_xy_only));
			BOOST_ASSERT(point);
			point_list.push_back(point);
		}
		return point_list;
	}

	const boost::shared_ptr<const FrameHeader> header;
protected:
	const boost::shared_ptr<FILE> fp;
	const unsigned int point_addr;
	const boost::optional<std::vector<boost::shared_ptr<const Point> > > point_list;
};

class ILDA : boost::noncopyable {
public:
	ILDA(const std::vector<boost::shared_ptr<const Palette> >& palette_list, const std::vector<boost::shared_ptr<const Frame> >& frame_list) :
		palette_list(palette_list), frame_list(frame_list)
	{
		BOOST_FOREACH(boost::shared_ptr<const Frame> frame, frame_list) {
			BOOST_ASSERT(frame);
		}
		BOOST_FOREACH(boost::shared_ptr<const Palette> palette, palette_list) {
			BOOST_ASSERT(palette);
		}
	}

	~ILDA() {
	}

	enum ILDA_TYPE {
		ILDA_TYPE_FRAME,
		ILDA_TYPE_PALETTE,
		ILDA_TYPE_UNKNOWN,
		ILDA_TYPE_END,
	};

	static ILDA_TYPE CheckILDA(const char *data) {
		if(strcmp(data,"ILDA") != 0) {
			return ILDA_TYPE_END;
		}
		data += 4;
		const unsigned int format_id = Read32BitU(data);
		data += 4;
		switch(format_id){
			case 0:
			case 1:
				return ILDA_TYPE_FRAME;
			case 3:{
				unsigned int i = 8;
				bool flag = true;
				while(i < 24){
					flag = flag && 0x20 <= data[i] && data[i] <= 0x79;
					i++;
				}
				if(!flag){
					break;
				}
				//先頭16字がASCIIだったら、独自拡張版フォーマットID3だと認識してpaletteを読み込む
			}
			case 2:
				return ILDA_TYPE_PALETTE;
		}
		return ILDA_TYPE_UNKNOWN;
	}

	static ILDA *ReadImpl(boost::function<bool (std::vector<boost::shared_ptr<const Palette> > *, std::vector<boost::shared_ptr<const Frame> > *)> read_proc) {
		std::vector<boost::shared_ptr<const Palette> > palette_list;
		std::vector<boost::shared_ptr<const Frame> > frame_list;
		if(!read_proc(&palette_list, &frame_list)) {
			return false;
		}
		ILDA * const result = new ILDA(palette_list, frame_list);
		BOOST_ASSERT(result);
		return result;
	}

	static bool MemoryRead(const char *data, std::vector<boost::shared_ptr<const Palette> > *palette_list, std::vector<boost::shared_ptr<const Frame> > *frame_list) {
		ILDA_TYPE type;
		while((type = CheckILDA(data)) != ILDA_TYPE_END){
			switch(type){
				case ILDA_TYPE_FRAME: {
					unsigned int frame_size;
					boost::shared_ptr<const Frame> frame(Frame::Read(data, &frame_size));
					if(!frame){
						return false;
					}
					data += frame_size;
					frame_list->push_back(frame);
					break;
				}
				case ILDA_TYPE_PALETTE:{
					unsigned int palette_size;
					boost::shared_ptr<const Palette> palette(Palette::Read(data, &palette_size));
					if(!palette){
						return false;
					}
					data += palette_size;
					palette_list->push_back(palette);
					break;
				}
				case ILDA_TYPE_UNKNOWN: {
					unsigned int length = Read32BitU(data+8);
					data += 12 + length;
					break;
				}
			}
		}
		return true;
	}

	static bool FileRead(boost::shared_ptr<FILE> fp, std::vector<boost::shared_ptr<const Palette> > *palette_list, std::vector<boost::shared_ptr<const Frame> > *frame_list) {
		std::vector<char> data(24);
		ILDA_TYPE type;
		while(::fread(&data.front(), 1, data.size(), fp.get()) == data.size() && (type = CheckILDA(&data.front())) != ILDA_TYPE_END){
			switch(type){
				case ILDA_TYPE_FRAME: {
					boost::shared_ptr<const Frame> frame(Frame::Read(fp, data));
					if(!frame){
						return false;
					}
					frame_list->push_back(frame);
					break;
				}
				case ILDA_TYPE_PALETTE:{
					boost::shared_ptr<const Palette> palette(Palette::Read(fp, data));
					if(!palette){
						return false;
					}
					palette_list->push_back(palette);
					break;
				}
				case ILDA_TYPE_UNKNOWN: {
					unsigned int length = Read32BitU(&data[8]);
					unsigned int current = ftell(fp.get());
					::fseek(fp.get(), current - 12 + length, SEEK_SET);
					break;
				}
			}
		}
		return true;
	}

	static ILDA *Read(const char *data, unsigned int *length) {
		ILDA * const result = ReadImpl(boost::bind(&ILDA::MemoryRead, data, _1, _2));
		*length = result->Size();
		return result;
	}

	static ILDA *Read(boost::shared_ptr<FILE> fp) {
		return ReadImpl(boost::bind(&ILDA::FileRead, fp, _1, _2));
	}

	static ILDA *Read(const char *filename) {
		if(filename == NULL) {
			return NULL;
		}
		boost::shared_ptr<FILE> fp = MyFOpen(filename, "rb");
		if(!fp) {
			return NULL;
		}
		return Read(fp);
	}

	bool Put(char *data, unsigned int *length) const {
		if(data == NULL || length == NULL) {
			return false;
		}
		std::vector<boost::shared_ptr<const Frame> >::const_iterator fi = frame_list.begin();
		std::vector<boost::shared_ptr<const Palette> >::const_iterator pi = palette_list.begin();
		while(fi != frame_list.end() || pi != palette_list.end()){
			if(fi != frame_list.end()){
				unsigned int frame_size;
				if(!(*fi)->Put(data, &frame_size)){
					return false;
				}
				data += frame_size;
				++fi;
			}
			if(pi != palette_list.end()){
				unsigned int palette_size;
				if(!(*pi)->Put(data, &palette_size)){
					return false;
				}
				data += palette_size;
				++pi;
			}
		}
		*length = Size();
		return true;
	}

	bool Put(FILE *fp) const {
		if(fp == NULL) {
			return false;
		}
		std::vector<boost::shared_ptr<const Frame> >::const_iterator fi = frame_list.begin();
		std::vector<boost::shared_ptr<const Palette> >::const_iterator pi = palette_list.begin();
		while(fi != frame_list.end() || pi != palette_list.end()){
			if(fi != frame_list.end()){
				if(!(*fi)->Put(fp)){
					return false;
				}
				++fi;
			}
			if(pi != palette_list.end()){
				if(!(*pi)->Put(fp)){
					return false;
				}
				++pi;
			}
		}
		return true;
	}

	int Size() const {
		unsigned int result = 0;
		BOOST_FOREACH(boost::shared_ptr<const Frame> frame, frame_list) {
			result += frame->Size();
		}
		BOOST_FOREACH(boost::shared_ptr<const Palette> palette, palette_list) {
			result += palette->Size();
		}
		return result;
	}

	const std::vector<boost::shared_ptr<const Palette> > palette_list;
	const std::vector<boost::shared_ptr<const Frame> > frame_list;
};

std::vector<boost::shared_ptr<const ILDA> > ilda_list;
std::vector<struct ILDAPoint> ilda_point_list;
std::vector<unsigned int> ilda_point_count;

void ResizeIldaList(void) {
	unsigned int i = 1;
	unsigned int size = 0;
	BOOST_FOREACH(boost::shared_ptr<const ILDA> ilda, ilda_list) {
		if(ilda) {
			size = i;
		}
		i++;
	}
	if(ilda_list.size() > size) {
		ilda_list.resize(size);
	}
}

ILDA_API ILDA_HANDLE ILDAOpenHandle(const char *filename) {
	if(filename == NULL) {
		return ILDA_INVALID_HANDLE;
	}
	boost::shared_ptr<const ILDA> ilda(ILDA::Read(filename));
	if(!ilda) {
		return ILDA_INVALID_HANDLE;
	}
	ilda_list.push_back(ilda);
	const ILDA_HANDLE result = ilda_list.size() - 1;
	return result;
}

ILDA_API ILDA_ERROR_ID ILDACloseHandle(ILDA_HANDLE handle) {
	if(handle >= ilda_list.size() || handle < 0) {
		return ILDA_ERROR_INVALID_HANDLE;
	}
	ilda_list[handle].reset();
	ResizeIldaList();
	return ILDA_ERROR_SUCCESS;
}

struct SumFramePointCount {
	int operator() (const unsigned int value, boost::shared_ptr<const Frame> frame) const {
		return value + frame->header->point_count;
	}
};

ILDA_ERROR_ID SetILDAPointList(std::vector<boost::shared_ptr<const Frame> >::const_iterator start, std::vector<boost::shared_ptr<const Frame> >::const_iterator end, boost::optional<unsigned int> point_count_max = boost::none) {
	unsigned int all_point_count;
	if(!point_count_max) {
		all_point_count = std::accumulate(start, end, (unsigned int)0, SumFramePointCount());
	} else {
		const unsigned int frame_count = end - start;
		all_point_count = point_count_max.get() * frame_count;
	}
	ilda_point_list.resize(all_point_count);
	std::vector<struct ILDAPoint>::iterator it = ilda_point_list.begin();
	std::vector<boost::shared_ptr<const Frame> >::const_iterator frame = start;
	while(frame != end) {
		unsigned int i = 0;
		BOOST_FOREACH(boost::shared_ptr<const Point> point, (*frame)->GetPointList()) {
			if(point_count_max && point_count_max.get() == i) {
				break;
			}
			it->x = (point->x + 32768) / 256;
			it->y = (point->y + 32768) / 256;
			it->blanking = (point->status & 0x40) ? 1 : 0;
			++it;
			i++;
		}
		while(point_count_max && point_count_max.get() > i) {
			it->x = 128;
			it->y = 128;
			it->blanking = 0;
			++it;
			i++;
		}
		++frame;
	}
	return ILDA_ERROR_SUCCESS;
}

ILDA_ERROR_ID SetILDAPointCountList(std::vector<boost::shared_ptr<const Frame> >::const_iterator start, std::vector<boost::shared_ptr<const Frame> >::const_iterator end) {
	const unsigned int size = end - start;
	ilda_point_count.resize(size);
	std::vector<unsigned int>::iterator it = ilda_point_count.begin();
	std::vector<boost::shared_ptr<const Frame> >::const_iterator frame = start;
	while(frame != end) {
		*it = (*frame)->header->point_count;
		++it;
		++frame;
	}
	return ILDA_ERROR_SUCCESS;
}

ILDA_API ILDA_ERROR_ID GetPointData(ILDA_HANDLE handle, unsigned int first_frame, unsigned int frame_count, struct ILDAPoint **start_ptr, unsigned int **point_count_list, unsigned int *read_frame) {
	if(handle >= ilda_list.size() || handle < 0) {
		return ILDA_ERROR_INVALID_HANDLE;
	}
	boost::shared_ptr<const ILDA> ilda = ilda_list[handle];
	if(!ilda) {
		return ILDA_ERROR_INVALID_HANDLE;
	}
	if(frame_count == 0 || start_ptr == NULL || point_count_list == NULL || read_frame == NULL) {
		return ILDA_ERROR_INVALID_PARAMETER;
	}
	std::vector<boost::shared_ptr<const Frame> > frame_list = ilda->frame_list;
	if(frame_list.size() <= first_frame) {
		return ILDA_ERROR_FRAME_OVER;
	}
	if(frame_list.size() < first_frame + frame_count) {
		*read_frame = frame_list.size() - first_frame;
	} else {
		*read_frame = frame_count;
	}
	const std::vector<boost::shared_ptr<const Frame> >::const_iterator start = frame_list.begin() + first_frame;
	const std::vector<boost::shared_ptr<const Frame> >::const_iterator end = start + *read_frame;

	ILDA_ERROR_ID error ;
	if(error = SetILDAPointList(start, end)) {
		return error;
	}
	if(error = SetILDAPointCountList(start, end)) {
		return error;
	}

	if(ilda_point_list.empty()) {
		*start_ptr = NULL;
	} else {
		*start_ptr = &ilda_point_list.front();
	}
	*point_count_list = &ilda_point_count.front();

	return ILDA_ERROR_SUCCESS;
}

ILDA_API ILDA_ERROR_ID GetPointData2(ILDA_HANDLE handle, unsigned int first_frame, unsigned int frame_count, unsigned int point_count, struct ILDAPoint **start_ptr, unsigned int *read_frame) {
	if(handle >= ilda_list.size() || handle < 0) {
		return ILDA_ERROR_INVALID_HANDLE;
	}
	boost::shared_ptr<const ILDA> ilda = ilda_list[handle];
	if(!ilda) {
		return ILDA_ERROR_INVALID_HANDLE;
	}
	if(frame_count == 0 || start_ptr == NULL || read_frame == NULL) {
		return ILDA_ERROR_INVALID_PARAMETER;
	}
	std::vector<boost::shared_ptr<const Frame> > frame_list = ilda->frame_list;
	if(frame_list.size() <= first_frame) {
		return ILDA_ERROR_FRAME_OVER;
	}
	if(frame_list.size() < first_frame + frame_count) {
		*read_frame = frame_list.size() - first_frame;
	} else {
		*read_frame = frame_count;
	}
	const std::vector<boost::shared_ptr<const Frame> >::const_iterator start = frame_list.begin() + first_frame;
	const std::vector<boost::shared_ptr<const Frame> >::const_iterator end = start + *read_frame;

	ILDA_ERROR_ID error ;
	if(error = SetILDAPointList(start, end, point_count)) {
		return error;
	}

	if(ilda_point_list.empty()) {
		*start_ptr = NULL;
	} else {
		*start_ptr = &ilda_point_list.front();
	}

	return ILDA_ERROR_SUCCESS;
}

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
	switch(fdwReason) {
		case DLL_PROCESS_ATTACH:
		case DLL_THREAD_ATTACH:
		case DLL_THREAD_DETACH:
		case DLL_PROCESS_DETACH:
			break;
	}
	return TRUE;
}