1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-06 04:31:29 +00:00

Use local functions instead of anonymous functions for gsub (less GC overhead)

This commit is contained in:
dmiller
2020-11-30 23:22:06 +00:00
parent c8fdcd80b5
commit 86deb87187
5 changed files with 69 additions and 43 deletions

View File

@@ -78,6 +78,10 @@ local function clamp (args, i, j, mask)
end end
end end
local function _fromhex (s)
return char(tonumber(s, 16))
end
--- Returns a binary packed string. --- Returns a binary packed string.
-- --
-- The format string describes how the parameters (<code>p1</code>, -- The format string describes how the parameters (<code>p1</code>,
@@ -107,7 +111,7 @@ function _ENV.pack (format, ...)
assert(n > 0, "n cannot be 0") -- original bin library allowed this, it doesn't make sense assert(n > 0, "n cannot be 0") -- original bin library allowed this, it doesn't make sense
local new = "=" -- !! in original bin library, hex strings are always native local new = "=" -- !! in original bin library, hex strings are always native
for j = i, i+n-1 do for j = i, i+n-1 do
args[j] = tostring(args[j]):gsub("%s*(%S%S?)%s*", function (s) return char(tonumber(s, 16)) end) args[j] = tostring(args[j]):gsub("%s*(%S%S?)%s*", _fromhex)
new = new .. ("c%d"):format(#args[j]) new = new .. ("c%d"):format(#args[j])
end end
new = new .. endianness -- restore old endianness new = new .. endianness -- restore old endianness
@@ -208,15 +212,24 @@ do
assert(_ENV.pack("<C2SIL", 0x123, 0xfff1, 0x1ffff, 0x112345678, 0x1234567812345678) == "\x23\xf1\xff\xff\x78\x56\x34\x12\x78\x56\x34\x12\x78\x56\x34\x12") assert(_ENV.pack("<C2SIL", 0x123, 0xfff1, 0x1ffff, 0x112345678, 0x1234567812345678) == "\x23\xf1\xff\xff\x78\x56\x34\x12\x78\x56\x34\x12\x78\x56\x34\x12")
end end
local function _fmt_hex (c)
return ("%02X"):format(c:byte())
end
local function _fmt_bin (c)
local n = tobinary(c:byte())
return ("0"):rep(8-#n)..n
end
local function unpacker (fixer, status, ...) local function unpacker (fixer, status, ...)
if not status then return 1 end if not status then return 1 end
-- Lua's unpack gives the stop index last: -- Lua's unpack gives the stop index last:
local list = pack(...) local list = pack(...)
for i, v in ipairs(fixer) do for i, v in ipairs(fixer) do
if v.what == "H" then if v.what == "H" then
list[v.which] = list[v.which]:gsub(".", function (c) return ("%02X"):format(c:byte()) end) list[v.which] = list[v.which]:gsub(".", _fmt_hex)
elseif v.what == "B" then elseif v.what == "B" then
list[v.which] = list[v.which]:gsub(".", function (c) local n = tobinary(c:byte()); return ("0"):rep(8-#n)..n end) list[v.which] = list[v.which]:gsub(".", _fmt_bin)
else else
assert(false) assert(false)
end end

View File

@@ -680,9 +680,28 @@ end
local bin_lookup = { local bin_lookup = {
[0]="0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", ["0"]="0000",
"1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111", ["1"]="0001",
["2"]="0010",
["3"]="0011",
["4"]="0100",
["5"]="0101",
["6"]="0110",
["7"]="0111",
["8"]="1000",
["9"]="1001",
["a"]="1010",
["b"]="1011",
["c"]="1100",
["d"]="1101",
["e"]="1110",
["f"]="1111",
} }
setmetatable(bin_lookup, {
__index = function()
error("Error in ipOps.hex_to_bin: Expected string representing a hexadecimal number.")
end
})
--- ---
-- Converts a string of hexadecimal digits into the corresponding string of -- Converts a string of hexadecimal digits into the corresponding string of
-- binary digits. -- binary digits.
@@ -699,14 +718,7 @@ hex_to_bin = function( hex )
return nil, "Error in ipOps.hex_to_bin: Expected string" return nil, "Error in ipOps.hex_to_bin: Expected string"
end end
local status, result = pcall( string.gsub, hex, ".", function(nibble) local status, result = pcall( string.gsub, string.lower(hex), ".", bin_lookup)
local n = bin_lookup[tonumber(nibble, 16)]
if n then
return n
else
error("Error in ipOps.hex_to_bin: Expected string representing a hexadecimal number.")
end
end)
if status then if status then
return result return result
end end
@@ -820,7 +832,7 @@ end
do do
for _, h in ipairs({ for _, h in ipairs({
{"a", "1010"}, {"a", "1010"},
{"aa", "10101010"}, {"aA", "10101010"},
{"12", "00010010"}, {"12", "00010010"},
{"54321", "01010100001100100001"}, {"54321", "01010100001100100001"},
{"123error", false}, {"123error", false},

View File

@@ -445,6 +445,9 @@ end
-- Helpers -- Helpers
local function _hex_str (x)
return string.char(tonumber(x, 16))
end
--- Convert a MAC address string (like <code>"00:23:ae:5d:3b:10"</code>) to --- Convert a MAC address string (like <code>"00:23:ae:5d:3b:10"</code>) to
-- a raw six-byte long. -- a raw six-byte long.
-- @param str MAC address string. -- @param str MAC address string.
@@ -453,9 +456,7 @@ function mactobin(str)
if not str then if not str then
return nil, "MAC was not specified." return nil, "MAC was not specified."
end end
return (str:gsub("(%x%x)[^%x]?", function (x) return (str:gsub("(%x%x)[^%x]?", _hex_str))
return string.char(tonumber(x, 16))
end))
end end
--- Generate the link-local IPv6 address from the MAC address. --- Generate the link-local IPv6 address from the MAC address.

View File

@@ -70,6 +70,9 @@ end
-- This pattern must match the percent sign '%' since it is used in -- This pattern must match the percent sign '%' since it is used in
-- escaping. -- escaping.
local FILESYSTEM_UNSAFE = "[^a-zA-Z0-9._-]" local FILESYSTEM_UNSAFE = "[^a-zA-Z0-9._-]"
local function _escape_helper (c)
return format("%%%02x", byte(c))
end
--- ---
-- Escape a string to remove bytes and strings that may have meaning to -- Escape a string to remove bytes and strings that may have meaning to
-- a filesystem, such as slashes. -- a filesystem, such as slashes.
@@ -97,9 +100,7 @@ function filename_escape(s)
elseif s == ".." then elseif s == ".." then
return "%2e%2e" return "%2e%2e"
else else
return (gsub(s, FILESYSTEM_UNSAFE, function (c) return (gsub(s, FILESYSTEM_UNSAFE, _escape_helper))
return format("%%%02x", byte(c))
end))
end end
end end

View File

@@ -57,12 +57,17 @@ local function make_set(t)
return s return s
end end
local function hex_esc (c)
return string.format("%%%02x", string.byte(c))
end
-- these are allowed within a path segment, along with alphanum -- these are allowed within a path segment, along with alphanum
-- other characters must be escaped -- other characters must be escaped
local segment_set = make_set { local segment_set = make_set {
"-", "_", ".", "!", "~", "*", "'", "(", "-", "_", ".", "!", "~", "*", "'", "(",
")", ":", "@", "&", "=", "+", "$", ",", ")", ":", "@", "&", "=", "+", "$", ",",
} }
setmetatable(segment_set, { __index = hex_esc })
--- ---
-- Protects a path segment, to prevent it from interfering with the -- Protects a path segment, to prevent it from interfering with the
@@ -70,10 +75,7 @@ local segment_set = make_set {
-- @param s Binary string to be encoded. -- @param s Binary string to be encoded.
-- @return Escaped representation of string. -- @return Escaped representation of string.
local function protect_segment(s) local function protect_segment(s)
return string.gsub(s, "([^A-Za-z0-9_.~-])", function (c) return string.gsub(s, "([^A-Za-z0-9_.~-])", segment_set)
if segment_set[c] then return c
else return string.format("%%%02x", string.byte(c)) end
end)
end end
--- ---
@@ -115,25 +117,26 @@ end
-- @return Escaped representation of string. -- @return Escaped representation of string.
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
function escape(s) function escape(s)
local ret = string.gsub(s, "([^A-Za-z0-9_.~-])", function(c) return (string.gsub(s, "([^A-Za-z0-9_.~-])", hex_esc))
return string.format("%%%02x", string.byte(c))
end)
return ret
end end
local function hex_unesc (hex)
return string.char(base.tonumber(hex, 16))
end
--- ---
-- Decodes an escaped hexadecimal string. -- Decodes an escaped hexadecimal string.
-- @param s Hexadecimal-encoded string. -- @param s Hexadecimal-encoded string.
-- @return Decoded string. -- @return Decoded string.
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
function unescape(s) function unescape(s)
local ret = string.gsub(s, "%%(%x%x)", function(hex) return (string.gsub(s, "%%(%x%x)", hex_unesc))
return string.char(base.tonumber(hex, 16))
end)
return ret
end end
local function normalize_escape (s)
return escape(unescape(s))
end
--- ---
-- Parses a URL and returns a table with all its parts according to RFC 3986. -- Parses a URL and returns a table with all its parts according to RFC 3986.
@@ -171,14 +174,7 @@ function parse(url, default)
-- remove whitespace -- remove whitespace
-- url = string.gsub(url, "%s", "") -- url = string.gsub(url, "%s", "")
-- Decode unreserved characters -- Decode unreserved characters
url = string.gsub(url, "%%(%x%x)", function(hex) url = string.gsub(url, "%%%x%x", normalize_escape)
local char = string.char(base.tonumber(hex, 16))
if string.match(char, "[a-zA-Z0-9._~-]") then
return char
end
-- Hex encodings that are not unreserved must be preserved.
return nil
end)
-- get fragment -- get fragment
url = string.gsub(url, "#(.*)$", function(f) url = string.gsub(url, "#(.*)$", function(f)
parsed.fragment = f parsed.fragment = f
@@ -353,6 +349,11 @@ function build_path(parsed, unsafe)
return table.concat(path) return table.concat(path)
end end
local entities = {
["amp"] = "&",
["lt"] = "<",
["gt"] = ">"
}
--- ---
-- Breaks a query string into name/value pairs. -- Breaks a query string into name/value pairs.
-- --
@@ -369,9 +370,7 @@ function parse_query(query)
local parsed = {} local parsed = {}
local pos = 1 local pos = 1
query = string.gsub(query, "&amp;", "&") query = string.gsub(query, "&([ampltg]+);", entities)
query = string.gsub(query, "&lt;", "<")
query = string.gsub(query, "&gt;", ">")
local function ginsert(qstr) local function ginsert(qstr)
local pos = qstr:find("=", 1, true) local pos = qstr:find("=", 1, true)