-- -- Created by: Cyril. -- Created at: 15/6/20 下午2:05 -- Email: houshoushuai@gmail.com -- -- Library for reading low level data local assert = assert local unpack = unpack local floor = math.floor local strbyte , strchar = string.byte , string.char local le_uint_to_num = function ( s , i , j ) i , j = i or 1 , j or #s local b = { strbyte ( s , i , j ) } local n = 0 for i=#b , 1 , -1 do n = n*2^8 + b [ i ] end return n end local le_int_to_num = function ( s , i , j ) i , j = i or 1 , j or #s local n = le_uint_to_num ( s , i , j ) local overflow = 2^(8*(j-i) + 7) if n > 2^overflow then n = - ( n % 2^overflow ) end return n end local num_to_le_uint = function ( n , bytes ) bytes = bytes or 4 local b = { } for i=1 , bytes do b [ i ] , n = n % 2^8 , floor ( n / 2^8 ) end return strchar ( unpack ( b ) ) end local num_to_le_int = function ( n , bytes ) bytes = bytes or 4 if n < 0 then -- Converted to unsigned. n = 2^(8*bytes) + n end return num_to_le_uint ( n , bytes ) end local be_uint_to_num = function ( s , i , j ) i , j = i or 1 , j or #s local b = { strbyte ( s , i , j ) } local n = 0 for i=1 , #b do n = n*2^8 + b [ i ] end return n end local num_to_be_uint = function ( n , bytes ) bytes = bytes or 4 local b = { } for i=bytes , 1 , -1 do b [ i ] , n = n % 2^8 , floor ( n / 2^8 ) end assert ( n == 0 ) return strchar ( unpack ( b ) ) end -- Returns (as a number); bits i to j (indexed from 0) local extract_bits = function ( s , i , j ) j = j or i local i_byte = floor ( i / 8 ) + 1 local j_byte = floor ( j / 8 ) + 1 local n = be_uint_to_num ( s , i_byte , j_byte ) n = n % 2^( j_byte*8 - i ) n = floor ( n / 2^( (-(j+1) ) % 8 ) ) return n end -- Look at ith bit in given string (indexed from 0) -- Returns boolean local le_bpeek = function ( s , bitnum ) local byte = floor ( bitnum / 8 ) + 1 local bit = bitnum % 8 local char = strbyte ( s , byte ) return floor ( ( char % 2^(bit+1) ) / 2^bit ) == 1 end -- Test with: --local sum = 0 for i=0,31 do v = le_bpeek ( num_to_le_uint ( N , 4 ) , i ) sum=sum + ( v and 1 or 0 )*2^i end assert ( sum == N ) local be_bpeek = function ( s , bitnum ) local byte = floor ( bitnum / 8 ) + 1 local bit = 7-bitnum % 8 local char = strbyte ( s , byte ) return floor ( ( char % 2^(bit+1) ) / 2^bit ) == 1 end -- Test with: --local sum = 0 for i=0,31 do v = be_bpeek ( num_to_be_uint ( N , 4 ) , i ) sum=sum + ( v and 1 or 0 )*2^(31-i) end assert ( sum == N ) local hasffi , ffi = pcall ( require , "ffi" ) local to_double , from_double do local s , e , d if hasffi then d = ffi.new ( "double[1]" ) else -- Can't use with to_double as we can't strip debug info :( d = string.dump ( loadstring ( [[return 523123.123145345]] ) ) s , e = d:find ( "\3\54\208\25\126\204\237\31\65" ) s = d:sub ( 1 , s ) e = d:sub ( e+1 , -1 ) end function to_double ( n ) if hasffi then d [ 0 ] = n return ffi.string ( d , 8 ) else -- Should be the 8 bytes following the second \3 (LUA_TSTRING == '\3') local str = string.dump ( loadstring ( [[return ]] .. n ) ) local loc , en , mat = str:find ( "\3(........)" , str:find ( "\3" ) + 1 ) return mat end end function from_double ( str ) assert ( #str == 8 ) if hasffi then ffi.copy ( d , str , 8 ) return d [ 0 ] else str = s .. str .. e return loadstring ( str ) ( ) end end end return { le_uint_to_num = le_uint_to_num ; le_int_to_num = le_int_to_num ; num_to_le_uint = num_to_le_uint ; num_to_le_int = num_to_le_int ; be_uint_to_num = be_uint_to_num ; num_to_be_uint = num_to_be_uint ; extract_bits = extract_bits ; le_bpeek = le_bpeek ; be_bpeek = be_bpeek ; to_double = to_double ; from_double = from_double ; }