6
votes

Lua, traitant de flux d'octets non ASCII, change Byeorder

besoin d'encoder et de décoder l'octet-flux (contenant des caractères non ascii éventuellement), de / dans UINT16, UINT32, UINT64 (leur signification typique C / C ++), prenant soin de l'endansion. Qu'est-ce qu'un moyen de plate-forme inter-plate-forme efficace et d'espoir à faire une telle chose à Lua?

My Target Arch est 64 bits X86_64, mais je voudrais le garder portable (si cela ne m'a pas coûté sur le front de performance).

E.g.

décodage (dire actuellement dans une chaîne Lua) - 0x00, 0x1d, 0xFF, 0x23, 0x44, 0x32 (Petite Endian) comme - uint16: (0x1d00) = 7424 uint32: (0x324423ff) = 843326463

serait formidable si quelqu'un peut expliquer avec un exemple.


0 commentaires

3 Réponses :


7
votes

pour la conversion des octets à l'INT (en prenant soin de l'endansement au niveau des octets et de la signature): xxx

et pendant que nous sommes aussi l'autre direction: < PRE> XXX

Toutes les remarques sont les bienvenues, il est testé, mais pas trop soigneusement ...


6 commentaires

Très pédagogique. Il me semble avoir appris une charge de Lua à travers votre exemple illustratif, sérieusement.


En fonction de la fonction bytes_to_int, la ligne n = (n> 2 ^ (# t-1) -1) et (n-2 ^ # t) ou n je pense que cela devrait être # t * 8 à la place ou #t. Est le nombre de bits que vous voulez, pas d'octets.


Il semble que tu as raison! Merci pour la suggestion, je l'ai corrigé dans ma réponse.


@jpjacobs - merci beaucoup. Fonction INT_TO_BYTES a également besoin de correction lors de la gestion des numéros signés: si signé et num <0 puis , la ligne suivante 2 ^ n doit être num = num + 2 ^ ( 8 * n)


int_to_bytes ne manipule pas toujours les numéros signés correctement (lorsque exp de frexp est multiple de 8). Par exemple, -32769 doit être 0xFF 0XFF 0xFF 0x00 0x00 , mais la fonction telle qu'elle est renvoie 0x7f 0xFF .


De plus, pour les chiffres dépassant 16 bits, int_to_bytes ne renvoie pas nécessairement un nombre même d'octets, de sorte que le résultat pour les numéros signés ne peut pas être portable à d'autres applications (par exemple, pour un numéro signé dans Big Endian retour dans 3 octets, le premier octet est supposé être 0x00 au lieu de 0xFF). Ma solution pour les deux problèmes manque d'élégance concise du code ci-dessus ... peut-être qu'un véritable programmeur peut aider!



6
votes

Jetez un oeil à la struct et LPACK bibliothèques.

Dans cet exemple, j'utilise le structure.unpack Pour décoder une chaîne Lua en deux entiers avec codage de petite endan forcé: xxx


4 commentaires

Semble très simple et élégant, mais je ne semble pas avoir un module d'extension «Struct». Luarocks échoue à bâtir / l'installer avec une erreur. Va essayer de résoudre ça et d'essayer ceci. Merci!


@ Michal-Kottman, essayé le code après avoir fixé des Luarocks et installer 'Struct' mais pour les berceaux Lua sur le deuxième paramètre à déballer (c'est-à-dire STR) ne pas être une chaîne. Pour déboguer, j'ai essayé ce petit code (qui ne berce pas, mais ne semble pas fonctionner comme prévu non plus - > str = string.char (0x00, 0xff) > local u16 = struct.unpack (' > print (u16) nil


@ Michal-Kottman, désolé! corrigé ça. Un léger changement était nécessaire à Lua 5.1 (au moins sur mon système). Il suffit de faire un: struct = nécessite ("struct")


Étrange, j'ai testé le code présenté comme à Lua 5.1, et cela a fonctionné correctement (peut-être que j'ai eu une version plus ancienne de struct ), mais je suis content que cela fonctionne pour vous maintenant, c'est un très Outil pratique pour les données binaires ...



1
votes

Ma suggestion pour un «INT16TOBYTE» -Fonction sans vérification des paramètres:

function Int16ToBytes(num, endian)
  if num < 0 then 
      num = num & 0xFFFF
  end

  highByte = (num & 0xFF00) >> 8
  lowByte  = num & 0xFF

  if endian == "little" then
      lowByte, highByte = highByte, lowByte
  end

  return string.char(highByte,lowByte)
end


0 commentaires