Created
May 1, 2012 00:28
Revisions
-
paulmoore revised this gist
May 3, 2012 . 1 changed file with 25 additions and 6 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -2,11 +2,11 @@ -- -- https://gist.github.com/2563975 -- -- V0.3 for Lua 5.1 -- -- A simple Base64 encoder/decoder that uses a URL safe variant of the standard. -- This implementation encodes character 62 as '-' (instead of '+') and character 63 as '_' (instead of '/'). -- In addition, padding is not used by default. -- A full description of the specification can be found here: http://tools.ietf.org/html/rfc4648 -- -- To encode, use base64.encode(input), where input is a string of arbitrary bytes. The output is a Base64 encoded string. @@ -19,6 +19,10 @@ -- print("Error, "..result) -- end -- -- If you prefer a different Base64 variant, you can simply change the ENCODABET to your liking. -- If you wish to use padding, you can change the PAD value to a non-nil, non-empty string. -- The library will still be able to decode non-padded strings if a PAD is given. -- -- For all valid input, input == base64.decode(base64.encode(input)). -- -- This library has a dependency on LuaBit v0.4, which can be found here: http://luaforge.net/projects/bit/ @@ -64,6 +68,8 @@ for i, v in ipairs(ENCODABET) do DECODABET[v] = i - 1 end local PAD = nil --- Converts a 6-bit octet into the associated Base64 character. -- -- @param octet A 6-bit integer. @@ -144,6 +150,9 @@ function base64.encode (input) b = bit.band(b, 0x3f) out[#out + 1] = toChar(b) out[#out + 1] = PAD out[#out + 1] = PAD -- Special case 2: Two bytes extra, will produce 3 octets. elseif #bytes % 3 == 2 then local buffer = 0 @@ -167,6 +176,8 @@ function base64.encode (input) b = bit.blogic_rshift(buffer, 6) b = bit.band(b, 0x3f) out[#out + 1] = toChar(b) out[#out + 1] = PAD end return table.concat(out) @@ -183,11 +194,19 @@ function base64.decode (input) assert(type(input) == "string", "Invalid input, expected type string but got: "..tostring(input).." as a: "..type(input)) assert(#input > 0, "Invalid input, cannot decode an empty string.") local length = #input -- Ignore any padding. if PAD then length = input:find(PAD, 1, true) or (length + 1) length = length - 1 end assert(length > 0, "Invalid input, cannot decode a padded string with no bytes: "..tostring(input)) local out = {} -- Go through each group of 4 octets to obtain 3 bytes. local i = 1 while i <= length - 3 do local buffer = 0 -- Read the 4 octets into the buffer, producing a 24-bit integer. @@ -224,7 +243,7 @@ function base64.decode (input) end -- Special case 1: Only 2 octets remain, producing 1 byte. if length % 4 == 2 then local buffer = 0 local b = toOctet(input:sub(i, i)) @@ -242,7 +261,7 @@ function base64.decode (input) out[#out + 1] = b -- Special case 2: Only 3 octets remain, producing 2 bytes. elseif length % 4 == 3 then local buffer = 0 local b = toOctet(input:sub(i, i)) @@ -269,7 +288,7 @@ function base64.decode (input) out[#out + 1] = b -- Special case 3: One octet remains, we can't get any bytes out of this, throw error. elseif length % 4 == 1 then error("Invalid length input string, extra character: "..tostring(input:sub(i, i))) end -
paulmoore revised this gist
May 1, 2012 . 1 changed file with 60 additions and 40 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -2,6 +2,8 @@ -- -- https://gist.github.com/2563975 -- -- V0.2 for Lua 5.1 -- -- A simple Base64 encoder/decoder that uses a URL safe variant of the standard. -- This implementation encodes character 62 as '-' (instead of '+') and character 63 as '_' (instead of '/'). -- In addition, padding is not used. @@ -10,7 +12,14 @@ -- To encode, use base64.encode(input), where input is a string of arbitrary bytes. The output is a Base64 encoded string. -- To decode, use base64.decode(input), where input is a Base64 encoded string. The output is a string of arbitrary bytes. -- -- The library will throw an error on invalid input, you can catch these as such: -- -- local status, result = pcall(base64.decode(invalidInput)) -- if not status then -- print("Error, "..result) -- end -- -- For all valid input, input == base64.decode(base64.encode(input)). -- -- This library has a dependency on LuaBit v0.4, which can be found here: http://luaforge.net/projects/bit/ -- @@ -50,25 +59,38 @@ local ENCODABET = { } --- char -> octet encoding. local DECODABET = {} for i, v in ipairs(ENCODABET) do DECODABET[v] = i - 1 end --- Converts a 6-bit octet into the associated Base64 character. -- -- @param octet A 6-bit integer. -- @return The Base64 representation of the character local function toChar (octet) return assert(ENCODABET[octet + 1], "No Base64 character for octet: "..tostring(octet)) end --- Converts a Base64 character into the associated octet. -- -- @param char The single Base64 character. -- @return The 6-bit integer representing the Base64 character. local function toOctet (char) return assert(DECODABET[char], "Not a valid Base64 character: "..tostring(char)) end --- Encodes a string into a Base64 string. -- The input can be any string of arbitrary bytes. -- If the input is not a string, or the string is empty, an error will be thrown. -- -- @param input The input string. -- @return The Base64 representation of the input string. function base64.encode (input) assert(type(input) == "string", "Invalid input, expected type string but got: "..tostring(input).." as a: "..type(input)) assert(#input > 0, "Invalid input, cannot encode an empty string.") local bytes = { input:byte(i, #input) } local out = {} @@ -93,18 +115,18 @@ function base64.encode (input) -- Read out the 4 octets into the output buffer. b = bit.blogic_rshift(buffer, 18) b = bit.band(b, 0x3f) out[#out + 1] = toChar(b) b = bit.blogic_rshift(buffer, 12) b = bit.band(b, 0x3f) out[#out + 1] = toChar(b) b = bit.blogic_rshift(buffer, 6) b = bit.band(b, 0x3f) out[#out + 1] = toChar(b) b = bit.band(buffer, 0x3f) out[#out + 1] = toChar(b) i = i + 3 end @@ -116,11 +138,11 @@ function base64.encode (input) local b = bit.blogic_rshift(buffer, 18) b = bit.band(b, 0x3f) out[#out + 1] = toChar(b) b = bit.blogic_rshift(buffer, 12) b = bit.band(b, 0x3f) out[#out + 1] = toChar(b) -- Special case 2: Two bytes extra, will produce 3 octets. elseif #bytes % 3 == 2 then @@ -136,28 +158,31 @@ function base64.encode (input) b = bit.blogic_rshift(buffer, 18) b = bit.band(b, 0x3f) out[#out + 1] = toChar(b) b = bit.blogic_rshift(buffer, 12) b = bit.band(b, 0x3f) out[#out + 1] = toChar(b) b = bit.blogic_rshift(buffer, 6) b = bit.band(b, 0x3f) out[#out + 1] = toChar(b) end return table.concat(out) end --- Decodes a Base64 string into an output string of arbitrary bytes. -- If the input is not a string, or the string is empty, or the string is not well-formed Base64, an error will be thrown. -- -- @param input The Base64 input to decode. -- @return The decoded Base64 string, as a string of bytes. function base64.decode (input) assert(type(input) == "string", "Invalid input, expected type string but got: "..tostring(input).." as a: "..type(input)) assert(#input > 0, "Invalid input, cannot decode an empty string.") local out = {} -- Go through each group of 4 octets to obtain 3 bytes. @@ -166,26 +191,22 @@ function base64.decode (input) local buffer = 0 -- Read the 4 octets into the buffer, producing a 24-bit integer. local b = toOctet(input:sub(i, i)) b = bit.blshift(b, 18) buffer = bit.bor(buffer, b) i = i + 1 b = toOctet(input:sub(i, i)) b = bit.blshift(b, 12) buffer = bit.bor(buffer, b) i = i + 1 b = toOctet(input:sub(i, i)) b = bit.blshift(b, 6) buffer = bit.bor(buffer, b) i = i + 1 b = toOctet(input:sub(i, i)) buffer = bit.bor(buffer, b) i = i + 1 @@ -206,14 +227,12 @@ function base64.decode (input) if #input % 4 == 2 then local buffer = 0 local b = toOctet(input:sub(i, i)) b = bit.blshift(b, 18) buffer = bit.bor(buffer, b) i = i + 1 b = toOctet(input:sub(i, i)) b = bit.blshift(b, 12) buffer = bit.bor(buffer, b) i = i + 1 @@ -226,20 +245,17 @@ function base64.decode (input) elseif #input % 4 == 3 then local buffer = 0 local b = toOctet(input:sub(i, i)) b = bit.blshift(b, 18) buffer = bit.bor(buffer, b) i = i + 1 b = toOctet(input:sub(i, i)) b = bit.blshift(b, 12) buffer = bit.bor(buffer, b) i = i + 1 b = toOctet(input:sub(i, i)) b = bit.blshift(b, 6) buffer = bit.bor(buffer, b) i = i + 1 @@ -251,6 +267,10 @@ function base64.decode (input) b = bit.blogic_rshift(buffer, 8) b = bit.band(b, 0xff) out[#out + 1] = b -- Special case 3: One octet remains, we can't get any bytes out of this, throw error. elseif #input % 4 == 1 then error("Invalid length input string, extra character: "..tostring(input:sub(i, i))) end return string.char(unpack(out)) -
paulmoore revised this gist
May 1, 2012 . 1 changed file with 2 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,5 +1,7 @@ --- base64.lua -- -- https://gist.github.com/2563975 -- -- A simple Base64 encoder/decoder that uses a URL safe variant of the standard. -- This implementation encodes character 62 as '-' (instead of '+') and character 63 as '_' (instead of '/'). -- In addition, padding is not used. -
paulmoore created this gist
May 1, 2012 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,256 @@ --- base64.lua -- -- A simple Base64 encoder/decoder that uses a URL safe variant of the standard. -- This implementation encodes character 62 as '-' (instead of '+') and character 63 as '_' (instead of '/'). -- In addition, padding is not used. -- A full description of the specification can be found here: http://tools.ietf.org/html/rfc4648 -- -- To encode, use base64.encode(input), where input is a string of arbitrary bytes. The output is a Base64 encoded string. -- To decode, use base64.decode(input), where input is a Base64 encoded string. The output is a string of arbitrary bytes. -- -- For all input, input == base64.decode(base64.encode(input)). -- -- This library has a dependency on LuaBit v0.4, which can be found here: http://luaforge.net/projects/bit/ -- -- Copyright (C) 2012 by Paul Moore -- -- Permission is hereby granted, free of charge, to any person obtaining a copy -- of this software and associated documentation files (the "Software"), to deal -- in the Software without restriction, including without limitation the rights -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -- copies of the Software, and to permit persons to whom the Software is -- furnished to do so, subject to the following conditions: -- -- The above copyright notice and this permission notice shall be included in -- all copies or substantial portions of the Software. -- -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -- THE SOFTWARE. require "bit" base64 = {} --- octet -> char encoding. local ENCODABET = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_' } --- char -> octet encoding. -- Offset by 44 (from index 1). local DECODABET = { 62, 0, 0, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, 0, 0, 0, 0, 0, 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, 0, 0, 0, 0, 63, 0, 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 } --- Encodes a string into a Base64 string. -- The input can be any string of arbitrary bytes. -- -- @param input The input string. -- @return The Base64 representation of the input string. function base64.encode (input) local bytes = { input:byte(i, #input) } local out = {} -- Go through each triplet of 3 bytes, which produce 4 octets. local i = 1 while i <= #bytes - 2 do local buffer = 0 -- Fill the buffer with the bytes, producing a 24-bit integer. local b = bit.blshift(bytes[i], 16) b = bit.band(b, 0xff0000) buffer = bit.bor(buffer, b) b = bit.blshift(bytes[i + 1], 8) b = bit.band(b, 0xff00) buffer = bit.bor(buffer, b) b = bit.band(bytes[i + 2], 0xff) buffer = bit.bor(buffer, b) -- Read out the 4 octets into the output buffer. b = bit.blogic_rshift(buffer, 18) b = bit.band(b, 0x3f) out[#out + 1] = ENCODABET[b + 1] b = bit.blogic_rshift(buffer, 12) b = bit.band(b, 0x3f) out[#out + 1] = ENCODABET[b + 1] b = bit.blogic_rshift(buffer, 6) b = bit.band(b, 0x3f) out[#out + 1] = ENCODABET[b + 1] b = bit.band(buffer, 0x3f) out[#out + 1] = ENCODABET[b + 1] i = i + 3 end -- Special case 1: One byte extra, will produce 2 octets. if #bytes % 3 == 1 then local buffer = bit.blshift(bytes[i], 16) buffer = bit.band(buffer, 0xff0000) local b = bit.blogic_rshift(buffer, 18) b = bit.band(b, 0x3f) out[#out + 1] = ENCODABET[b + 1] b = bit.blogic_rshift(buffer, 12) b = bit.band(b, 0x3f) out[#out + 1] = ENCODABET[b + 1] -- Special case 2: Two bytes extra, will produce 3 octets. elseif #bytes % 3 == 2 then local buffer = 0 local b = bit.blshift(bytes[i], 16) b = bit.band(b, 0xff0000) buffer = bit.bor(buffer, b) b = bit.blshift(bytes[i + 1], 8) b = bit.band(b, 0xff00) buffer = bit.bor(buffer, b) b = bit.blogic_rshift(buffer, 18) b = bit.band(b, 0x3f) out[#out + 1] = ENCODABET[b + 1] b = bit.blogic_rshift(buffer, 12) b = bit.band(b, 0x3f) out[#out + 1] = ENCODABET[b + 1] b = bit.blogic_rshift(buffer, 6) b = bit.band(b, 0x3f) out[#out + 1] = ENCODABET[b + 1] end return table.concat(out) end --- Decodes a Base64 string into an output string of arbitrary bytes. -- Currently does not check the input for valid Base64, so be careful. -- -- @param input The Base64 input to decode. -- @return The decoded Base64 string, as a string of bytes. function base64.decode (input) local out = {} -- Go through each group of 4 octets to obtain 3 bytes. local i = 1 while i <= #input - 3 do local buffer = 0 -- Read the 4 octets into the buffer, producing a 24-bit integer. local b = input:byte(i) b = DECODABET[b - 44] b = bit.blshift(b, 18) buffer = bit.bor(buffer, b) i = i + 1 b = input:byte(i) b = DECODABET[b - 44] b = bit.blshift(b, 12) buffer = bit.bor(buffer, b) i = i + 1 b = input:byte(i) b = DECODABET[b - 44] b = bit.blshift(b, 6) buffer = bit.bor(buffer, b) i = i + 1 b = input:byte(i) b = DECODABET[b - 44] buffer = bit.bor(buffer, b) i = i + 1 -- Append the 3 re-constructed bytes into the output buffer. b = bit.blogic_rshift(buffer, 16) b = bit.band(b, 0xff) out[#out + 1] = b b = bit.blogic_rshift(buffer, 8) b = bit.band(b, 0xff) out[#out + 1] = b b = bit.band(buffer, 0xff) out[#out + 1] = b end -- Special case 1: Only 2 octets remain, producing 1 byte. if #input % 4 == 2 then local buffer = 0 local b = input:byte(i) b = DECODABET[b - 44] b = bit.blshift(b, 18) buffer = bit.bor(buffer, b) i = i + 1 b = input:byte(i) b = DECODABET[b - 44] b = bit.blshift(b, 12) buffer = bit.bor(buffer, b) i = i + 1 b = bit.blogic_rshift(buffer, 16) b = bit.band(b, 0xff) out[#out + 1] = b -- Special case 2: Only 3 octets remain, producing 2 bytes. elseif #input % 4 == 3 then local buffer = 0 local b = input:byte(i) b = DECODABET[b - 44] b = bit.blshift(b, 18) buffer = bit.bor(buffer, b) i = i + 1 b = input:byte(i) b = DECODABET[b - 44] b = bit.blshift(b, 12) buffer = bit.bor(buffer, b) i = i + 1 b = input:byte(i) b = DECODABET[b - 44] b = bit.blshift(b, 6) buffer = bit.bor(buffer, b) i = i + 1 b = bit.blogic_rshift(buffer, 16) b = bit.band(b, 0xff) out[#out + 1] = b b = bit.blogic_rshift(buffer, 8) b = bit.band(b, 0xff) out[#out + 1] = b end return string.char(unpack(out)) end This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,259 @@ --[[--------------- LuaBit v0.4 ------------------- a bitwise operation lib for lua. http://luaforge.net/projects/bit/ How to use: ------------------- bit.bnot(n) -- bitwise not (~n) bit.band(m, n) -- bitwise and (m & n) bit.bor(m, n) -- bitwise or (m | n) bit.bxor(m, n) -- bitwise xor (m ^ n) bit.brshift(n, bits) -- right shift (n >> bits) bit.blshift(n, bits) -- left shift (n << bits) bit.blogic_rshift(n, bits) -- logic right shift(zero fill >>>) Please note that bit.brshift and bit.blshift only support number within 32 bits. 2 utility functions are provided too: bit.tobits(n) -- convert n into a bit table(which is a 1/0 sequence) -- high bits first bit.tonumb(bit_tbl) -- convert a bit table into a number ------------------- Under the MIT license. copyright(c) 2006~2007 hanzhao (abrash_han@hotmail.com) --]]--------------- do ------------------------ -- bit lib implementions local function check_int(n) -- checking not float if(n - math.floor(n) > 0) then error("trying to use bitwise operation on non-integer!") end end local function to_bits(n) check_int(n) if(n < 0) then -- negative return to_bits(bit.bnot(math.abs(n)) + 1) end -- to bits table local tbl = {} local cnt = 1 while (n > 0) do local last = math.mod(n,2) if(last == 1) then tbl[cnt] = 1 else tbl[cnt] = 0 end n = (n-last)/2 cnt = cnt + 1 end return tbl end local function tbl_to_number(tbl) local n = table.getn(tbl) local rslt = 0 local power = 1 for i = 1, n do rslt = rslt + tbl[i]*power power = power*2 end return rslt end local function expand(tbl_m, tbl_n) local big = {} local small = {} if(table.getn(tbl_m) > table.getn(tbl_n)) then big = tbl_m small = tbl_n else big = tbl_n small = tbl_m end -- expand small for i = table.getn(small) + 1, table.getn(big) do small[i] = 0 end end local function bit_or(m, n) local tbl_m = to_bits(m) local tbl_n = to_bits(n) expand(tbl_m, tbl_n) local tbl = {} local rslt = math.max(table.getn(tbl_m), table.getn(tbl_n)) for i = 1, rslt do if(tbl_m[i]== 0 and tbl_n[i] == 0) then tbl[i] = 0 else tbl[i] = 1 end end return tbl_to_number(tbl) end local function bit_and(m, n) local tbl_m = to_bits(m) local tbl_n = to_bits(n) expand(tbl_m, tbl_n) local tbl = {} local rslt = math.max(table.getn(tbl_m), table.getn(tbl_n)) for i = 1, rslt do if(tbl_m[i]== 0 or tbl_n[i] == 0) then tbl[i] = 0 else tbl[i] = 1 end end return tbl_to_number(tbl) end local function bit_not(n) local tbl = to_bits(n) local size = math.max(table.getn(tbl), 32) for i = 1, size do if(tbl[i] == 1) then tbl[i] = 0 else tbl[i] = 1 end end return tbl_to_number(tbl) end local function bit_xor(m, n) local tbl_m = to_bits(m) local tbl_n = to_bits(n) expand(tbl_m, tbl_n) local tbl = {} local rslt = math.max(table.getn(tbl_m), table.getn(tbl_n)) for i = 1, rslt do if(tbl_m[i] ~= tbl_n[i]) then tbl[i] = 1 else tbl[i] = 0 end end --table.foreach(tbl, print) return tbl_to_number(tbl) end local function bit_rshift(n, bits) check_int(n) local high_bit = 0 if(n < 0) then -- negative n = bit_not(math.abs(n)) + 1 high_bit = 2147483648 -- 0x80000000 end for i=1, bits do n = n/2 n = bit_or(math.floor(n), high_bit) end return math.floor(n) end -- logic rightshift assures zero filling shift local function bit_logic_rshift(n, bits) check_int(n) if(n < 0) then -- negative n = bit_not(math.abs(n)) + 1 end for i=1, bits do n = n/2 end return math.floor(n) end local function bit_lshift(n, bits) check_int(n) if(n < 0) then -- negative n = bit_not(math.abs(n)) + 1 end for i=1, bits do n = n*2 end return bit_and(n, 4294967295) -- 0xFFFFFFFF end local function bit_xor2(m, n) local rhs = bit_or(bit_not(m), bit_not(n)) local lhs = bit_or(m, n) local rslt = bit_and(lhs, rhs) return rslt end -------------------- -- bit lib interface bit = { -- bit operations bnot = bit_not, band = bit_and, bor = bit_or, bxor = bit_xor, brshift = bit_rshift, blshift = bit_lshift, bxor2 = bit_xor2, blogic_rshift = bit_logic_rshift, -- utility func tobits = to_bits, tonumb = tbl_to_number, } end --[[ for i = 1, 100 do for j = 1, 100 do if(bit.bxor(i, j) ~= bit.bxor2(i, j)) then error("bit.xor failed.") end end end --]]