Unexpected values ​​from bit manipulations

I am trying to create a dynamic byte array class for Lua 5.1 / 5.2. They are a very limited server-side Lua platform in a Flash game, they allow me to do nothing else while executing one source code.

Each byte is denoted by 8 bits inside a number that is inside a table of numbers.

I am temporarily testing it by trying to write a string ( 'abc'

), pass my bytes to a byte array, but when checking for the appropriate number of those bytes, its value is incorrect. It should be 0x636261

(because it a

is 0x61

), but as a result it is actually 6300000

.

local arr = bytearray:new('abc', 5);
print(arr[LK_Stack][1]);

      

I am using a maximum of 7 bytes from the stack number (56 bits). I got an adaptive bitwise AND function from this answer for testing over 32 bits. I am trying to use the library bit32

where possible.

This is temporary as I implement my byte read and write functions that work on a specific number from the byte array stack. The write function should return the stack number back to the changed state.

local Opr_readByte;
local Opr_writeByte;

if _16 then
    -- ...
else
    function Opr_readByte(n, bit)
        if bit == 48 then
            local add = band(n, 4) > 0xB;
            return floor(n / (add and 0x1000000000001 or 0x1000000000000));
        end
        if bit == 40 then return band(floor(n / 0x10000000000), 0xFF); end
        if bit == 32 then return band(floor(n / 0x100000000), 0xFF); end
        if bit == 24 then return band(floor(n / 0x100000000), 0xFF); end
        if bit == 16 then return band(rshift(n, 16), 0xFF); end
        if bit == 8 then  return band(rshift(n, 8), 0xFF); end
        return                   band(n, 0xFF);
    end

    function Opr_writeByte(n, bit, val)
        if bit == 48 then return (val * 0x1000000000000) + Opr_band56(n,   0xFFFFFFFFFFFF); end
        if bit == 40 then return (val * 0x10000000000)   + Opr_band56(n, 0xFF00FFFFFFFFFF); end
        if bit == 32 then return (val * 0x100000000)     + Opr_band56(n, 0xFFFF00FFFFFFFF); end
        if bit == 24 then return (val * 0x1000000)       + Opr_band56(n, 0xFFFFFF00FFFFFF); end
        if bit == 16 then return (val * 0x10000)         + Opr_band56(n, 0xFFFFFFFF00FFFF); end
        if bit == 8  then return (val * 0x100)           + Opr_band56(n, 0xFFFFFFFFFF00FF); end
        return                    val                    + Opr_band56(n, 0xFFFFFFFFFFFF00);
    end
end

      

And this is my complete current code.

do
    --[=[ pre-locals BEGIN ]=]

    local band         = bit32.band;
    local lshift       = bit32.lshift;
    local rshift       = bit32.rshift;
    local floor        = math.floor;
    local min          = math.min;
    local byte         = string.byte;
    local getmetatable = getmetatable;
    local setmetatable = setmetatable;
    local tonumber     = tonumber;
    local type         = type;

    local BIT5 = (0x7FFFFFFF + 1) == 0x7FFFFFFF and 16 or 48;
    local _16 = BIT5 == 16;
    local BYTE5 = _16 and 4 or 7;

    --[=[ pre-locals END ]=]

    --[=[ Tracker BEGIN ]=]

    --[=[
     * *****
     * Offset indices consist of [[number index]] and [[bit index]].
     * *****]=]

    local function Tracker_backward(x, y)
        if y <= 0 then return x - 1, BIT5 end
        return x, y - 8;
    end

    local function Tracker_forward(x, y)
        if y >= BIT5 then return x + 1, 0 end
        return x, y + 8;
    end

    local function Tracker_track(x, y, yx, yy)
        while y < x do yx, yy = Tracker_forward(yx, yy); y = y + 1; end
        while y > x do yx, yy = Tracker_backward(yx, yy); y = y - 1; end
        return yx, yy;
    end

    local function Tracker_optimalIndexFor(target, x, xx, xy, y, yx, yy)
        local zx = target > x and target - x or x - target;
        local zy = target > y and target - y or y - target;
        local optimal = min(zx, zy, target);
        if optimal == zx then return xx, xy; end
        if optimal == zy then return yx, yy; end
        return 1, 0;
    end

    --[=[ Tracker END ]=]

    --[=[ Opr BEGIN ]=]

    local Opr_readByte
        , Opr_writeByte;

    if _16 then
        function Opr_readByte(n, bit)
            if bit == 16 then return rshift(n, 16); end
            if bit == 8 then return band(rshift(n, 8), 0xFF); end
            return band(n, 0xFF);
        end

        function Opr_writeByte(n, bit, val)
            if bit == 16 then return lshift(val, 16) + band(n, 0xFFFF); end
            if bit == 8 then return lshift(val, 8) + band(n, 0xFF00FF); end
            return val + band(n, 0xFFFF00);
        end
    else
        local function Opr_band56(x, y)
            local xl = x % 0x10000000000;
            local yl = y % 0x10000000000;
            local xh = (x - xl) / 0x10000000000;
            local yh = (y - yl) / 0x10000000000;
            return band(xh, yh) * 0x10000000000 + band(xl, yl);
        end

        function Opr_readByte(n, bit)
            if bit == 48 then
                local add = band(n, 4) > 0xB;
                return floor(n / (add and 0x1000000000001 or 0x1000000000000));
            end
            if bit == 40 then return band(floor(n / 0x10000000000), 0xFF); end
            if bit == 32 then return band(floor(n / 0x100000000), 0xFF); end
            if bit == 24 then return band(floor(n / 0x100000000), 0xFF); end
            if bit == 16 then return band(rshift(n, 16), 0xFF); end
            if bit == 8 then  return band(rshift(n, 8), 0xFF); end
            return                   band(n, 0xFF);
        end

        function Opr_writeByte(n, bit, val)
            if bit == 48 then return (val * 0x1000000000000) + Opr_band56(n,   0xFFFFFFFFFFFF); end
            if bit == 40 then return (val * 0x10000000000)   + Opr_band56(n, 0xFF00FFFFFFFFFF); end
            if bit == 32 then return (val * 0x100000000)     + Opr_band56(n, 0xFFFF00FFFFFFFF); end
            if bit == 24 then return (val * 0x1000000)       + Opr_band56(n, 0xFFFFFF00FFFFFF); end
            if bit == 16 then return (val * 0x10000)         + Opr_band56(n, 0xFFFFFFFF00FFFF); end
            if bit == 8  then return (val * 0x100)           + Opr_band56(n, 0xFFFFFFFFFF00FF); end
            return                    val                    + Opr_band56(n, 0xFFFFFFFFFFFF00);
        end
    end

    --[=[ Opr END ]=]

    local LK_Stack          = false;
    local LK_TrackX         = true;
    local LK_TrackXX        = 0;
    local LK_TrackXY        = 1;
    local LK_Length         = 2;
    local LK_Use_Le         = 3;
    local LK_OfsLength      = 4;

    local function resize(stack, x, y)
        if x < y then
            for i = x + 1, y do stack[i] = nil; end
            return;
        end
        for i = y + 1, x do stack[i] = 0; end
    end

    local t = {};

    do
        local metatable = {};
        local prototype = {};

        local function bytearray(_, arg, n)
            local stack = {};

            local arr = setmetatable({
                [ LK_Stack ] = stack,
                [ LK_TrackX ] = 1,
                [ LK_TrackXX] = 1,
                [ LK_TrackXY ] = 0,
                [ LK_Use_Le ] = true
            }, metatable);

            local _type = type(arg);
            local isNum = _type == 'number';
            local blen = not isNum and #arg;
            local len = tonumber(isNum and arg or (n or blen)) or 0;

            local ld = floor((len / BYTE5) + 1);

            arr[LK_Length] = len;
            resize(stack, ld, 0);

            arr[LK_OfsLength] = ld;

            if not isNum then
                blen = blen % (len + 1);
                if _type == 'string' then arg = { byte(arg, 1, blen) }; end

                local n, x, y = 0, 1, 0;

                for i = 1, blen do
                    n = Opr_writeByte(n, y, arg[i]);
                    local xsav = x;
                    x, y = Tracker_forward(x, y);
                    if x ~= xsav then stack[xsav] = n; n = 0; end
                end

                stack[x] = n;
            end
            return arr;
        end

        local prototype = {};

        function prototype:getlength()
            return self[LK_Length];
        end

        function prototype:setlength(len)
            resize(self[LK_Stack], len, self[LK_Length]);
            self[LK_Length] = len;
        end

        metatable.__index = prototype;
        t.new = bytearray;
    end

    bytearray = t;

    local arr = bytearray:new('abc', 5);
    print(arr[LK_Stack][1]);
end

      

+3


source to share





All Articles