/*	
 *	clipreg.h
 *
 *	レジストリテーブル
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2015-2016 Naoyuki Sawa
 *
 *	* Tue Mar 24 02:10:47 JST 2015 Naoyuki Sawa
 *	- 1st リリース。
 *	* Tue Mar 24 21:45:37 JST 2015 Naoyuki Sawa
 *	- REG_open_key(),及び,REG_get_value()に、(keyBody=NULL)を指定しても安全にしました。
 *	  REG_open_key_v()とREG_get_value_v()の処理の大部分を共通化してコード削減しました。
 *	* Thu Mar 26 21:28:16 JST 2015 Naoyuki Sawa
 *	- dRegTblC.exeの出力データ構造を変更した事に伴い、当モジュールも大幅に変更しました。
 *	  前回まではキー配列をリニアサーチしていましたが、今後はバイナリサーチになりました。
 *	  詳細は、「clip/tool/dRegTblC/winapp.h」の同日のコメントを参照してください。
 *	* Sat Apr 11 13:20:40 JST 2015 Naoyuki Sawa
 *	 - 文字列のデータタイプを追加し、大幅な変更を行いました。
 *	   変更前のコードを参照するには、前回のアーカイブを参照してください。
 *	* Mon Jul 27 21:32:15 JST 2015 Naoyuki Sawa
 *	- REG_open_key_v()の処理を修正しました。修正内容は、以下の通りです:
 *	  'REG_open_key_l(keyBody,-1)'に対して、これまではNULLを返していました。(keyBody)自身を返すのが自然であると思うので、そのように修正しました。
 *	- 既に、clipfsm.c の FsmObj_GetTransKey() にて、'REG_open_key_l(keyBody,-1)'が(keyBody)自身を返す事を期待したコードを書いてしまっていました。
 *	  これまでは、'REG_open_key_l(keyBody,-1)'がNULLを返していたので、FsmObj_GetTransKey() が正しく動作していませんでした。
 *	  今回、'REG_open_key_l(keyBody,-1)'が(keyBody)自身を返すように修正したので、FsmObj_GetTransKey() が正しく動作するようになりました。
 *	- 上記の修正を、REG_open_get_v()やREG_open_key()ではなく、REG_open_key_v()で行った理由は、影響範囲を小さく留めるためです。
 *	  REG_open_get_v()やREG_open_key()は、他の関数との共通性のために、(keyName=-1)を終端と見なす特例処理を行いたくありません。
 *	  特例処理は、呼び出し階層の浅い部分で行う方が安全だと考えて、REG_open_key_v()で行う事にしました。
 *	* Tue Sep 22 12:15:09 JST 2015 Naoyuki Sawa
 *	- 「インデクスアクセス型,及び,イテレーション用の関数」を追加しました。
 *	- インデクスアクセス型の関数を使用して、イテレーションを行う例を示します。
 *	  □TBL_RegTbl->RegKey_X->RegKey_Yに属する値をｲﾃﾚｰﾄする｡TBL_RegTbl->RegKey_X->RegKey_Yが存在しなくても安全です｡
 *	  │for(index=0;
 *	  │    (valueData=REG_get_nth_value_l(TBL_RegTbl,index,&valueName,RegKey_X,RegKey_Y,-1))!=-1;
 *	  │    index++){
 *	  │      printf("%d:%d=>%d\n",index,valueName,valueData);
 *	  │}
 *	* Sun Oct 04 21:01:44 JST 2015 Naoyuki Sawa
 *	- 大幅な変更を行いました。
 *	  変更前のコードはソースの中に残していないので、必要ならば前回までのソースを参照してください。
 *	  変更前のソースとツールを'keep/17_レジストリテーブル形式変更前保存/'に保存しておきました。
 *	- 変更点は以下の通りです。
 *	  ①'値'データが24ビット符号無しの値を返せるようにしました。これまでは16ビット符号無しの値しか返せませんでした。
 *	  ②'BLOB'タイプを追加しました。これまでは'BLOB'タイプが無く、複数の値に分割して格納していました。
 *	  ③配列の要素数の上限が65536になりました。これまでは配列の要素数の上限が65535でした。
 *	- 既存の関数仕様には変更有りません。'BLOB'タイプの関数を追加しました。
 *	  レジストリテーブルのバイナリフォーマットは互換性は有りません。
 *	- 今回の変更により、全てのタイプのデータが24ビットに統一されました。新しいタイプを追加する事も容易だと思います。
 *	  マスクのビットも4ビット残っているので、あと4種類は容易に増やせます。詳細はREG_op()のmask変数を参照して下さい。
 *	* Wed Oct 07 21:27:19 JST 2015 Naoyuki Sawa
 *	- REG_get_blob_size()を追加しました。
 *	* Thu Oct 08 21:52:46 JST 2015 Naoyuki Sawa
 *	- BLOBのデータ構造を少し変更しました。
 *	  これまでは、BLOBのサイズに(データ本体のバイト数)を格納していましたが、今後は、(データ本体のバイト数-1)を格納します。
 *	  他のフィールドには(要素数-1)を格納しているので、BLOBのサイズもそれらに合わせて統一する方が判り易いと思ったからです。
 *	* Fri Oct 09 22:14:58 JST 2015 Naoyuki Sawa
 *	- REG_op()を高速化しました。
 *	  これまでは汎用のbsearch()を利用していましたが、REG_op()からの利用に特化して高速化したREG_bsearch()を作成してそれを呼び出すようにしました。
 *	  厳密な計測ではありませんが、REG_op()を呼び出す関数の動作が、3倍ぐらい早くなったみたいです。
 *	* Wed Oct 14 21:21:55 JST 2015 Naoyuki Sawa
 *	- 警告抑制のためにREG_bsearch()のC言語版の実装を修正しました。
 *	  動作内容は変わっていません。
 *	* Thu Oct 29 21:30:16 JST 2015 Naoyuki Sawa
 *	- REG_op()とREG_nth()のaddrにNULLが渡された場合の判定が抜けていたのを修正しました。
 *	- 上記のREG_op()のバグの影響で、clipfsm.cのFsmObj_ApplyTrans()が正しく動作していませんでした。
 *	  FsmObj_ApplyTrans()の処理で、(pKey=NULL)に対してiFnGrd,iFnAct,iStNexを取得しようとした時に、正しくは(-1)を返すべきところ、NULLアドレス付近のメモリが偶然キーに一致すると、値が取得できたと見なしてしまい間違った値を返してしまうからです。
 *	  今回の修正によって、FsmObj_ApplyTrans()が正しく動作するようになりました。
 *	* Wed Nov 18 21:37:53 JST 2015 Naoyuki Sawa
 *	- 'extern "C" {'～'}'で囲みました。.cppを含むWin32プロジェクトからもインクルード出来るようにするためです。
 *	* Thu May 12 22:56:34 JST 2016 Naoyuki Sawa
 *	- 「要素数を取得する関数」を追加しました。理由は以下の通りです。
 *	  要素数を取得する方法は、既存の「インデクスアクセス型,及び,イテレーション用の関数」を使って、NULL,又は,-1が返されるまでindexを増やしながらループする方法も有るのですが、その方法では要素数が多いと時間が掛かってしまうという問題が有ります。
 *	  要素数が多くても高速に要素数を取得したいケースが生じたので、明示的に要素数を取得する関数群を追加する事にしました。
 */
#ifndef __CLIP_REG_H__
#define __CLIP_REG_H__
#ifdef  __cplusplus
extern "C" {
#endif//__cplusplus
/****************************************************************************
 *	辞書アクセス型の関数
 ****************************************************************************/
/*==========================================================================*
 *	基本的な関数
 *==========================================================================*/
const uint8_t* REG_open_key(const uint8_t* keyBody, int keyName);
int REG_get_value(const uint8_t* keyBody, int valueName);
const char* REG_get_string(const uint8_t* keyBody, int stringName);
const void* REG_get_blob(const uint8_t* keyBody, int  blobName);
/*==========================================================================*
 *	ユーティリティ関数
 *==========================================================================*/
const uint8_t* REG_open_key_l(const uint8_t* keyBody, ...);
const uint8_t* REG_open_key_a(const uint8_t* keyBody, va_list ap);
const uint8_t* REG_open_key_v(const uint8_t* keyBody, const int* names/*[[[[keyName,]keyName],…,]keyName,]-1*/);
/*--------------------------------------------------------------------------*/
int REG_get_value_l(const uint8_t* keyBody, ...);
int REG_get_value_a(const uint8_t* keyBody, va_list ap);
int REG_get_value_v(const uint8_t* keyBody, const int* names/*[[[[keyName,]keyName],…,]valueName,]-1*/);
/*--------------------------------------------------------------------------*/
const char* REG_get_string_l(const uint8_t* keyBody, ...);
const char* REG_get_string_a(const uint8_t* keyBody, va_list ap);
const char* REG_get_string_v(const uint8_t* keyBody, const int* names/*[[[[keyName,]keyName],…,]stringName,]-1*/);
/*--------------------------------------------------------------------------*/
const void* REG_get_blob_l(const uint8_t* keyBody, ...);
const void* REG_get_blob_a(const uint8_t* keyBody, va_list ap);
const void* REG_get_blob_v(const uint8_t* keyBody, const int* names/*[[[[keyName,]keyName],…,]blobName,]-1*/);
/****************************************************************************
 *	インデクスアクセス型,及び,イテレーション用の関数
 ****************************************************************************/
/*==========================================================================*
 *	基本的な関数
 *==========================================================================*/
const uint8_t* REG_open_nth_key(const uint8_t* keyBody, int index, int* p_keyName/*NULL可*/);
int REG_get_nth_value(const uint8_t* keyBody, int index, int* p_valueName/*NULL可*/);
const char* REG_get_nth_string(const uint8_t* keyBody, int index, int* p_stringName/*NULL可*/);
const void* REG_get_nth_blob(const uint8_t* keyBody, int index, int* p_blobName/*NULL可*/);
/*==========================================================================*
 *	ユーティリティ関数
 *==========================================================================*/
const uint8_t* REG_open_nth_key_l(const uint8_t* keyBody, int index, int* p_keyName/*NULL可*/, ...);
const uint8_t* REG_open_nth_key_a(const uint8_t* keyBody, int index, int* p_keyName/*NULL可*/, va_list ap);
const uint8_t* REG_open_nth_key_v(const uint8_t* keyBody, int index, int* p_keyName/*NULL可*/, const int* names/*[[[[keyName,]keyName],…,]keyName,]-1*/);
/*--------------------------------------------------------------------------*/
int REG_get_nth_value_l(const uint8_t* keyBody, int index, int* p_valueName/*NULL可*/, ...);
int REG_get_nth_value_a(const uint8_t* keyBody, int index, int* p_valueName/*NULL可*/, va_list ap);
int REG_get_nth_value_v(const uint8_t* keyBody, int index, int* p_valueName/*NULL可*/, const int* names/*[[[[keyName,]keyName],…,]keyName,]-1*/);
/*--------------------------------------------------------------------------*/
const char* REG_get_nth_string_l(const uint8_t* keyBody, int index, int* p_stringName/*NULL可*/, ...);
const char* REG_get_nth_string_a(const uint8_t* keyBody, int index, int* p_stringName/*NULL可*/, va_list ap);
const char* REG_get_nth_string_v(const uint8_t* keyBody, int index, int* p_stringName/*NULL可*/, const int* names/*[[[[keyName,]keyName],…,]keyName,]-1*/);
/*--------------------------------------------------------------------------*/
const void* REG_get_nth_blob_l(const uint8_t* keyBody, int index, int* p_blobName/*NULL可*/, ...);
const void* REG_get_nth_blob_a(const uint8_t* keyBody, int index, int* p_blobName/*NULL可*/, va_list ap);
const void* REG_get_nth_blob_v(const uint8_t* keyBody, int index, int* p_blobName/*NULL可*/, const int* names/*[[[[keyName,]keyName],…,]keyName,]-1*/);
/****************************************************************************
 *	要素数を取得する関数
 ****************************************************************************/
/*==========================================================================*
 *	基本的な関数
 *==========================================================================*/
int REG_num_key(const uint8_t* keyBody);
int REG_num_value(const uint8_t* keyBody);
int REG_num_string(const uint8_t* keyBody);
int REG_num_blob(const uint8_t* keyBody);
/*==========================================================================*
 *	ユーティリティ関数
 *==========================================================================*/
int REG_num_key_l(const uint8_t* keyBody, ...);
int REG_num_key_a(const uint8_t* keyBody, va_list ap);
int REG_num_key_v(const uint8_t* keyBody, const int* names/*[[[[keyName,]keyName],…,]keyName,]-1*/);
/*--------------------------------------------------------------------------*/
int REG_num_value_l(const uint8_t* keyBody, ...);
int REG_num_value_a(const uint8_t* keyBody, va_list ap);
int REG_num_value_v(const uint8_t* keyBody, const int* names/*[[[[keyName,]keyName],…,]keyName,]-1*/);
/*--------------------------------------------------------------------------*/
int REG_num_string_l(const uint8_t* keyBody, ...);
int REG_num_string_a(const uint8_t* keyBody, va_list ap);
int REG_num_string_v(const uint8_t* keyBody, const int* names/*[[[[keyName,]keyName],…,]keyName,]-1*/);
/*--------------------------------------------------------------------------*/
int REG_num_blob_l(const uint8_t* keyBody, ...);
int REG_num_blob_a(const uint8_t* keyBody, va_list ap);
int REG_num_blob_v(const uint8_t* keyBody, const int* names/*[[[[keyName,]keyName],…,]keyName,]-1*/);
/****************************************************************************
 *	BLOBのデータ構造について
 ****************************************************************************/
//	┌─────────────────┐
//  4N-3│(データ本体のバイト数-1) bit23～16│	┐
//  4N-2│(データ本体のバイト数-1) bit15～ 8│	├符号無し24ビットBE	アプリケーションがBLOBのバイト数を知る必要が有る場合は、REG_get_blob()やREG_get_nth_blob()が返したアドレスの3バイト前～1バイト前を参照して下さい。REG_get_blob_size()を利用する事も出来ます。
//  4N-1│(データ本体のバイト数-1) bit 7～ 0│	┘
//	├─────────────────┤
//  4N  │ データ本体の1バイト目　　　　　　│	←REG_get_blob()やREG_get_nth_blob()が返すアドレスはここを指しています。データ本体の1バイト目はワードアライメントされている事が保証されています。(dRegTblC.exeが必要に応じて各BLOBの前にパディングを出力しているから)
//	│ データ本体の2バイト目　　　　　　│
//	│　　　　　　　・　　　　　　　　　│
//	│　　　　　　　・　　　　　　　　　│
//	│　　　　　　　・　　　　　　　　　│
//	│ データ本体の?バイト目　　　　　　│
//	└─────────────────┘
int REG_get_blob_size(const void* _blob/*NULL可*/);
#ifdef  __cplusplus
}//extern "C"
#endif//__cplusplus
#endif//__CLIP_REG_H__
