Thread Tools Display Modes
10-12-13, 03:44 PM   #1
Vrul
A Scalebane Royal Guard
 
Vrul's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2007
Posts: 404
Unwrapping a Script for a Specific Header

It seems like all the code for wrapping/unwrapping script handlers was set up to allow unwrapping a script handler for a specific header that had already been wrapped again. But it doesn't quite work that way, it only removes the last wrap no matter the source. I would like to see some minor changes to some functions in SecureHandlers.lua, that maintain backwards compatability, but also allow for this behavior. The following functions would need modified as shown:
Code:
local function RemoveWrapper(frame, script, header)
    local wrap = frame:GetScript(script);

    if ((not issecure()) or (LOCAL_Wrapped_Handlers[wrap] == nil)) then
        -- not valid
        return;
    end

    if ((not header) or (wrap(MAGIC_UNWRAP) == header)) then
        if (not securecall(RestoreWrapHandler, frame, script, wrap)) then
            -- not valid
            return;
        end
    else
        local prevWrap;
        repeat
            prevWrap, wrap = wrap, LOCAL_Wrapped_Handlers[wrap];
            if (not wrap) then return; end
        until (wrap(MAGIC_UNWRAP) == header)
        LOCAL_Wrapped_Handlers[prevWrap] = LOCAL_Wrapped_Handlers[wrap];
    end

    -- Extract header, preBody, postBody
    return wrap(MAGIC_UNWRAP);
end

function SecureHandlerUnwrapScript(frame, script, header)
    if (not IsValidFrame(frame)) then
        error("Invalid frame");
    end
    if (type(script) ~= "string") then
        error("Invalid script id");
    end
    if (header) then
        if (not IsValidFrame(header)) then
            error("Invalid header frame");
            return;
        end
        if (not select(2, header:IsProtected())) then
            error("Header frame must be explicitly protected");
            return;
        end
        LOCAL_API_Frame:SetAttribute("_apiheader", header);
    else
        LOCAL_API_Frame:SetAttribute("_apiheader", nil);
    end
    wipe(UNWRAP_TEMP_TABLE);
    UNWRAP_TEMP_TABLE[1] = false;
    LOCAL_API_Frame:SetAttribute("_apiframe", frame);
    LOCAL_API_Frame:SetAttribute("_apidata", UNWRAP_TEMP_TABLE);
    LOCAL_API_Frame:SetAttribute("_unwrap", script);

    local chkFrame = UNWRAP_TEMP_TABLE[1];
    local chkScript = UNWRAP_TEMP_TABLE[2];
    local header = UNWRAP_TEMP_TABLE[3];
    local preBody = UNWRAP_TEMP_TABLE[4];
    local postBody = UNWRAP_TEMP_TABLE[5];

    if ((chkFrame ~= frame) or (chkScript ~= script)) then
        error("Unable to retrieve unwrap results");
        return;
    end
    wipe(UNWRAP_TEMP_TABLE);
    return header, preBody, postBody;
end

local function SecureHandlerMethod_UnwrapScript(self, frame, script, restrict)
    -- Wrapped since args are in different order
    return SecureHandlerUnwrapScript(frame, script, restrict and self or nil);
end
The following portion of API_OnAttributeChanged would also need changed:
Code:
    -- _unwrap restores a previously wrapped handler
    if (name == "_unwrap") then
        local frame =  self:GetAttribute("_apiframe");
        local header = self:GetAttribute("_apiheader");
        local data =  self:GetAttribute("_apidata");
        if (data) then
            self:SetAttribute("_apidata", nil);
        end
        self:SetAttribute("_unwrap", nil);
        if (type(value) ~= "string") then
            error("Invalid unwrap script id");
        end
        if (not IsValidFrame(frame)) then
            error("Invalid unwrap frame");
        end
        if (header and (not IsValidFrame(header))) then
            error("Invalid header frame");
        end
        local script = value;
        if (not frame:HasScript(script)) then
            error("Frame does not support script '" .. script .. "'");
        end
        local header, preBody, postBody = RemoveWrapper(frame, script, header);
        if (type(data) == "table") then
            forceinsecure();
            wipe(data);
            data[1] = frame;
            data[2] = script;
            data[3] = header;
            data[4] = preBody;
            data[5] = postBody;
        end
        return;
    end
Those changes would allow you to undo a header's last wrap for a script with:
Code:
header:UnwrapScript(frame, script, true)
without the garbage churn from doing:
Code:
local function UnwrapScript(header, frame, script)
    local _header, _preScript, _postScript = header:UnwrapScript(frame, script)
    if _header and _header ~= header then
        UnwrapScript(header, frame, script)
        _header:WrapScript(frame, script, _preScript, _postScript)
    end
end

UnwrapScript(header, frame, script)
I would go so far as to suggest that this behavior should be the default as it seems weird to allow any header to unwrap another header's code.
  Reply With Quote

WoWInterface » Developer Discussions » Wish List » Unwrapping a Script for a Specific Header

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off