Appendix C. Pseudocode
La bonne formation d'un élément CBOR peut être vérifiée par le pseudocode de la Figure 1. Les données sont bien formées si et seulement si :
-
le pseudocode n'« échoue » pas ;
-
après l'exécution du pseudocode, il ne reste aucun octet dans l'entrée (sauf dans les applications en flux continu)
Le pseudocode a les prérequis suivants :
-
take(n) lit n octets des données d'entrée et les renvoie sous forme de chaîne d'octets. Si n octets ne sont plus disponibles, take(n) échoue.
-
uint() convertit une chaîne d'octets en un entier non signé en interprétant la chaîne d'octets dans l'ordre des octets du réseau.
-
L'arithmétique fonctionne comme en C.
-
Toutes les variables sont des entiers non signés de plage suffisante.
well_formed (breakable = false) {
// process initial bytes
ib = uint(take(1));
mt = ib >> 5;
val = ai = ib & 0x1f;
switch (ai) {
case 24: val = uint(take(1)); break;
case 25: val = uint(take(2)); break;
case 26: val = uint(take(4)); break;
case 27: val = uint(take(8)); break;
case 28: case 29: case 30: fail();
case 31:
return well_formed_indefinite(mt, breakable);
}
// process content
switch (mt) {
// case 0, 1, 7 do not have content; just use val
case 2: case 3: take(val); break; // bytes/UTF-8
case 4: for (i = 0; i < val; i++) well_formed(); break;
case 5: for (i = 0; i < val*2; i++) well_formed(); break;
case 6: well_formed(); break; // 1 embedded data item
}
return mt; // finite data item
}
well_formed_indefinite(mt, breakable) {
switch (mt) {
case 2: case 3:
while ((it = well_formed(true)) != -1)
if (it != mt) // need finite embedded
fail(); // of same type
break;
case 4: while (well_formed(true) != -1); break;
case 5: while (well_formed(true) != -1) well_formed(); break;
case 7:
if (breakable)
return -1; // signal break out
else fail(); // no enclosing indefinite
default: fail(); // wrong mt
}
return 0; // no break out
}
Figure 1 : Pseudocode pour la vérification de bonne formation
Notons que la complexité restante d'un décodeur CBOR complet concerne la présentation à l'application, sous une forme appropriée, des données qui ont été analysées.
Les types majeurs 0 et 1 sont conçus de telle manière qu'ils peuvent être encodés en C à partir d'un entier signé sans avoir réellement à faire un if-then-else pour positif/négatif (Figure 2). Cela utilise le fait que (-1-n), la transformation pour le type majeur 1, est la même que ~n (complément bit à bit) dans l'arithmétique non signée de C ; ~n peut alors être exprimé comme (-1)^n pour le cas négatif, tandis que 0^n laisse n inchangé pour les valeurs non négatives. Le signe d'un nombre peut être converti en -1 pour les valeurs négatives et 0 pour les valeurs non négatives (0 ou positives) en décalant arithmétiquement le nombre d'un bit de moins que la longueur en bits du nombre (par exemple, de 63 pour les nombres de 64 bits).
void encode_sint(int64_t n) {
uint64t ui = n >> 63; // extend sign to whole length
mt = ui & 0x20; // extract major type
ui ^= n; // complement negatives
if (ui < 24)
*p++ = mt + ui;
else if (ui < 256) {
*p++ = mt + 24;
*p++ = ui;
} else
...
Figure 2 : Pseudocode pour l'encodage d'un entier signé