/*	
 *	clipblob.c
 *
 *	ユーティリティ：BLOB
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2017-2018 Naoyuki Sawa
 *
 *	* Tue Sep 26 23:05:51 JST 2017 Naoyuki Sawa
 *	- 1st リリース。
 *	- dRegTblC.exeと同じ仕様の、BLOBデータを作成するユーティリティ関数です。
 *	  今後、dRegTblC.exeだけでなく、他のツールやモジュールでも同じ仕様を使おうと思うので、共通のユーティリティ関数として実装しておく事にしました。
 *	- 今回作成したのは、BLOBデータを作成するユーティリティ関数だけで、BLOBデータを読み出すユーティリティ関数は、まだ作成していません。
 *	  今後、もし、BLOBデータを読み出す処理も共通化する方が良さそうだと判断したら、その時に作成しようと思います。	⇒{{2017/09/27コメント追記:BLOBデータを読み出すユーティリティ関数も作成しました。}}
 *	* Thu Sep 28 23:55:37 JST 2017 Naoyuki Sawa
 *	- BLOBデータを読み出すユーティリティ関数も作成しました。
 *	  BLOBデータを作成するユーティリティ関数をテストするためには、やはりBLOBデータを読み出すユーティリティ関数も必要なので、作成する事にしました。
 *	  尚、アプリケーションから利用する事も出来ますが必須ではなく、特定のBLOBの構造を前提として直接アクセスしても構いません。
 *	- 「BLOBデータを作成するユーティリティ関数とBLOBデータを読み出すユーティリティ関数のテスト」を作成しました。
 *	* Sun Oct 01 23:07:12 JST 2017 Naoyuki Sawa
 *	- BLOB構造体にシグネチャを追加しました。
 *	  変更前のままでも動作上は問題無いのですが、data引数に間違ってBLOB以外のポインタを渡した場合に発見し辛いバグになるので、すぐにエラー停止出来るようにシグネチャを追加し、常に検査する事にしました。
 *	  今回の変更は、アプリケーションの観点からは透過であり、アプリケーションの変更は不要です。
 *	* Tue Oct 03 23:59:59 JST 2017 Naoyuki Sawa
 *	- blob_compare()を追加しました。
 *	* Sat Apr 07 23:59:59 JST 2018 Naoyuki Sawa
 *	- blob_add_ber(),blob_read_ber()を追加しました。
 */
#include "clip.h"
//*****************************************************************************
//	BLOBデータを作成するユーティリティ関数
//*****************************************************************************
//BLOB構造体。アプリケーションからは不可視です。
//{{2017/10/01変更:BLOB構造体にシグネチャを追加しました。
//struct blob {
//	int		bits;				//+ 0,4                格納したビット数。	((bits&7)!=0)の時にbit以外の格納を行う場合はバイト境界まで進める(即ち確実に((bits&7)==0)とする)。((bits&7)!=0)の時もデータ全体として見れば完全なのでどのタイミングでもファイナライズは不要である。
//	int		data[0/*(bits+31)/32*/];	//+ 4,4*((bits+31)/32) ビット配列データ。	←当モジュールの関数と、アプリケーションの間のやりとりでは、この位置を指すポインタを使用します。アプリケーションの観点では、当モジュールとやりとりするポインタをそのまま、データ本体と見なせます。
//};							//= 4+4*((bits+31)/32)
//↓2017/10/01変更:BLOB構造体にシグネチャを追加しました。
#define FOURCC_BLOB	MAKEFOURCC('B','L','O','B')
struct blob {
	int		sig;				//+ 0,4                シグネチャ。		"BLOB"固定。
	int		bits;				//+ 4,8                格納したビット数。	((bits&7)!=0)の時にbit以外の格納を行う場合はバイト境界まで進める(即ち確実に((bits&7)==0)とする)。((bits&7)!=0)の時もデータ全体として見れば完全なのでどのタイミングでもファイナライズは不要である。
	int		data[0/*(bits+31)/32*/];	//+ 8,4*((bits+31)/32) ビット配列データ。	←当モジュールの関数と、アプリケーションの間のやりとりでは、この位置を指すポインタを使用します。アプリケーションの観点では、当モジュールとやりとりするポインタをそのまま、データ本体と見なせます。
};							//= 8+4*((bits+31)/32)
//}}2017/10/01変更:BLOB構造体にシグネチャを追加しました。
//-----------------------------------------------------------------------------
//{{2017/10/01追加:BLOB構造体にシグネチャを追加しました。
//ビット配列データへのポインタを、BLOB構造体へのポインタに変換する。
static struct blob* blob_from_data(void* data/*NULL可*/) {
	//ビット配列データへのポインタを、BLOB構造体へのポインタに変換する。
	struct blob* blob = CONTAINING_RECORD(data, struct blob, data);
	//シグネチャを検査する。
	if(blob->sig != FOURCC_BLOB) { DIE(); }
	//BLOB構造体へのポインタを返す。
	return blob;
}
//}}2017/10/01追加:BLOB構造体にシグネチャを追加しました。
//-----------------------------------------------------------------------------
//BLOBのメモリを開放する。
void blob_free(void* data/*NULL可*/) {
	//BLOB構造体のメモリが確保済みならば…
	if(data) {
		//BLOB構造体のメモリを開放する。
//{{2017/10/01変更:BLOB構造体にシグネチャを追加しました。
//		struct blob* blob = CONTAINING_RECORD(data, struct blob, data);
//↓2017/10/01変更:BLOB構造体にシグネチャを追加しました。
		struct blob* blob = blob_from_data(data);
//}}2017/10/01変更:BLOB構造体にシグネチャを追加しました。
		free(blob);
	}
}
//-----------------------------------------------------------------------------
//格納したバイト数(データ末尾の余りビット込み)を取得する。
int blob_get_size(void* data/*NULL可*/) {
	//BLOB構造体のメモリが確保済みならば…
	if(data) {
		//格納したバイト数を返す。
//{{2017/10/01変更:BLOB構造体にシグネチャを追加しました。
//		struct blob* blob = CONTAINING_RECORD(data, struct blob, data);
//↓2017/10/01変更:BLOB構造体にシグネチャを追加しました。
		struct blob* blob = blob_from_data(data);
//}}2017/10/01変更:BLOB構造体にシグネチャを追加しました。
		return (blob->bits + 7) / 8;
	//BLOB構造体のメモリが未確保ならば…
	} else {
		//格納したバイト数=0を返す。
		return 0;
	}
}
//-----------------------------------------------------------------------------
//{{2017/10/03追加:blob_compare()を追加しました。
int blob_compare(void* data1/*NULL可*/, void* data2/*NULL可*/) {
	int size1 = blob_get_size(data1);
	int size2 = blob_get_size(data2);
	int result = memcmp(data1, data2, min(size1, size2));
	if(result) { return result; }
	if(size1 < size2) { return -1; }
	if(size1 > size2) { return  1; }
	return 0;
}
//}}2017/10/03追加:blob_compare()を追加しました。
//-----------------------------------------------------------------------------
//BLOBに1ビット整数値を格納する。(8ビット境界への整列無し)
void* blob_add_bit(void* data/*NULL可*/, int n) {
	struct blob* blob;
	//BLOB構造体のメモリが確保済みならば…
	if(data) {
		//データ末尾に余りビットが有れば…
//{{2017/10/01変更:BLOB構造体にシグネチャを追加しました。
//		blob = CONTAINING_RECORD(data, struct blob, data);
//↓2017/10/01変更:BLOB構造体にシグネチャを追加しました。
		blob = blob_from_data(data);
//}}2017/10/01変更:BLOB構造体にシグネチャを追加しました。
		if(blob->bits & 31) {
			//ビットを格納する。
			bitarray_lsb1st_set(blob->data, blob->bits, 1, n);	//ここでは'n & 1'は不要です。
			//格納したビット数を増やす。
			blob->bits++;
			//ビット配列データへのポインタを返す。
			return blob->data;	//ここまで
		}
	}
	//実装を簡単にするため、バイトとして格納した後に7ビット減らす方法を取った。
	data = blob_add_byte(data, n & 1);	//未格納ビットにゴミが格納されないように、'n & 1'は必須です。
//{{2017/10/01変更:BLOB構造体にシグネチャを追加しました。
//	blob = CONTAINING_RECORD(data, struct blob, data);
//↓2017/10/01変更:BLOB構造体にシグネチャを追加しました。
	blob = blob_from_data(data);
//}}2017/10/01変更:BLOB構造体にシグネチャを追加しました。
	blob->bits -= 7;
	//ビット配列データへのポインタを返す。
	return blob->data;
}
//-----------------------------------------------------------------------------
//BLOBに1バイト整数値を格納する。(8ビット境界への整列有り)
void* blob_add_byte(void* data/*NULL可*/, int n) {
	return blob_add_data(data, &n, 1);
}
//-----------------------------------------------------------------------------
//BLOBに2バイト整数値を格納する。(8ビット境界への整列有り)
void* blob_add_half(void* data/*NULL可*/, int n) {
	return blob_add_data(data, &n, 2);
}
//-----------------------------------------------------------------------------
//BLOBに2バイトexp10値を格納する。(8ビット境界への整列有り)
void* blob_add_exp10(void* data/*NULL可*/, int n) {
	int t = Exp10_Encode(n);	//当関数は引数nがexp10値の範囲内であるかを検査しない。もし引数nがexp10値の範囲外ならば格納される値は不定(実際には-1)である。不定値が格納される事を防ぐにはアプリケーション側にて当関数を呼び出す前に引数nがexp10値の範囲内であるかを検査せよ。
	return blob_add_data(data, &t, 2);
}
//-----------------------------------------------------------------------------
//BLOBに4バイト整数値を格納する。(8ビット境界への整列有り)
void* blob_add_word(void* data/*NULL可*/, int n) {
	return blob_add_data(data, &n, 4);
}
//-----------------------------------------------------------------------------
//{{2018/04/07追加:blob_add_ber(),blob_read_ber()を追加しました。
//BLOBにBER圧縮整数値を格納する。(8ビット境界への整列有り)
void* blob_add_ber(void* data/*NULL可*/, int n) {
	unsigned char buf[(sizeof(int)*8+6)/7];
	return blob_add_data(data, buf, BER_Encode(buf, n));
}
//}}2018/04/07追加:blob_add_ber(),blob_read_ber()を追加しました。
//-----------------------------------------------------------------------------
//BLOBに2バイト浮動小数値を格納する。(8ビット境界への整列有り)
void* blob_add_fp16(void* data/*NULL可*/, double d) {
	fp16 t = truncdfhf2(d);
	return blob_add_data(data, &t, 2);
}
//-----------------------------------------------------------------------------
//BLOBに4バイト浮動小数値を格納する。(8ビット境界への整列有り)
void* blob_add_fp32(void* data/*NULL可*/, double d) {
	float t = d;
	return blob_add_data(data, &t, 4);
}
//-----------------------------------------------------------------------------
//BLOBに8バイト浮動小数値を格納する。(8ビット境界への整列有り)
void* blob_add_fp64(void* data/*NULL可*/, double d) {
	return blob_add_data(data, &d, 8);
}
//-----------------------------------------------------------------------------
//BLOBにヌル終端文字列を格納する。(8ビット境界への整列有り)
void* blob_add_string(void* data/*NULL可*/, const char* s) {
	int len = strlen(s);
	return blob_add_data(data, s, len + 1/*'\0'*/);
}
//-----------------------------------------------------------------------------
//BLOBに任意長のデータを格納する。(8ビット境界への整列有り)
void* blob_add_data(void* data/*NULL可*/, const void* p, int size/*0可*/) {
	struct blob* blob;
	int old_words, new_words;
	//BLOB構造体のメモリが確保済みならば…
	if(data) {
		//確実にバイト境界まで進める。(たとえ0バイトのデータ格納であっても!!)
//{{2017/10/01変更:BLOB構造体にシグネチャを追加しました。
//		blob = CONTAINING_RECORD(data, struct blob, data);
//↓2017/10/01変更:BLOB構造体にシグネチャを追加しました。
		blob = blob_from_data(data);
//}}2017/10/01変更:BLOB構造体にシグネチャを追加しました。
		blob->bits = (blob->bits + 7) & ~7;
	//BLOB構造体のメモリが未確保ならば…
	} else {
		//メモリ未確保のBLOBに対して、0バイトのデータ格納を行う場合は、何もせずにそのままNULLを返す。(アプリケーションの利便性のためにメモリ確保済みのBLOBは常に空でないと見なせるようにするためです。(data!=NULL)かつ(blob_get_size(data)!=0)になる事は有り得ません。言い換えると空のBLOBは常にNULLポインタでのみ表現されます。)
		if(!size) { return NULL; }
		//空のBLOB構造体を確保する。
		blob = calloc(1, sizeof(struct blob));
		if(!blob) { DIE(); }
//{{2017/10/01追加:BLOB構造体にシグネチャを追加しました。
		//シグネチャを格納する。
		blob->sig = FOURCC_BLOB;
//}}2017/10/01追加:BLOB構造体にシグネチャを追加しました。
	}
	//変更前と変更後のワードキャパシティを求める。
	old_words = (blob->bits +              31) / 32;
	new_words = (blob->bits + (size * 8) + 31) / 32;
	//ワードキャパシティが変化するならば…
	if(new_words != old_words) {
		//BLOB構造体を拡張する。
		blob = realloc(blob, sizeof(struct blob) + (new_words * 4));
		if(!blob) { DIE(); }
		//拡張した部分をゼロクリアする。(データ末尾に余りビットが有っても完全なデータとするためです。詳細はstruct blob.bitsフィールドのコメントを参照して下さい。)
		memset(blob->data + old_words, 0, (new_words - old_words) * 4);
	}
	//データを格納する。
	memcpy((char*)blob->data + (blob->bits / 8), p, size);
	//格納したビット数を増やす。
	blob->bits += (size * 8);
	//ビット配列データへのポインタを返す。
	return blob->data;
}
//*****************************************************************************
//	BLOBデータを読み出すユーティリティ関数
//*****************************************************************************
//BLOBリーダー構造体を初期化する。
void blob_reader_init(struct blob_reader* reader, const int* data, int size/*0可*/) {
	reader->data = data;
	reader->bits = size * 8;
	reader->pos  = 0;
}
//-----------------------------------------------------------------------------
//BLOBから1ビット整数値を読み出す。(8ビット境界への整列無し)
int blob_read_bit(struct blob_reader* reader) {
	if(reader->pos >= reader->bits) { DIE(); }	//今回読み出すビット位置が、ビット配列データの総ビット数以上ならば、エラー停止する。(イコールもアウトです)
	return bitarray_lsb1st_get(reader->data, reader->pos++, 1);
}
//-----------------------------------------------------------------------------
//BLOBから1バイト整数値を読み出す。(8ビット境界への整列有り)
int blob_read_byte(struct blob_reader* reader) {
	return *(unsigned char*)blob_read_data(reader, 1);
}
//-----------------------------------------------------------------------------
//BLOBから2バイト整数値を読み出す。(8ビット境界への整列有り)
int blob_read_half(struct blob_reader* reader) {
	unsigned short t;
	return *(unsigned short*)blob_copy_data(reader, &t, 2);
}
//-----------------------------------------------------------------------------
//BLOBから2バイトexp10値を読み出す。(8ビット境界への整列有り)
int blob_read_exp10(struct blob_reader* reader) {
	return Exp10_Decode(blob_read_half(reader));
}
//-----------------------------------------------------------------------------
//BLOBから4バイト整数値を読み出す。(8ビット境界への整列有り)
int blob_read_word(struct blob_reader* reader) {
	int t;
	return *(int*)blob_copy_data(reader, &t, 4);
}
//-----------------------------------------------------------------------------
//{{2018/04/07追加:blob_add_ber(),blob_read_ber()を追加しました。
//BLOBからBER圧縮整数値を読み出す。(8ビット境界への整列有り)
int blob_read_ber(struct blob_reader* reader) {
	int t;
	blob_read_data(reader, BER_Decode(blob_read_data(reader, 0), &t));
	return t;
}
//}}2018/04/07追加:blob_add_ber(),blob_read_ber()を追加しました。
//-----------------------------------------------------------------------------
//BLOBから2バイト浮動小数値を読み出す。(8ビット境界への整列有り)
double blob_read_fp16(struct blob_reader* reader) {
	return extendhfdf2(blob_read_half(reader));
}
//-----------------------------------------------------------------------------
//BLOBから4バイト浮動小数値を読み出す。(8ビット境界への整列有り)
double blob_read_fp32(struct blob_reader* reader) {
	float t;
	return *(float*)blob_copy_data(reader, &t, 4);
}
//-----------------------------------------------------------------------------
//BLOBから8バイト浮動小数値を読み出す。(8ビット境界への整列有り)
double blob_read_fp64(struct blob_reader* reader) {
	double t;
	return *(double*)blob_copy_data(reader, &t, 8);
}
//-----------------------------------------------------------------------------
//BLOBからヌル終端文字列を読み出す。(8ビット境界への整列有り)
const char* blob_read_string(struct blob_reader* reader) {
	return blob_read_data(reader, strlen(blob_read_data(reader, 0)) + 1/*'\0'*/);
}
//-----------------------------------------------------------------------------
//BLOBから任意長のデータを読み出す。(8ビット境界への整列有り)
// - 当関数が返すポインタは、ハーフワード境界やワード境界には整列していません。
//   当関数が返すポインタを(int*)等にキャストして読み出すと、アドレス不整例外が発生します。
//   ハーフワード境界やワード境界への整列が必要な場合は、blob_copy_data()を使用して下さい。
const void* blob_read_data(struct blob_reader* reader, int size/*0可*/) {
	const void* p;
	//確実にバイト境界まで進める。(たとえ0バイトのデータ読み出しであっても!!)
	reader->pos = (reader->pos + 7) & ~7;
	//データのポインタを保存する。
	p = (char*)reader->data + (reader->pos / 8);
	//次に読み出すビット位置を進める。
	reader->pos += (size * 8);
	if(reader->pos > reader->bits) { DIE(); }	//次に読み出すビット位置が、ビット配列データの総ビット数を超えたら、エラー停止する。(イコールはセーフです)
	//データのポインタを返す。
	return p;
}
//-----------------------------------------------------------------------------
//BLOBから任意長のデータを読み出し、指定されたメモリへコピーする。(8ビット境界への整列有り)
// - 呼び出し側の利便性のために、当関数は引数pをそのまま返します。
//   具体例な利用方法は、blob_read_word()等の実装を参照して下さい。
void* blob_copy_data(struct blob_reader* reader, void* p, int size/*0可*/) {
	return memcpy(p, blob_read_data(reader, size), size);
}
//*****************************************************************************
//	BLOBデータを作成するユーティリティ関数とBLOBデータを読み出すユーティリティ関数のテスト
//*****************************************************************************
#if 0
enum {
	type_bit = 1,
	type_byte,
	type_half,
	type_exp10,
	type_word,
	type_ber,	//{{2018/04/07追加:blob_add_ber(),blob_read_ber()を追加しました。}}
	type_fp16,
	type_fp32,
	type_fp64,
	type_string,
	type_data,
	type_max = type_data,
};
struct value_bit    { int type; int n; };
struct value_byte   { int type; int n; };
struct value_half   { int type; int n; };
struct value_exp10  { int type; int n; };
struct value_word   { int type; int n; };
struct value_ber    { int type; int n; };	//{{2018/04/07追加:blob_add_ber(),blob_read_ber()を追加しました。}}
struct value_fp16   { int type; double d; };
struct value_fp32   { int type; double d; };
struct value_fp64   { int type; double d; };
struct value_string { int type; char* s; };
struct value_data   { int type; unsigned char* p; int size; };
union value {
	int                 type;
	struct value_bit    v_bit;
	struct value_byte   v_byte;
	struct value_half   v_half;
	struct value_exp10  v_exp10;
	struct value_word   v_word;
	struct value_ber    v_ber;	//{{2018/04/07追加:blob_add_ber(),blob_read_ber()を追加しました。}}
	struct value_fp16   v_fp16;
	struct value_fp32   v_fp32;
	struct value_fp64   v_fp64;
	struct value_string v_string;
	struct value_data   v_data;
};
static void test() {
	void* data = NULL;
	struct blob_reader reader;
	int n_value, n_bit, i, j, n;
	union value *TBL_value/*[n_value]*/, *p_value;
	struct value_bit*    p_bit;
	struct value_byte*   p_byte;
	struct value_half*   p_half;
	struct value_exp10*  p_exp10;
	struct value_word*   p_word;
	struct value_ber*    p_ber;	//{{2018/04/07追加:blob_add_ber(),blob_read_ber()を追加しました。}}
	struct value_fp16*   p_fp16;
	struct value_fp32*   p_fp32;
	struct value_fp64*   p_fp64;
	struct value_string* p_string;
	struct value_data*   p_data;
	//元データを作成する。
	n_value = RND32_RANGE(seed, 10, 100);	//値の数
	TBL_value = calloc(n_value, sizeof(union value));
	n_bit = 0;	//type_bitを連続し易いようにするための変数。
	for(i = 0; i < n_value; i++) {
		p_value = &TBL_value[i];
		if(n_bit) {	//type_bit連続中ならば…
			p_value->type = type_bit;
			n_bit--;
		} else {
			p_value->type = RND32_RANGE(seed, 1, type_max + 1);
			if(p_value->type == type_bit) {				//type_bitが新たに抽選されたら…
				n_bit = RND32_RANGE(seed, 0, 16/*調整可*/);	//次回以降のtype_bit連続数を抽選する。
			}
		}
		switch(p_value->type) {
		default:DIE();
		case type_bit:    p_bit    = &p_value->v_bit;    p_bit->n   =                        RND8( seed) & 1; break;
		case type_byte:   p_byte   = &p_value->v_byte;   p_byte->n  =                        RND8( seed);     break;
		case type_half:   p_half   = &p_value->v_half;   p_half->n  =                        RND16(seed);     break;
		case type_exp10:  p_exp10  = &p_value->v_exp10;  p_exp10->n =           Exp10_Decode(RND16(seed));    break;
		case type_word:   p_word   = &p_value->v_word;   p_word->n  =                        RND32(seed);     break;
		case type_ber:    p_ber    = &p_value->v_ber;    p_ber->n   =                        RND32(seed);     break;	//{{2018/04/07追加:blob_add_ber(),blob_read_ber()を追加しました。}}
		case type_fp16:   p_fp16   = &p_value->v_fp16;   p_fp16->d  = extendhfdf2(truncdfhf2(RNDF( seed)));   break;
		case type_fp32:   p_fp32   = &p_value->v_fp32;   p_fp32->d  =                 (float)RNDF( seed);     break;
		case type_fp64:   p_fp64   = &p_value->v_fp64;   p_fp64->d  =                        RNDF( seed);     break;
		case type_string: p_string = &p_value->v_string; n            = RND32_RANGE(seed, 0, 100); p_string->s = calloc(n + 1/*'\0'*/, 1); for(j = 0; j < n;            j++) { p_string->s[j] = RND32_RANGE(seed, 'A', 'Z' + 1); } break;
		case type_data:   p_data   = &p_value->v_data;   p_data->size = RND32_RANGE(seed, 0, 100); p_data->p   = malloc(p_data->size    ); for(j = 0; j < p_data->size; j++) { p_data->p[  j] = RND8(       seed);               } break;
		}
	}
	//BLOBを作成する。
	for(i = 0; i < n_value; i++) {
		p_value = &TBL_value[i];
		switch(p_value->type) {
		default:DIE();
		case type_bit:    p_bit    = &p_value->v_bit;    data = blob_add_bit(   data, p_bit->n               ); break;
		case type_byte:   p_byte   = &p_value->v_byte;   data = blob_add_byte(  data, p_byte->n              ); break;
		case type_half:   p_half   = &p_value->v_half;   data = blob_add_half(  data, p_half->n              ); break;
		case type_exp10:  p_exp10  = &p_value->v_exp10;  data = blob_add_exp10( data, p_exp10->n             ); break;
		case type_word:   p_word   = &p_value->v_word;   data = blob_add_word(  data, p_word->n              ); break;
		case type_ber:    p_ber    = &p_value->v_ber;    data = blob_add_ber(   data, p_ber->n               ); break;	//{{2018/04/07追加:blob_add_ber(),blob_read_ber()を追加しました。}}
		case type_fp16:   p_fp16   = &p_value->v_fp16;   data = blob_add_fp16(  data, p_fp16->d              ); break;
		case type_fp32:   p_fp32   = &p_value->v_fp32;   data = blob_add_fp32(  data, p_fp32->d              ); break;
		case type_fp64:   p_fp64   = &p_value->v_fp64;   data = blob_add_fp64(  data, p_fp64->d              ); break;
		case type_string: p_string = &p_value->v_string; data = blob_add_string(data, p_string->s            ); break;
		case type_data:   p_data   = &p_value->v_data;   data = blob_add_data(  data, p_data->p, p_data->size); break;
		}
	}
	//BLOBを読み出して比較する。
	blob_reader_init(&reader, data, blob_get_size(data));
	for(i = 0; i < n_value; i++) {
		p_value = &TBL_value[i];
		switch(p_value->type) {
		default:DIE();
		case type_bit:    p_bit    = &p_value->v_bit;    if(blob_read_bit(  &reader) != p_bit->n  ) { DIE(); } break;
		case type_byte:   p_byte   = &p_value->v_byte;   if(blob_read_byte( &reader) != p_byte->n ) { DIE(); } break;
		case type_half:   p_half   = &p_value->v_half;   if(blob_read_half( &reader) != p_half->n ) { DIE(); } break;
		case type_exp10:  p_exp10  = &p_value->v_exp10;  if(blob_read_exp10(&reader) != p_exp10->n) { DIE(); } break;
		case type_word:   p_word   = &p_value->v_word;   if(blob_read_word( &reader) != p_word->n ) { DIE(); } break;
		case type_ber:    p_ber    = &p_value->v_ber;    if(blob_read_ber(  &reader) != p_ber->n  ) { DIE(); } break;	//{{2018/04/07追加:blob_add_ber(),blob_read_ber()を追加しました。}}
		case type_fp16:   p_fp16   = &p_value->v_fp16;   if(blob_read_fp16( &reader) != p_fp16->d ) { DIE(); } break;
		case type_fp32:   p_fp32   = &p_value->v_fp32;   if(blob_read_fp32( &reader) != p_fp32->d ) { DIE(); } break;
		case type_fp64:   p_fp64   = &p_value->v_fp64;   if(blob_read_fp64( &reader) != p_fp64->d ) { DIE(); } break;
		case type_string: p_string = &p_value->v_string; if(strcmp(blob_read_string(&reader              ), p_string->s            )) { DIE(); } break;
		case type_data:   p_data   = &p_value->v_data;   if(memcmp(blob_read_data(  &reader, p_data->size), p_data->p, p_data->size)) { DIE(); } break;
		}
	}
	//元データを開放する。
	for(i = 0; i < n_value; i++) {
		p_value = &TBL_value[i];
		switch(p_value->type) {
		default:DIE();
		case type_bit:    p_bit    = &p_value->v_bit;    /** no job **/     break;
		case type_byte:   p_byte   = &p_value->v_byte;   /** no job **/     break;
		case type_half:   p_half   = &p_value->v_half;   /** no job **/     break;
		case type_exp10:  p_exp10  = &p_value->v_exp10;  /** no job **/     break;
		case type_word:   p_word   = &p_value->v_word;   /** no job **/     break;
		case type_ber:    p_ber    = &p_value->v_ber;    /** no job **/     break;	//{{2018/04/07追加:blob_add_ber(),blob_read_ber()を追加しました。}}
		case type_fp16:   p_fp16   = &p_value->v_fp16;   /** no job **/     break;
		case type_fp32:   p_fp32   = &p_value->v_fp32;   /** no job **/     break;
		case type_fp64:   p_fp64   = &p_value->v_fp64;   /** no job **/     break;
		case type_string: p_string = &p_value->v_string; free(p_string->s); break;
		case type_data:   p_data   = &p_value->v_data;   free(p_data->p  ); break;
		}
	}
	free(TBL_value);
	//BLOBを開放する。
	blob_free(data);
}
int app_main(int argc, char* argv[]) {
	int cnt = 0;
	seed = 0;	//再現性のために、同じ乱数シードから開始する事にした。
	for(;;) {
		printf("\r%d", ++cnt);
		test();
	}
}
#endif
