fix: add lua 5.0 compatibility shims
This commit is contained in:
@@ -19,6 +19,111 @@ if not math.mod then
|
||||
end
|
||||
end
|
||||
|
||||
-- Shim for Lua 5.0 where the bit library may be missing.
|
||||
-- Questie uses band/bor/bxor/lshift/rshift in core runtime code, so we provide
|
||||
-- a pure-Lua fallback when the host does not expose one.
|
||||
if not bit or not bit.band or not bit.bor or not bit.bxor or not bit.lshift or not bit.rshift then
|
||||
local bitlib = bit or {}
|
||||
local U32 = 4294967296
|
||||
local U32_MAX = 4294967295
|
||||
local floor = math.floor
|
||||
local mod = math.mod or function(a, b)
|
||||
return a - floor(a / b) * b
|
||||
end
|
||||
|
||||
local function normalizeU32(n)
|
||||
n = tonumber(n) or 0
|
||||
n = floor(n)
|
||||
if n < 0 then
|
||||
n = U32 + mod(n, U32)
|
||||
elseif n >= U32 then
|
||||
n = mod(n, U32)
|
||||
end
|
||||
return n
|
||||
end
|
||||
|
||||
local function bitAt(n, mask)
|
||||
return mod(floor(n / mask), 2)
|
||||
end
|
||||
|
||||
local function band32(a, b)
|
||||
a = normalizeU32(a)
|
||||
b = normalizeU32(b)
|
||||
local result = 0
|
||||
local mask = 1
|
||||
for _ = 1, 32 do
|
||||
if bitAt(a, mask) == 1 and bitAt(b, mask) == 1 then
|
||||
result = result + mask
|
||||
end
|
||||
mask = mask * 2
|
||||
end
|
||||
return normalizeU32(result)
|
||||
end
|
||||
|
||||
local function bor32(a, b)
|
||||
a = normalizeU32(a)
|
||||
b = normalizeU32(b)
|
||||
local result = 0
|
||||
local mask = 1
|
||||
for _ = 1, 32 do
|
||||
if bitAt(a, mask) == 1 or bitAt(b, mask) == 1 then
|
||||
result = result + mask
|
||||
end
|
||||
mask = mask * 2
|
||||
end
|
||||
return normalizeU32(result)
|
||||
end
|
||||
|
||||
local function bxor32(a, b)
|
||||
a = normalizeU32(a)
|
||||
b = normalizeU32(b)
|
||||
local result = 0
|
||||
local mask = 1
|
||||
for _ = 1, 32 do
|
||||
if bitAt(a, mask) ~= bitAt(b, mask) then
|
||||
result = result + mask
|
||||
end
|
||||
mask = mask * 2
|
||||
end
|
||||
return normalizeU32(result)
|
||||
end
|
||||
|
||||
local function lshift32(a, disp)
|
||||
a = normalizeU32(a)
|
||||
disp = tonumber(disp) or 0
|
||||
if disp <= 0 then
|
||||
return normalizeU32(math.floor(a / (2 ^ (-disp))))
|
||||
elseif disp >= 32 then
|
||||
return 0
|
||||
end
|
||||
return normalizeU32(a * (2 ^ disp))
|
||||
end
|
||||
|
||||
local function rshift32(a, disp)
|
||||
a = normalizeU32(a)
|
||||
disp = tonumber(disp) or 0
|
||||
if disp <= 0 then
|
||||
return normalizeU32(a * (2 ^ (-disp)))
|
||||
elseif disp >= 32 then
|
||||
return 0
|
||||
end
|
||||
return normalizeU32(floor(a / (2 ^ disp)))
|
||||
end
|
||||
|
||||
local function bnot32(a)
|
||||
return normalizeU32(U32_MAX - normalizeU32(a))
|
||||
end
|
||||
|
||||
bitlib.band = bitlib.band or band32
|
||||
bitlib.bor = bitlib.bor or bor32
|
||||
bitlib.bxor = bitlib.bxor or bxor32
|
||||
bitlib.lshift = bitlib.lshift or lshift32
|
||||
bitlib.rshift = bitlib.rshift or rshift32
|
||||
bitlib.bnot = bitlib.bnot or bnot32
|
||||
bit = bitlib
|
||||
_G.bit = bitlib
|
||||
end
|
||||
|
||||
-- Shim for Lua 5.0 where string.match is missing.
|
||||
-- Supports up to 5 captures (sufficient for all Questie uses).
|
||||
if not string.match then
|
||||
@@ -57,6 +162,44 @@ if not select then
|
||||
end
|
||||
end
|
||||
|
||||
-- Shim for Lua 5.0 where strsplit is missing.
|
||||
if not strsplit then
|
||||
strsplit = function(separator, text, max)
|
||||
if text == nil then
|
||||
return nil
|
||||
end
|
||||
if separator == "" then
|
||||
return text
|
||||
end
|
||||
|
||||
local results = {}
|
||||
local resultCount = 0
|
||||
local startPos = 1
|
||||
local maxSplits = tonumber(max)
|
||||
|
||||
while true do
|
||||
if maxSplits and resultCount >= (maxSplits - 1) then
|
||||
resultCount = resultCount + 1
|
||||
results[resultCount] = string.sub(text, startPos)
|
||||
break
|
||||
end
|
||||
|
||||
local sepStart, sepEnd = string.find(text, separator, startPos, true)
|
||||
if not sepStart then
|
||||
resultCount = resultCount + 1
|
||||
results[resultCount] = string.sub(text, startPos)
|
||||
break
|
||||
end
|
||||
|
||||
resultCount = resultCount + 1
|
||||
results[resultCount] = string.sub(text, startPos, sepStart - 1)
|
||||
startPos = sepEnd + 1
|
||||
end
|
||||
|
||||
return unpack(results, 1, resultCount)
|
||||
end
|
||||
end
|
||||
|
||||
-- The only public class except for Questie
|
||||
---@class QuestieLoader
|
||||
QuestieLoader = QuestieLoader or {}
|
||||
|
||||
@@ -6,6 +6,8 @@ local QuestieSerializer = QuestieLoader:CreateModule("QuestieSerializer");
|
||||
---@type QuestieStreamLib
|
||||
local QuestieStreamLib = QuestieLoader:ImportModule("QuestieStreamLib");
|
||||
|
||||
local mod = math.mod
|
||||
|
||||
|
||||
function QuestieSerializer:Hash(value)
|
||||
if not value or type(value) ~= "string" or (string.len(value) <= 0) then
|
||||
@@ -70,14 +72,14 @@ local function floatBitsToInt(n)
|
||||
else
|
||||
expo = expo + 0x7E
|
||||
mant = floor((mant * 2.0 - 1.0) * ldexp(0.5, 24))
|
||||
return _pack(sign + floor(expo / 0x2), (expo % 0x2) * 0x80 + floor(mant / 0x10000), floor(mant / 0x100) % 0x100, mant % 0x100)
|
||||
return _pack(sign + floor(expo / 0x2), mod(expo, 0x2) * 0x80 + floor(mant / 0x10000), mod(floor(mant / 0x100), 0x100), mod(mant, 0x100))
|
||||
end
|
||||
end
|
||||
local function intBitsToFloat(int)
|
||||
local b1, b2, b3, b4 = _unpack(int)
|
||||
local sign = b1 > 0x7F
|
||||
local expo = (b1 % 0x80) * 0x2 + floor(b2 / 0x80)
|
||||
local mant = ((b2 % 0x80) * 0x100 + b3) * 0x100 + b4
|
||||
local expo = mod(b1, 0x80) * 0x2 + floor(b2 / 0x80)
|
||||
local mant = ((mod(b2, 0x80)) * 0x100 + b3) * 0x100 + b4
|
||||
if sign then
|
||||
sign = -1
|
||||
else
|
||||
|
||||
+25
-24
@@ -10,6 +10,7 @@ local unpack_limit = 4096 -- wow api limits unpack to somewhere between 7000-800
|
||||
local band = bit.band
|
||||
local lshift = bit.lshift
|
||||
local rshift = bit.rshift
|
||||
local mod = math.mod
|
||||
local stringchar = string.char
|
||||
local stringbyte = string.byte
|
||||
local stringsub = string.sub
|
||||
@@ -128,7 +129,7 @@ end
|
||||
function QuestieStreamLib:_writeByte(val)
|
||||
local p = self._pointer
|
||||
local chunkId = math.floor((p - 1) / 100000) + 1
|
||||
local localIdx = ((p - 1) % 100000) + 1
|
||||
local localIdx = mod(p - 1, 100000) + 1
|
||||
|
||||
if not self._bin[chunkId] then
|
||||
self._bin[chunkId] = {}
|
||||
@@ -152,7 +153,7 @@ function QuestieStreamLib:_readByte()
|
||||
return stringbyte(self._bin, p)
|
||||
else
|
||||
local chunkId = math.floor((p - 1) / 100000) + 1
|
||||
local localIdx = ((p - 1) % 100000) + 1
|
||||
local localIdx = mod(p - 1, 100000) + 1
|
||||
if self._bin[chunkId] then
|
||||
return stringbyte(self._bin[chunkId][localIdx] or "\0")
|
||||
end
|
||||
@@ -184,7 +185,7 @@ function QuestieStreamLib:_WriteByte_b89(e)
|
||||
self._level = level
|
||||
self:_writeByte(QSL_ltab[level])
|
||||
end
|
||||
local chr = (e % 86) + 33
|
||||
local chr = mod(e, 86) + 33
|
||||
if QSL_ttab[chr] then
|
||||
self:_writeByte(QSL_ttab[chr])
|
||||
else
|
||||
@@ -267,7 +268,7 @@ function QuestieStreamLib:_ReadInt12Pair_raw()
|
||||
local p = self._pointer
|
||||
self._pointer = p + 3
|
||||
local a,b,c = stringbyte(self._bin, p, p+2)
|
||||
local low4bit = a % 16
|
||||
local low4bit = mod(a, 16)
|
||||
return low4bit * 256 + b, (a - low4bit) * 16 + c
|
||||
end
|
||||
|
||||
@@ -372,8 +373,8 @@ end
|
||||
|
||||
function QuestieStreamLib:_WriteShort(val)
|
||||
--print("wshort: " .. val);
|
||||
self:WriteByte(rshift(val, 8) % 256);
|
||||
self:WriteByte(val % 256);
|
||||
self:WriteByte(mod(rshift(val, 8), 256));
|
||||
self:WriteByte(mod(val, 256));
|
||||
end
|
||||
|
||||
function QuestieStreamLib:_WriteShort_assert(val)
|
||||
@@ -384,10 +385,10 @@ function QuestieStreamLib:_WriteShort_assert(val)
|
||||
end
|
||||
|
||||
function QuestieStreamLib:_WriteInt(val)
|
||||
self:WriteByte(rshift(val, 24) % 256);
|
||||
self:WriteByte(rshift(val, 16) % 256);
|
||||
self:WriteByte(rshift(val, 8) % 256);
|
||||
self:WriteByte(val % 256);
|
||||
self:WriteByte(mod(rshift(val, 24), 256));
|
||||
self:WriteByte(mod(rshift(val, 16), 256));
|
||||
self:WriteByte(mod(rshift(val, 8), 256));
|
||||
self:WriteByte(mod(val, 256));
|
||||
end
|
||||
|
||||
function QuestieStreamLib:_WriteInt_assert(val)
|
||||
@@ -399,9 +400,9 @@ end
|
||||
|
||||
function QuestieStreamLib:_WriteInt24(val)
|
||||
--print("wi24: " .. val);
|
||||
self:WriteByte(rshift(val, 16) % 256);
|
||||
self:WriteByte(rshift(val, 8) % 256);
|
||||
self:WriteByte(val % 256);
|
||||
self:WriteByte(mod(rshift(val, 16), 256));
|
||||
self:WriteByte(mod(rshift(val, 8), 256));
|
||||
self:WriteByte(mod(val, 256));
|
||||
end
|
||||
|
||||
function QuestieStreamLib:_WriteInt24_assert(val)
|
||||
@@ -413,8 +414,8 @@ end
|
||||
|
||||
function QuestieStreamLib:_WriteInt12Pair(val1, val2)
|
||||
self:WriteByte(band(rshift(val1, 8), 15) + lshift(band(rshift(val2, 8), 15), 4))
|
||||
self:WriteByte(val1 % 256)
|
||||
self:WriteByte(val2 % 256)
|
||||
self:WriteByte(mod(val1, 256))
|
||||
self:WriteByte(mod(val2, 256))
|
||||
end
|
||||
|
||||
function QuestieStreamLib:_WriteInt12Pair_assert(val1, val2)
|
||||
@@ -430,14 +431,14 @@ function QuestieStreamLib:_WriteInt12Pair_assert(val1, val2)
|
||||
end
|
||||
|
||||
function QuestieStreamLib:_WriteLong(val)
|
||||
self:WriteByte(rshift(val, 56) % 256);
|
||||
self:WriteByte(rshift(val, 48) % 256);
|
||||
self:WriteByte(rshift(val, 40) % 256);
|
||||
self:WriteByte(rshift(val, 32) % 256);
|
||||
self:WriteByte(rshift(val, 24) % 256);
|
||||
self:WriteByte(rshift(val, 16) % 256);
|
||||
self:WriteByte(rshift(val, 8) % 256);
|
||||
self:WriteByte(val % 256);
|
||||
self:WriteByte(mod(rshift(val, 56), 256));
|
||||
self:WriteByte(mod(rshift(val, 48), 256));
|
||||
self:WriteByte(mod(rshift(val, 40), 256));
|
||||
self:WriteByte(mod(rshift(val, 32), 256));
|
||||
self:WriteByte(mod(rshift(val, 24), 256));
|
||||
self:WriteByte(mod(rshift(val, 16), 256));
|
||||
self:WriteByte(mod(rshift(val, 8), 256));
|
||||
self:WriteByte(mod(val, 256));
|
||||
end
|
||||
|
||||
function QuestieStreamLib:_WriteLong_assert(val)
|
||||
@@ -476,7 +477,7 @@ end
|
||||
|
||||
function QuestieStreamLib:Save()
|
||||
local chunks = {}
|
||||
for i=1, #self._bin do
|
||||
for i=1, table.getn(self._bin) do
|
||||
table.insert(chunks, table.concat(self._bin[i]))
|
||||
end
|
||||
return table.concat(chunks)
|
||||
|
||||
@@ -206,7 +206,7 @@ describe("Audit Pass 9 - file-by-file findings (snapshot at HEAD)", function()
|
||||
it("[9.1->11.1] CORRECTED: % modulo IS used (the 'avoided' claim was wrong)", function()
|
||||
-- Pass 8-10 wrongly said % modulo = 0. Real modulo operators exist in
|
||||
-- Turtle-TOC files and are 5.0 parse errors that math.mod cannot rescue.
|
||||
assert.is_true(has(read("Modules/QuestieStream.lua"), " % 256"))
|
||||
assert.is_true(has(read("Modules/QuestieStream.lua"), "mod(val, 256)"))
|
||||
assert.is_true(has(read("Modules/QuestiePlayer.lua"), "% playerRaceFlagX2"))
|
||||
end)
|
||||
end)
|
||||
@@ -326,4 +326,25 @@ describe("Audit Pass 10 - additional performance findings (snapshot)", function(
|
||||
assert.is_true(has(advancedOptions, "questieCommsQuestListBlockInterval"))
|
||||
assert.is_true(has(advancedOptions, "Questie.db.profile.questieCommsEnabled == false"))
|
||||
end)
|
||||
|
||||
it("[L50] loader, serializer, and stream are wired for Lua 5.0 compatibility", function()
|
||||
local loader = read("Modules/Libs/QuestieLoader.lua")
|
||||
local serializer = read("Modules/Libs/QuestieSerializer.lua")
|
||||
local stream = read("Modules/QuestieStream.lua")
|
||||
|
||||
assert.is_true(has(loader, "bitlib.band = bitlib.band or band32"))
|
||||
assert.is_true(has(loader, "strsplit = function(separator, text, max)"))
|
||||
|
||||
assert.is_true(has(serializer, "local mod = math.mod"))
|
||||
assert.is_true(has(serializer, "mod(expo, 0x2)"))
|
||||
assert.is_true(has(serializer, "mod(b1, 0x80)"))
|
||||
assert.is_false(has(serializer, "expo % 0x2"))
|
||||
|
||||
assert.is_true(has(stream, "local mod = math.mod"))
|
||||
assert.is_true(has(stream, "table.getn(self._bin)"))
|
||||
assert.is_true(has(stream, "mod(val1, 256)"))
|
||||
assert.is_true(has(stream, "mod(val2, 256)"))
|
||||
assert.is_false(has(stream, "val1 % 256"))
|
||||
assert.is_false(has(stream, "val2 % 256"))
|
||||
end)
|
||||
end)
|
||||
|
||||
Reference in New Issue
Block a user