Fandom Developers Wiki
Documentation icon Module documentation

The documentation for this module is missing. Click here to create it.

-- Utils: representation

local function hex_to_bytes(repr)
    assert(string.match(repr, '^%x*$'), 'Representation contains non-hexadecimal digits')
    assert(#repr % 2 == 0, 'Cannot convert odd number of nibbles without truncation')
    local bytes = ''
    for x in string.gmatch(repr, '%x%x') do
        bytes = bytes .. string.char(tonumber(x, 16))
    end
    return bytes
end

-- Utils: MW helpers

local function make_message(frame)
    local i, message = 0, ''
    for k, v in ipairs(frame.args) do
        if i > 0 then message = message .. '\0' end
        i = i + 1
        message = message .. v
    end
    -- Per Scribunto docs, we can't count the number of anonymous/numbered params with `#frame.args`
    assert(i > 0, 'Function must be invoked with at least one anonymous or numbered parameter')
    return message
end

-- Utils: hash functions

local function MD5(message)
    local iface, partial_message, memoized_digest, memoized_hexdigest = {}, message or '', nil, nil

    function iface.update(message)
        assert(partial_message ~= nil, 'MD5 context has already been finalized')
        partial_message = partial_message .. message
        return iface  -- Facilitate fluent interface
    end

    function iface.digest()
        if memoized_digest == nil then memoized_digest = hex_to_bytes(iface.hexdigest()) end
        return memoized_digest
    end

    function iface.hexdigest()
        if memoized_hexdigest == nil then
            assert(partial_message ~= nil, 'MD5 context has already been finalized')
            memoized_hexdigest = mw.hash.hashValue('md5', partial_message)
            partial_message = nil
        end
        return memoized_hexdigest
    end

    return iface
end

-- Exports

local p = {}

-- Exports: for use in other libraries

p.MD5 = MD5

-- Exports: invocables

function p.md5_hexdigest(frame)
    local message = make_message(frame)
    return mw.hash.hashValue('md5', message)
end

return p