1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250
|
-----------------------------------------------------------------------------
-- Encoding conversion routines
-- LuaSocket toolkit
-- Author: Diego Nehab
-- Conforming to: RFC 2045, LTN7
-- RCS ID: $Id: code.lua,v 1.10 2003/07/05 06:11:32 diego Exp $
-----------------------------------------------------------------------------
local Private, Public = {}, {}
local socket = _G[LUASOCKET_LIBNAME] -- get LuaSocket namespace
socket.code = Public
-----------------------------------------------------------------------------
-- Public constants
-----------------------------------------------------------------------------
Public.LINEWIDTH = 76
-----------------------------------------------------------------------------
-- Direct and inverse convertion tables for base64
-----------------------------------------------------------------------------
Private.t64 = {
[00] = 'A', [01] = 'B', [02] = 'C', [03] = 'D', [04] = 'E', [05] = 'F',
[06] = 'G', [07] = 'H', [08] = 'I', [09] = 'J', [10] = 'K', [11] = 'L',
[12] = 'M', [13] = 'N', [14] = 'O', [15] = 'P', [16] = 'Q', [17] = 'R',
[18] = 'S', [19] = 'T', [20] = 'U', [21] = 'V', [22] = 'W', [23] = 'X',
[24] = 'Y', [25] = 'Z', [26] = 'a', [27] = 'b', [28] = 'c', [29] = 'd',
[30] = 'e', [31] = 'f', [32] = 'g', [33] = 'h', [34] = 'i', [35] = 'j',
[36] = 'k', [37] = 'l', [38] = 'm', [39] = 'n', [40] = 'o', [41] = 'p',
[42] = 'q', [43] = 'r', [44] = 's', [45] = 't', [46] = 'u', [47] = 'v',
[48] = 'w', [49] = 'x', [50] = 'y', [51] = 'z', [52] = '0', [53] = '1',
[54] = '2', [55] = '3', [56] = '4', [57] = '5', [58] = '6', [59] = '7',
[60] = '8', [61] = '9', [62] = '+', [63] = '/', [64] = '='
}
Private.f64 = {
['A'] = 00, ['B'] = 01, ['C'] = 02, ['D'] = 03, ['E'] = 04, ['F'] = 05,
['G'] = 06, ['H'] = 07, ['I'] = 08, ['J'] = 09, ['K'] = 10, ['L'] = 11,
['M'] = 12, ['N'] = 13, ['O'] = 14, ['P'] = 15, ['Q'] = 16, ['R'] = 17,
['S'] = 18, ['T'] = 19, ['U'] = 20, ['V'] = 21, ['W'] = 22, ['X'] = 23,
['Y'] = 24, ['Z'] = 25, ['a'] = 26, ['b'] = 27, ['c'] = 28, ['d'] = 29,
['e'] = 30, ['f'] = 31, ['g'] = 32, ['h'] = 33, ['i'] = 34, ['j'] = 35,
['k'] = 36, ['l'] = 37, ['m'] = 38, ['n'] = 39, ['o'] = 40, ['p'] = 41,
['q'] = 42, ['r'] = 43, ['s'] = 44, ['t'] = 45, ['u'] = 46, ['v'] = 47,
['w'] = 48, ['x'] = 49, ['y'] = 50, ['z'] = 51, ['0'] = 52, ['1'] = 53,
['2'] = 54, ['3'] = 55, ['4'] = 56, ['5'] = 57, ['6'] = 58, ['7'] = 59,
['8'] = 60, ['9'] = 61, ['+'] = 62, ['/'] = 63, ['='] = 64
}
-----------------------------------------------------------------------------
-- Converts a three byte sequence into its four character base64
-- representation
-----------------------------------------------------------------------------
function Private.t2f(a,b,c)
local s = string.byte(a)*65536 + string.byte(b)*256 + string.byte(c)
local ca, cb, cc, cd
cd = math.mod(s, 64)
s = (s - cd) / 64
cc = math.mod(s, 64)
s = (s - cc) / 64
cb = math.mod(s, 64)
ca = (s - cb) / 64
return Private.t64[ca] .. Private.t64[cb] ..
Private.t64[cc] .. Private.t64[cd]
end
-----------------------------------------------------------------------------
-- Converts a four character base64 representation into its three byte
-- sequence
-----------------------------------------------------------------------------
function Private.f2t(a,b,c,d)
local s = Private.f64[a]*262144 + Private.f64[b]*4096 +
Private.f64[c]*64 + Private.f64[d]
local ca, cb, cc
cc = math.mod(s, 256)
s = (s - cc) / 256
cb = math.mod(s, 256)
ca = (s - cb) / 256
return string.char(ca, cb, cc)
end
-----------------------------------------------------------------------------
-- Creates a base64 representation of an incomplete last block
-----------------------------------------------------------------------------
function Private.to64pad(s)
local a, b, ca, cb, cc, _
_, _, a, b = string.find(s, "(.?)(.?)")
if b == "" then
s = string.byte(a)*16
cb = math.mod(s, 64)
ca = (s - cb)/64
return Private.t64[ca] .. Private.t64[cb] .. "=="
end
s = string.byte(a)*1024 + string.byte(b)*4
cc = math.mod(s, 64)
s = (s - cc) / 64
cb = math.mod(s, 64)
ca = (s - cb)/64
return Private.t64[ca] .. Private.t64[cb] .. Private.t64[cc] .. "="
end
-----------------------------------------------------------------------------
-- Decodes the base64 representation of an incomplete last block
-----------------------------------------------------------------------------
function Private.from64pad(s)
local a, b, c, d
local ca, cb, _
_, _, a, b, c, d = string.find(s, "(.)(.)(.)(.)")
if d ~= "=" then return Private.f2t(a,b,c,d)
elseif c ~= "=" then
s = Private.f64[a]*1024 + Private.f64[b]*16 + Private.f64[c]/4
cb = math.mod(s, 256)
ca = (s - cb)/256
return string.char(ca, cb)
else
s = Private.f64[a]*4 + Private.f64[b]/16
ca = math.mod(s, 256)
return string.char(ca)
end
end
-----------------------------------------------------------------------------
-- Break a string in lines of equal size
-- Input
-- data: string to be broken
-- eol: end of line marker
-- width: width of output string lines
-- Returns
-- string broken in lines
-----------------------------------------------------------------------------
function Public.split(data, eol, width)
width = width or (Public.LINEWIDTH - string.len(eol) + 2)
eol = eol or "\r\n"
-- this looks ugly, but for lines with less then 200 columns,
-- it is more efficient then using strsub and the concat module
local line = "(" .. string.rep(".", width) .. ")"
local repl = "%1" .. eol
return string.gsub(data, line, repl)
end
-----------------------------------------------------------------------------
-- Encodes a string into its base64 representation
-- Input
-- s: binary string to be encoded
-- single: single line output?
-- Returns
-- string with corresponding base64 representation
-----------------------------------------------------------------------------
function Public.base64(s, single)
local pad, whole
local l = string.len(s)
local m = math.mod(l, 3)
l = l - m
if l > 0 then
whole = string.gsub(string.sub(s, 1, l), "(.)(.)(.)", Private.t2f)
else whole = "" end
if m > 0 then pad = Private.to64pad(string.sub(s, l+1))
else pad = "" end
if single then return whole .. pad
else return Public.split(whole .. pad, 76) end
end
-----------------------------------------------------------------------------
-- Decodes a string from its base64 representation
-- Input
-- s: base64 string
-- Returns
-- decoded binary string
-----------------------------------------------------------------------------
function Public.unbase64(s)
-- clean string
local f64 = Private.f64
s = string.gsub(s, "(.)", function (c)
if f64[c] then return c
else return "" end
end)
local l = string.len(s)
local whole, pad
if l > 4 then
whole = string.gsub(string.sub(s, 1, -5), "(.)(.)(.)(.)", Private.f2t)
else whole = "" end
pad = Private.from64pad(string.sub(s, -4))
return whole .. pad
end
-----------------------------------------------------------------------------
-- Encodes a string into its hexadecimal representation
-- Input
-- s: binary string to be encoded
-- Returns
-- string with corresponding hexadecimal representation
-----------------------------------------------------------------------------
function Public.hexa(s)
return string.gsub(s, "(.)", function(c)
return string.format("%02x", string.byte(c))
end)
end
-----------------------------------------------------------------------------
-- Encodes a string into its hexadecimal representation
-- Input
-- s: hexa string
-- Returns
-- decoded binary string
-----------------------------------------------------------------------------
function Public.unhexa(s)
return string.gsub(s, "(%x%x)", function(hex)
return string.char(tonumber(hex, 16))
end)
end
-----------------------------------------------------------------------------
-- Encodes a string into its escaped hexadecimal representation
-- Input
-- s: binary string to be encoded
-- Returns
-- escaped representation of string binary
-----------------------------------------------------------------------------
function Public.escape(s)
return string.gsub(s, "(.)", function(c)
return string.format("%%%02x", string.byte(c))
end)
end
-----------------------------------------------------------------------------
-- Encodes a string into its escaped hexadecimal representation
-- Input
-- s: binary string to be encoded
-- Returns
-- escaped representation of string binary
-----------------------------------------------------------------------------
function Public.unescape(s)
return string.gsub(s, "%%(%x%x)", function(hex)
return string.char(tonumber(hex, 16))
end)
end
-----------------------------------------------------------------------------
-- Decodes a string from its Quoted-Printable representation
-- Input
-- s: Quoted-Printable string
-- Returns
-- decoded binary string
-----------------------------------------------------------------------------
function Public.unquote(s)
s = string.gsub(s, "%=\r\n", "")
s = string.gsub(s, "%=(%x%x)", function (hex)
return string.char(tonumber(hex, 16))
end)
return s
end
|