3. Presentation Language (表現言語)
この文書は, 外部表現におけるデータのフォーマットを扱います。以下の非常に基本的でやや簡略的に定義されたプレゼンテーション構文が使用されます。
3.1 Basic Block Size (基本ブロックサイズ)
すべてのデータ項目の表現は明示的に指定されます。基本データブロックサイズは1バイト (つまり8ビット) です。複数バイトのデータ項目は, 左から右へ, 上から下へのバイトの連結です。バイトストリームから, 複数バイトの項目 (以下の例では数値) は (C記法を使用して) 次のように形成されます:
value = (byte[0] << 8*(n-1)) | (byte[1] << 8*(n-2)) |
... | byte[n-1];
複数バイト値のこのバイト順序は, 一般的なネットワークバイトオーダーまたはビッグエンディアン形式です。
3.2 Miscellaneous (その他)
コメントは /* で始まり, */ で終わります。
オプションのコンポーネントは, [[ ]] (二重括弧) で囲むことで示されます。
解釈されないデータを含む単一バイトエンティティは opaque 型です。
既存の型 T の型エイリアス T' は次のように定義されます:
T T';
3.3 Numbers (数値)
基本的な数値データ型は符号なしバイト (uint8) です。すべての大きな数値データ型は, セクション3.1で説明されているように連結された固定長のバイト列から形成され, これも符号なしです。以下の数値型が事前定義されています:
uint8 uint16[2];
uint8 uint24[3];
uint8 uint32[4];
uint8 uint64[8];
ここおよび仕様の他の場所のすべての値は, ネットワークバイト (ビッグエンディアン) 順序で送信されます。16進バイト 01 02 03 04 で表される uint32 は, 10進値 16909060 と同等です。
3.4 Vectors (ベクトル)
ベクトル (一次元配列) は, 同質なデータ要素のストリームです。ベクトルのサイズは, ドキュメント時に指定することも, 実行時まで未指定のままにすることもできます。どちらの場合も, 長さはベクトル内の要素数ではなく, バイト数を宣言します。型 T の固定長ベクトルである新しい型 T' を指定する構文は次のとおりです:
T T'[n];
ここで, T' はデータストリームで n バイトを占有し, n は T のサイズの倍数です。ベクトルの長さは, エンコードされたストリームには含まれません。
次の例では, Datum はプロトコルが解釈しない3つの連続したバイトとして定義され, Data は3つの連続した Datum で, 合計9バイトを消費します。
opaque Datum[3]; /* 3つの解釈されないバイト */
Datum Data[9]; /* 3つの連続した3バイトベクトル */
可変長ベクトルは, <floor..ceiling> 表記を使用して, 合法的な長さのサブ範囲を包括的に指定することで定義されます。これらがエンコードされる場合, 実際の長さはバイトストリーム内のベクトルの内容の前に置かれます。長さは, ベクトルの指定された最大 (ceiling) 長さを保持するために必要なバイト数を消費する数値の形式になります。実際の長さフィールドがゼロの可変長ベクトルは空ベクトルと呼ばれます。
T T'<floor..ceiling>;
次の例では, mandatory は opaque 型の300から400バイトを含む必要があるベクトルです。これは決して空になることはできません。実際の長さフィールドは2バイトを消費し, uint16 で, 値400を表すのに十分です (セクション3.3参照)。同様に, longer は最大800バイトのデータ, または400の uint16 要素を表すことができ, 空であってもかまいません。そのエンコーディングには, ベクトルの前に付加された2バイトの実際の長さフィールドが含まれます。エンコードされたベクトルの長さは, 単一要素の長さの偶数倍でなければなりません (たとえば, uint16 の17バイトベクトルは不正です)。
opaque mandatory<300..400>;
/* 長さフィールドは2バイト, 空にはできない */
uint16 longer<0..800>;
/* 0から400の16ビット符号なし整数 */
3.5 Enumerateds (列挙型)
enum と呼ばれる追加のスパースデータ型が利用可能です。各定義は異なる型です。同じ型の列挙のみが割り当てまたは比較できます。次の例で示されているように, 列挙のすべての要素には値を割り当てる必要があります。列挙の要素は順序付けられていないため, 任意の順序で任意の一意の値を割り当てることができます。
enum { e1(v1), e2(v2), ... , en(vn) [[, (n)]] } Te;
プロトコルへの将来の拡張または追加により, 新しい値が定義される可能性があります。フィールドの定義に別段の記載がない限り, 実装は不明な値を解析して無視できる必要があります。
列挙は, バイトストリームで, その最大定義序数値が占有するのと同じだけのスペースを占有します。次の定義により, Color 型のフィールドを運ぶために1バイトが使用されます:
enum { red(3), blue(5), white(7) } Color;
オプションで, 関連するタグなしで値を指定して, 余分な要素を定義せずに幅定義を強制することができます。
次の例では, Taste はデータストリームで2バイトを消費しますが, プロトコルの現在のバージョンでは値1, 2, または4のみを想定できます。
enum { sweet(1), sour(2), bitter(4), (32000) } Taste;
列挙の要素の名前は, 定義された型内でスコープされます。最初の例では, 列挙の2番目の要素への完全修飾参照は Color.blue になります。割り当てのターゲットが適切に指定されている場合, そのような修飾は必要ありません。
Color color = Color.blue; /* 過度に指定されているが合法 */
Color color = blue; /* 正しい, 型は暗黙的 */
要素の名前は一意である必要はありません。ただし, 要素間の数値は一意でなければなりません。
enum { low(1), medium(2), high(2) } Priority; /* 間違い */
外部表現に変換されない列挙の場合, 数値情報は省略できます。
enum { low, medium, high } Priority;
3.6 Constructed Types (構築型)
構造体型は, 便宜上プリミティブ型から構築できます。各仕様は新しい一意の型を宣言します。定義の構文はCの構文に似ています:
struct {
T1 f1;
T2 f2;
...
Tn fn;
} T;
標準ベクトル構文を使用して, 固定長および可変長ベクトルフィールドが許可されます。バリアントの例 (セクション3.8) の構造体 V1 と V2 はこれを示しています。
構造体内のフィールドは, 列挙で利用可能な構文とよく似た構文を使用して, 型の名前を使用して修飾できます。たとえば, T.f2 は前の宣言の2番目のフィールドを指します。
3.7 Constants (定数)
フィールドと変数には, 次のように = を使用して固定値を割り当てることができます:
struct {
T1 f1 = 8; /* T.f1 は常に8でなければならない */
T2 f2;
} T;
3.8 Variants (バリアント)
定義された構造体は, 環境内で利用可能ないくつかの知識に基づいてバリアントを持つことができます。セレクタは, 構造体が定義する可能なバリアントを定義する列挙型でなければなりません。バリアント構造体の各アームは, そのバリアントのフィールドの型とオプションのフィールドラベルを指定します。実行時にバリアントが選択されるメカニズムは, プレゼンテーション言語では規定されていません。
struct {
T1 f1;
T2 f2;
....
Tn fn;
select (E) {
case e1: Te1 [[fe1]];
case e2: Te2 [[fe2]];
....
case en: Ten [[fen]];
};
} Tv;
例:
enum { apple, orange, banana } VariantTag;
struct {
uint16 number;
opaque string<0..10>; /* 可変長 */
} V1;
struct {
uint32 number;
opaque string[10]; /* 固定長 */
} V2;
struct {
VariantTag type;
select (VariantRecord.type) {
case apple: V1;
case orange:
case banana: V2;
};
} VariantRecord;