Lua, имея дело с потоками байтов, отличными от ascii, смена байтов - PullRequest
4 голосов
/ 09 марта 2011

Необходимо кодировать и декодировать поток байтов (возможно, содержащий символы не ascii), из / в uint16, uint32, uint64 (их типичное значение C / C ++), заботясь о порядке байтов.Каков эффективный и, надеюсь, кроссплатформенный способ сделать это в Lua?

Моя целевая арка - 64-битная x86_64, но я хотел бы сохранить ее переносимой (если это не будет стоить мне производительности)front).

например,

декодировать (скажем, в настоящее время в строке Lua) - 0x00, 0x1d, 0xff, 0x23, 0x44, 0x32 (little-endian) as - uint16: (0x1d00) =7424 uint32: (0x324423ff) = 843326463

Было бы замечательно, если бы кто-то мог объяснить с примером.

Ответы [ 3 ]

6 голосов
/ 09 марта 2011

для преобразования байтов в int (заботясь о порядке байтов на уровне байтов и подписи):

function bytes_to_int(str,endian,signed) -- use length of string to determine 8,16,32,64 bits
    local t={str:byte(1,-1)}
    if endian=="big" then --reverse bytes
        local tt={}
        for k=1,#t do
            tt[#t-k+1]=t[k]
        end
        t=tt
    end
    local n=0
    for k=1,#t do
        n=n+t[k]*2^((k-1)*8)
    end
    if signed then
        n = (n > 2^(#t*8-1) -1) and (n - 2^(#t*8)) or n -- if last bit set, negative.
    end
    return n
end

И пока мы находимся в другом направлении:

function int_to_bytes(num,endian,signed)
    if num<0 and not signed then num=-num print"warning, dropping sign from number converting to unsigned" end
    local res={}
    local n = math.ceil(select(2,math.frexp(num))/8) -- number of bytes to be used.
    if signed and num < 0 then
        num = num + 2^n
    end
    for k=n,1,-1 do -- 256 = 2^8 bits per char.
        local mul=2^(8*(k-1))
        res[k]=math.floor(num/mul)
        num=num-res[k]*mul
    end
    assert(num==0)
    if endian == "big" then
        local t={}
        for k=1,n do
            t[k]=res[n-k+1]
        end
        res=t
    end
    return string.char(unpack(res))
end

Любые замечания приветствуются, они проверены, но не слишком тщательно ...

4 голосов
/ 09 марта 2011

Взгляните на библиотеки struct и lpack .

В этом примере я использую struct.unpack для декодирования строки Lua в два целых числа с принудительным кодированием с прямым порядком байтов:

require 'struct'
-- convert character codes to a Lua string - this may come from your source
local str = string.char(0x00, 0x1d, 0xff, 0x23, 0x44, 0x32)
-- format string: < = little endian, In = unsigned int (n bytes)
local u16, u32 = struct.unpack('<I2I4', str)
print(u16, u32) --> 7424    843326463
0 голосов
/ 09 ноября 2016

мое предложение для функции "Int16ToByte" без проверки параметров:

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