Common Data Representation(CDR)
An Open Software Platform for Robotic Technologies
Home RtORB
RtORBの開発 >> 開発メモ >> RtORBの開発メモ >> Common Data Representation(CDR)

Common Data Representation(CDR)

CDRは、OMGのGIOPの仕様で規定されている。データの表現情報の一つである。このCDRの表現を用いて、リモートオブジェクトへのデータの受渡しや結果の受信をおこなっている。このCDRは、送受信に使われるために、marshalingとunmarshalingによる、符号化と復号化に関する規定である。
RtORBでは、CDRに関しては、giop-marshal.cの中に記述されている。

データ型

先ず、データの符号化と復号化の説明の前に、CORBAで使用するデータタイプについて述べる。CORBAで扱うデータは、charやintのようなプリミティブ型とstructやunion,sequenceなどのようにIDLで設定するコンストラクト型に大別される。これの他には、データ型を表すTypeCodeやCORBAオブジェクト、すべての型をあらわすany型などのような擬似オブジェクト型がある。プリミティブ型は、CORBAの実装で予め決められているデータ表現でありバイト列に符号化する場合に、置くことができる場所が決められている。これはAlignmentと呼ばれており、データの符号化、復号化のプログラムを書くときに気をつけなければならない。

プリミティブ型

プリミティブ型には、下記ようにAlignmentが決められている。 各型のRtORBへのマッピングも示す。
TYPEデータ長AlignmentRtORBにおけるマッピング
char11char
wchar21, 2 or 4 for GIOP 1.1
1 for GIOP 1.2 and lator
unsigned short
octet11char
short22short
unsigned short22unsigned short
long44int
unsigned long44unsigned int
long long88なし
unsigned long long88なし
float44float
double88double
long double168なし
boolean11char
上記のことから、例えば、charとlongの2つのデータをバイト列に符号化する場合には、
  • char,longの順:1バイト目にchar, 5バイト目から8バイト目にlongのデータが格納される。
    01234567
    clong
  • long,charの順:1バイト目にlong, 5バイト目にcharのデータが格納される。
    01234
    longc
のように符号化した場合のデータ長が変わってくる。

コンストラクト型

コンストラクタ型のデータ型では、Alignmentは特に決まっていません。これは、符号化する際に、どの様なデータに並べられているかによるからです。各データ型のAlignmentは、それを符号化の際に、その中のプリミティブ型のAlignmentに従うと思っていればよいと思います。
String型とWstring型
String型とWstring型は、通常、C言語では、それぞれ"unsigned char*"と”wchar_t *"にマッピングされる。RtORBでは、Wstring型を"unsigned short *"にマッピングしているが、これは、仮対応であるので正しい動作はしない。String型のデータは、バイト列への符号化する場合には、文字列の長さ+文字列 となる。文字列の長さおよび文字列には、終端記号である\0が含まれるので、注意すべきである。このことからString型では、Alignmentは、longと同じ ”4” になる。
Wstring型に関しては、少し複雑であるためにC言語を使う場合には、現在のところ該当するコードが実装されていない。CORBAにおける文字列の扱いは、仕様書のCord Set Conversionに詳しく書いてある。簡単に言えば、文字列には、2種類あり、バイト単位で扱えるもの(byte-oriented)とそうでないもの(non-byte-oriented)がある。バイト単位で扱えるものには、single-byteのASCII,ISAO 8859-1 ,EBCDIC等とmuiti-byteのUTF-8,eucJP,Shift-JIS, JIS等がある。これらのコードを扱うだけであれば、String型のサポートでCord Set Conversionは、何もしないように動作させればよい。バイト単位で扱えない文字列は、Wstring型がそうであるが、ISO 10646 USC-2(Unicode)やUTF-16などがこれにあたる。この文字列を取り扱う場合には、クライアントとサーバー間でCord Set Conversionをどうするかを事前に決めておく必要がある。さらに、文字列の取り扱いについては、GIOPの1.2以降でその仕様が変更されているために、すべてのものを実装しても、使用頻度とアプリケーションを考えると、無理に実装する必要ないかと思っています。どうしても必要な場合は、UTF-16に対する対応ぐらいは考えてもよいと思っています。
<
詳細は、OMGから公開されてる仕様書を読んでいただく方がよいと思います。
Struct型
構造体は、C言語へのマッピングは、ほぼそのままです。すなわち構造体の各データ型をそのまま置き換えるということです。そのため、Alignmentも構成されたデータ型によって変わります。
RtORBのC++のラッパーでは、オブジェクト呼出の引数のタイプ(in, out, inout)によって振舞が変わりますし、_var, _ptr 等のデータ型もありますので、アクセス用のテンプレートクラスの定義をcorba-struct.hhで行っています。詳細は、ソースコードを参照して下さい。
OpenRTM-aistでは、データの送受信時に、すべてのデータをCDRで符号化しています。OpenRTM-aistのソースコードを読めば分かるのですが、その中では、CORBAの実装であるomniORBのcdrStreamクラスを利用しています。RtORBでも、このcdrStreamとほぼ同じ機能を再実装していますので、同じ機能を実現した関数が、giop-marshal.cとcdrStream.cpp, cdrStream.hに入っています。今後は、ソースコードを整理す必要があるかもしれません。
<
Union型
共用体は、C言語の標準マッピングでは、そのままunionとなっています。当初は、RtORBでもunion型へマッピングしていましたが、OpenRTM-aistの下位層で使用するために、格納されたデータ型の種類を表すindexと構成要素を各要素とした構造体になる。
例えば、
 enum NumericType {    SHORT_TYPE, LONG_TYPE, FLOAT_TYPE, DOUBLE_TYPE
 };
 union Numeric switch (NumericType){
    case SHORT_TYPE: short short_value;
    case LONG_TYPE: long long_value;
    case FLOAT_TYPE: float float_value;
    case DOUBLE_TYPE: double double_value;
 };
とIDLで定義さえていれば、IDLコンパイラにより
 enum {   SHORT_TYPE, LONG_TYPE, FLOAT_TYPE, DOUBLE_TYPE
 };
 typedef int NumericType;
 typedef Numeric_type Numeric;
 struct Numeric_type{
    NumericType __d;
    struct{
      CORBA_short short_value;
      CORBA_long long_value;
      CORBA_float float_value;
      COBRA_double double_value;
   } _u;
 };
となる。これは、C++のラッパーを作成するときに、コンストラクタをもつ構造体に共用体を内部に持つことが禁止されているためである。
Union型を符号化する場合には、現在値が入っている型を表すindex(__d)データ(_u.xx) になる。
Sequence型
シーケンス型は、いわゆる可変長配列である。C++では、 vectorクラスとよく似ている。例えば、
 struct NmaeValue{    string name;
    any value;
 };
 typedef seqnece<NameValue> NVList;
は、IDLコンパイラによって下記のようになる。
 typedef struct NameValue_type NameValue; struct NameValue_type{
   CORBA_string name;
   CORBA_any value;
 };
 
 typedef struct CORBA_sequence_NameValue_type{
   CORBA_unsigned_long  _maximum, _length;
   NameValue *_buffer;
   CORBA_unsigned_long _release;
 } CORBA_sequence_NameValue;
 typedef CORBA_sequence_NameValue  NVList;
Seqeunce型を符号化する場合には、Sequenceの長さ構成された値の列 であり、String型を汎用化したものと考えて良い。Sequence型のAlignmentは、長さ、値のそれぞれのAlignmentに従うことになる。
Enum型
Enum型は、CORBAでは同じenumにマッピングされる。C言語の場合には、int にtypedef されている。Enum型の符号化は、longの場合と同じになる。

擬似オブジェクト型

擬似オブジェクト型は、CORBAにおける”型”を表す TypeCode、すべてのデータ型を表せすAny,例外を表すException、CORBAオブジェクトを表すObjectReferenceなどがある。この他にPrincipalやContextなどがある。
TypeCode型
TypeCodeは、CORBAで使用する”型”を表す。RtORBでは、TypeCodeを表す構造体をcorba-defs.hに下記のように記載されている。
 typedef struct CORBA_TypeCode_struct{   void *			parents;
   CORBA_TCKind			kind;
   CORBA_RepositoryId		repository_id;
   CORBA_Identifier		identifier; 
   unsigned long			member_count; 	/* struct, union, enum, value, exception, event */
   CORBA_Identifier  		*member_name; 	/* struct, union, enum, value, exception, event */
   struct CORBA_TypeCode_struct 	**member_type; 	/* struct, union, value, exception, event */
   long 			*member_label; 	/* union */
   struct CORBA_TypeCode_struct 	*discriminator; /* union */
   long   			default_index;  /* union */
   unsigned long   		length; 	/* string, wstring, sequence, array */ 
   struct CORBA_TypeCode_struct 	*content_type;  /* sequence, array, value_box, alias */ 
   unsigned short		fixed_digits;   /* fixed */
   short				fixed_scale;    /* fixed */
   CORBA_Visibility		*member_visibility;  	/* value, event */
   CORBA_ValueModifier		type_modifier;  	/* value, event */
   struct CORBA_TypeCode_struct 	*concrete_base_type;  	/* value, event */
   short 			size;
   short				alignment;
 
 #ifdef __cplusplus
   const char *id() const { return repository_id; }
   const char *name() const { return identifier; }
 #endif 
 
 }CORBA_TypeCode_struct;
このTypeCodeの定義自体は、ORBit2で用いられているものとほぼ同じである。これは、基本的に、RtORBのIDLコンパイラがORBit2で用いられてものを流用し、独自部分を付加するように作成したためである。また、上記の定義からわかるが、TypeCodeの一意性は、kind, repository_id, identifierで表されている。
TypeCodeの符号化については、その型によって変わる。先ず、kindのみの符号化で済むのは、tk_null, tk_void, tk_short, tk_long, tk_ushort,tk_ulong, tk_float, tk_double, tk_boolean, tk_char, tk_octet,tk_any, tk_TypeCode, tk_Principal, tk_longlong, tk_ulonglong, tk_longdoubleである。また、kind + (long)0 で符号化されるのは,tk_string, tk_wstringである。それ以外のTypeCodeは、それぞれ符号化の方法が異なっている。
Any型
Any型は、C言語で言えば汎用ポインタ(void *)になるが、CORBAでは、内容の型を表すTypeCodeと値を表す汎用ポインタからなる。Any型の定義は、corba-defs.hに下記のように記載されてる。
 typedef union {
   CORBA_boolean val_bool;
   CORBA_octet val_octet;
   CORBA_char  val_char;
   CORBA_unsigned_long val_ulong;
 
   char * val_str;
   struct CORBA_Object_struct * val_obj;
   void * val_except;
 
   /* tk_struct */
   struct val_t {
     int   len;
     char * data;
   } val_encoded;
 } CORBA_any_val; 
 
 typedef struct CORBA_any {
   struct CORBA_TypeCode_struct *_type;
   CORBA_any_val *_val;
   CORBA_unsigned_long _release;
  
 #ifdef __cplusplus
   CORBA_any();
   CORBA_any(const CORBA_any &o);
   ~CORBA_any();
 
   CORBA_boolean hasData(struct CORBA_TypeCode_struct *) const; 
 
   void setData(struct CORBA_TypeCode_struct *tc, char *data, int len);
   void copy_val(CORBA_TypeCode_struct *, CORBA_any_val *);
   void set_val(CORBA_TypeCode_struct *, CORBA_any_val *);
 	
   void alloc(CORBA_TypeCode_struct *);
   void free_();
   
   CORBA_any & operator=(const CORBA_any &o); 
 
   CORBA_any * duplicate();
 
   CORBA_TypeCode_struct * type() { return _type; }
 		
   struct from_char {
     from_char(CORBA_char v) : val(v) {};
     CORBA_char val;
   }; 
 
   struct from_boolean {
     from_boolean(CORBA_boolean v) : val(v) {};
     CORBA_boolean val;
   };
 
   struct from_octet {
     from_octet(CORBA_octet v) : val(v) {};
     CORBA_octet val;
   };
 
   struct from_string {
     from_string(const char *v) : val(v) {}
     const char *val;
   };
 
   struct from_object {
     from_object(CORBA::Object_ptr &ptr_);
     CORBA::Object_ptr &ptr;
   };
   
   struct from_any {
     from_any(CORBA_any *v) : val(v) {}
     CORBA_any * val;
   };
 
   void operator<<=(from_char);
   void operator<<=(from_boolean);
   void operator<<=(from_octet);
   void operator<<=(from_string);
   void operator<<=(from_object);
   void operator<<=(from_any);
   void operator<<=(CORBA_unsigned_long); 
 
   struct to_char {
     to_char(CORBA_char &buf_) : buf(buf_){}
     CORBA_char &buf;
   }; 
 
   struct to_octet {
     to_octet(CORBA_octet &buf_) : buf(buf_){}
     CORBA_octet &buf;
   };
 
   struct to_boolean {
     to_boolean(CORBA_boolean &buf_) : buf(buf_){}
     CORBA_boolean &buf;
   }; 
 
   struct to_string {
     to_string(char *& buf_) : buf(buf_){}
     to_string(const char *& buf_) : buf((char *&)buf_){}
     char * & buf;
   };
 
   struct to_object {
     to_object(CORBA::Object_ptr &ptr_) : ptr(ptr_) {}
     CORBA::Object_ptr &ptr;
   }; 
 	
   CORBA_boolean operator>>=(to_char o) const;
   CORBA_boolean operator>>=(to_boolean o) const;
   CORBA_boolean operator>>=(to_octet o) const;
   CORBA_boolean operator>>=(to_string o) const;
   CORBA_boolean operator>>=(to_object o) const;
   CORBA_boolean operator>>=(CORBA_any &o) const;
   CORBA_boolean operator>>=(CORBA_unsigned_long &n) const;
 #endif
 } CORBA_any ;
この表現は、完全ではないが、OpenRTM-aistで用いるには、十分であるように実装されている。OpenRTM-aistでは、現在Any型を非常に限定された場所でしか使用していないため、限定的にさらに簡易な実装も可能である。
Any型の符号化では、まずそのデータのTypeCodeが符号化され続いて、そのデータが符号化される。RtORBにおいてのAny型の実装に関しては、OpenRTM-aistで利用している範囲では、ほぼ正常に動作しているが、完全ではない。
Exception型
Exceptionは、CORBAの関数呼び出し時に発生する例外を表す。RtORBでは、Exceptionは、それを一意にあらわる文字列をもつ構造体としている。
Object Reference
これは、CORBAオブジェクトを表す。オブジェクトリファレンスは、The Interoperable Object Reference (IOR)のことであり、マジックナンバー、バイトオーダー。タグ付きのプロファイル、プロトコルのバージョン、サーバのアドレスとポート番号、リモートオブジェクトを識別するバオブジェクトキー、コンポーネントのプロファイルを含んだ印字可能な文字列になっている。
オブジェクトリファレンスは、文字列であるが、通常の文字列と異なり、その長さを符号化しない。これは、オブジェクトリファレンスがバイト列は、カプセル化されたものになっているからであり、その情報のみで復号可能だからである。
ちなみに、CORBAオブジェクトのリファレンス表現でよく出てくる IOR:..... という表現は、”IOR:” 以降の文字列をバイト列に変換して復号化すればよい。つまり ”01000000” という文字列は、 01000000 というバイト列になる。 

データの符号化(marshling)

データの符号化は、CORBAオブジェクトのメソッド呼出の時、クライアントとサーバーの双方で、データの受け渡しをするときに行われる。CORBAでは、すべてのデータは、バイト列に符号化され、上述のように符号化するデータの型によってAlignmentが予め決められている。また、データの符号化は、通常、符号化するコンピュータ上のデータ形式で行われるために、メッセージの送受信時には、ヘッダー等に符号化したときのendian情報が付加される。

データの復号化(unmarshaling)

データの復号化は、上述のバイト列で送られてきたデータを、元の形に復元することである。送られてきたデータは、通常、送信元のデータ形式で符号化されているために、ヘッダー等に付加された endianフラグに基づき復号化が行われる。

GIOPとIIOPについて
RtORBの開発メモ
GIOPメッセージについて