位操作的意外值

时间:2017-05-22 14:55:05

标签: lua

我正在尝试为Lua 5.1 / 5.2构建动态字节数组类。它是Flash游戏中非常有限的Lua服务器平台,它们允许我在执行单个源代码时不做任何其他事情。

每个字节在数字表内的数字内用8位表示。

我通过尝试写一个字符串('abc')暂时测试它,将其字节传递给字节数组,但是当检查这些字节的相应数量时,它的值是错误的。它应该是0x636261(因为a0x61),但实际上会产生6300000

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

我最多使用堆栈号(56位)的7个字节。我从this回答得到了一个自适应按位AND函数,用于检查32位。我尝试尽可能使用bit32库。

这暂时是我如何实现字节读取和写入函数,这些函数对字节数组的堆栈中的特定数字进行操作。写入功能必须以更改状态返回堆栈编号。

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

这是我目前的完整代码。

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

0 个答案:

没有答案