En javascript (sin usar el nodo), me enfrento a resultados diferentes cuando codifico CBOR usando la biblioteca ( https://github.com/paroga/cbor-js ) y cuando uso CBOR en línea ( https://cbor.me/ ). Tenga en cuenta que incluso usando una biblioteca CBOR más reciente, el resultado es idéntico.
Por ejemplo, establecer un objeto como:
const initial = { 1: "John", "-2": 456 };La codificación usando CBOR en línea da: a201644a6f686e622d321901c8. Los detalles son:
A2 # map(2) 01 # unsigned(1) 64 # text(4) 4A6F686E # "John" 62 # text(2) 2D32 # "-2" 19 01C8 # unsigned(456)Ahora, la codificación usando la biblioteca CBOR en javascript da un resultado diferente: a26131644a6f686e622d321901c8
Al decodificar este hexadecimal anterior en CBOR en línea, obtuve: {"1": "John", "-2": 456}. El resultado es casi idéntico al de la constante 'inicial' excepto que la clave 1 ahora aparece entre comillas (").
CBOR en línea reformatea mi valor hexadecimal a una vista más 'legible':
A2 # map(2) 61 # text(1) 31 # "1" 64 # text(4) 4A6F686E # "John" 62 # text(2) 2D32 # "-2" 19 01C8 # unsigned(456)Vea a continuación mi código Javascript:
//convert an array of bytes (as 8 bits) to string of Hex. ensure that Hex value are not return with 1 digit but 2 digits. ie '01' instead of '1' function toHexString(byteArray) { var s = ''; byteArray.forEach(function(byte) { s += ('0' + (byte & 0xFF).toString(16)).slice(-2); }); return s; } const initial = { 1: "John", "-2": 456 }; var encoded = CBOR.encode(initial); var encodedHex = toHexString(Array.from(new Uint8Array(encoded))); console.log ( encodedHex );Podría reemplazar manualmente valores hexadecimales específicos como:
'61 31 64' reemplazado por '01 64'
Pero no te apetezca hacerlo ya que la lista podría ser importante para cubrir todas las opciones posibles.
¿Alguien tiene una solución porque necesito que mi resultado sea 'a201644a6f686e622d321901c8' y no 'a26131644a6f686e622d321901c8'?
La especificación CBOR, sección 5.6 dice:
En las aplicaciones que necesitan interactuar con aplicaciones basadas en JSON, la conversión se simplifica al limitar las claves a cadenas de texto únicamente.
Y, de hecho, el paquete cbor-js usa el método Object.keys aquí , que devuelve todas las claves como cadenas. Javascript no distingue entre números y sus valores de cadena y trata {'1':1, 1:2} como {'1':2} (mientras que cbor.me trata esto como un mapa con dos entradas).
cbor-js modificado Su ejemplo sugiere que desea que CBOR trate las claves numéricas no negativas como numéricas. Esto se puede lograr con el siguiente parche en el código fuente cbor-js :
diff --git a/cbor.js b/cbor.js --- a/cbor.js +++ b/cbor.js @@ -164,7 +164,10 @@ function encode(value) { writeTypeAndLength(5, length); for (i = 0; i < length; ++i) { var key = keys[i]; - encodeItem(key); + if (isNaN(key) || Number(key) < 0) + encodeItem(key); + else + encodeItem(Number(key)); encodeItem(value[key]); } }Con este cambio, Node.js me da
> Buffer.from(cbor.encode({1:'John','-2':456})).toString('hex')) 'a201644a6f686e622d321901c8' O incluso podría tratar las teclas numéricas negativas como numéricas omitiendo el || Number(key) < 0 en el parche de arriba. Esto da
> Buffer.from(cbor.encode({1:'John','-2':456})).toString('hex')) 'a201644a6f686e211901c8' A2 # map(2) 01 # unsigned(1) 64 # text(4) 4A6F686E # "John" 21 # negative(1) 19 01C8 # unsigned(456)cbor A diferencia cbor-js , el paquete cbor le permite codificar un Map de Javascript, que distingue las claves numéricas de las de cadena:
> Buffer.from(cbor.encode(new Map().set(1,'John').set(-2,456))).toString('hex') 'a201644a6f686e211901c8'