Passa al contenuto principale

Appendice C. Pseudocodice

La buona formazione di un elemento CBOR può essere verificata tramite lo pseudocodice nella Figura 1. I dati sono ben formati se e solo se:

  • lo pseudocodice non "fallisce";

  • dopo l'esecuzione dello pseudocodice, non rimangono byte in input (tranne che nelle applicazioni in streaming)

Lo pseudocodice ha i seguenti prerequisiti:

  • take(n) legge n byte dai dati in input e li restituisce come stringa di byte. Se non sono più disponibili n byte, take(n) fallisce.

  • uint() converte una stringa di byte in un intero senza segno interpretando la stringa di byte in ordine di byte di rete.

  • L'aritmetica funziona come in C.

  • Tutte le variabili sono interi senza segno di intervallo sufficiente.

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
}

Figura 1: Pseudocodice per il controllo di buona formazione

Si noti che la complessità rimanente di un decoder CBOR completo riguarda la presentazione all'applicazione, in una forma appropriata, dei dati che sono stati analizzati.

I tipi principali 0 e 1 sono progettati in modo tale da poter essere codificati in C a partire da un intero con segno senza dover effettuare effettivamente un if-then-else per positivo/negativo (Figura 2). Questo sfrutta il fatto che (-1-n), la trasformazione per il tipo principale 1, è uguale a ~n (complemento bit a bit) nell'aritmetica senza segno del C; ~n può quindi essere espresso come (-1)^n per il caso negativo, mentre 0^n lascia n invariato per il caso non negativo. Il segno di un numero può essere convertito in -1 per i negativi e 0 per i non negativi (0 o positivi) spostando aritmeticamente il numero di un bit in meno rispetto alla lunghezza in bit del numero (ad esempio, di 63 per i numeri a 64 bit).

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
...

Figura 2: Pseudocodice per la codifica di un intero con segno