NuAoA

Untitled

May 13th, 2013
170
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.96 KB | None | 0 0
  1. --- base64.lua
  2. --
  3. -- https://gist.github.com/2563975
  4. --
  5. -- V0.3 for Lua 5.1
  6. --
  7. -- A simple Base64 encoder/decoder that uses a URL safe variant of the standard.
  8. -- This implementation encodes character 62 as '-' (instead of '+') and character 63 as '_' (instead of '/').
  9. -- In addition, padding is not used by default.
  10. -- A full description of the specification can be found here: http://tools.ietf.org/html/rfc4648
  11. --
  12. -- To encode, use base64.encode(input), where input is a string of arbitrary bytes. The output is a Base64 encoded string.
  13. -- To decode, use base64.decode(input), where input is a Base64 encoded string. The output is a string of arbitrary bytes.
  14. --
  15. -- The library will throw an error on invalid input, you can catch these as such:
  16. --
  17. -- local status, result = pcall(base64.decode(invalidInput))
  18. -- if not status then
  19. -- print("Error, "..result)
  20. -- end
  21. --
  22. -- If you prefer a different Base64 variant, you can simply change the ENCODABET to your liking.
  23. -- If you wish to use padding, you can change the PAD value to a non-nil, non-empty string.
  24. -- The library will still be able to decode non-padded strings if a PAD is given.
  25. --
  26. -- For all valid input, input == base64.decode(base64.encode(input)).
  27. --
  28. -- This library has a dependency on LuaBit v0.4, which can be found here: http://luaforge.net/projects/bit/
  29. --
  30. -- Copyright (C) 2012 by Paul Moore
  31. --
  32. -- Permission is hereby granted, free of charge, to any person obtaining a copy
  33. -- of this software and associated documentation files (the "Software"), to deal
  34. -- in the Software without restriction, including without limitation the rights
  35. -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  36. -- copies of the Software, and to permit persons to whom the Software is
  37. -- furnished to do so, subject to the following conditions:
  38. --
  39. -- The above copyright notice and this permission notice shall be included in
  40. -- all copies or substantial portions of the Software.
  41. --
  42. -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  43. -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  44. -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  45. -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  46. -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  47. -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  48. -- THE SOFTWARE.
  49.  
  50. require "bit"
  51.  
  52. base64 = {}
  53.  
  54. --- octet -> char encoding.
  55. local ENCODABET = {
  56. 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
  57. 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
  58. 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
  59. 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
  60. 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
  61. 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
  62. '8', '9', '-', '_'
  63. }
  64.  
  65. --- char -> octet encoding.
  66. local DECODABET = {}
  67. for i, v in ipairs(ENCODABET) do
  68. DECODABET[v] = i - 1
  69. end
  70.  
  71. local PAD = nil
  72.  
  73. --- Converts a 6-bit octet into the associated Base64 character.
  74. --
  75. -- @param octet A 6-bit integer.
  76. -- @return The Base64 representation of the character
  77. local function toChar (octet)
  78. return assert(ENCODABET[octet + 1], "No Base64 character for octet: "..tostring(octet))
  79. end
  80.  
  81. --- Converts a Base64 character into the associated octet.
  82. --
  83. -- @param char The single Base64 character.
  84. -- @return The 6-bit integer representing the Base64 character.
  85. local function toOctet (char)
  86. return assert(DECODABET[char], "Not a valid Base64 character: "..tostring(char))
  87. end
  88.  
  89. --- Encodes a string into a Base64 string.
  90. -- The input can be any string of arbitrary bytes.
  91. -- If the input is not a string, or the string is empty, an error will be thrown.
  92. --
  93. -- @param input The input string.
  94. -- @return The Base64 representation of the input string.
  95. function base64.encode (input)
  96.  
  97. assert(type(input) == "string", "Invalid input, expected type string but got: "..tostring(input).." as a: "..type(input))
  98. assert(#input > 0, "Invalid input, cannot encode an empty string.")
  99.  
  100. local bytes = { input:byte(i, #input) }
  101.  
  102. local out = {}
  103.  
  104. -- Go through each triplet of 3 bytes, which produce 4 octets.
  105. local i = 1
  106. while i <= #bytes - 2 do
  107. local buffer = 0
  108.  
  109. -- Fill the buffer with the bytes, producing a 24-bit integer.
  110. local b = bit.blshift(bytes[i], 16)
  111. b = bit.band(b, 0xff0000)
  112. buffer = bit.bor(buffer, b)
  113.  
  114. b = bit.blshift(bytes[i + 1], 8)
  115. b = bit.band(b, 0xff00)
  116. buffer = bit.bor(buffer, b)
  117.  
  118. b = bit.band(bytes[i + 2], 0xff)
  119. buffer = bit.bor(buffer, b)
  120.  
  121. -- Read out the 4 octets into the output buffer.
  122. b = bit.blogic_rshift(buffer, 18)
  123. b = bit.band(b, 0x3f)
  124. out[#out + 1] = toChar(b)
  125.  
  126. b = bit.blogic_rshift(buffer, 12)
  127. b = bit.band(b, 0x3f)
  128. out[#out + 1] = toChar(b)
  129.  
  130. b = bit.blogic_rshift(buffer, 6)
  131. b = bit.band(b, 0x3f)
  132. out[#out + 1] = toChar(b)
  133.  
  134. b = bit.band(buffer, 0x3f)
  135. out[#out + 1] = toChar(b)
  136.  
  137. i = i + 3
  138. end
  139.  
  140. -- Special case 1: One byte extra, will produce 2 octets.
  141. if #bytes % 3 == 1 then
  142. local buffer = bit.blshift(bytes[i], 16)
  143. buffer = bit.band(buffer, 0xff0000)
  144.  
  145. local b = bit.blogic_rshift(buffer, 18)
  146. b = bit.band(b, 0x3f)
  147. out[#out + 1] = toChar(b)
  148.  
  149. b = bit.blogic_rshift(buffer, 12)
  150. b = bit.band(b, 0x3f)
  151. out[#out + 1] = toChar(b)
  152.  
  153. out[#out + 1] = PAD
  154. out[#out + 1] = PAD
  155.  
  156. -- Special case 2: Two bytes extra, will produce 3 octets.
  157. elseif #bytes % 3 == 2 then
  158. local buffer = 0
  159.  
  160. local b = bit.blshift(bytes[i], 16)
  161. b = bit.band(b, 0xff0000)
  162. buffer = bit.bor(buffer, b)
  163.  
  164. b = bit.blshift(bytes[i + 1], 8)
  165. b = bit.band(b, 0xff00)
  166. buffer = bit.bor(buffer, b)
  167.  
  168. b = bit.blogic_rshift(buffer, 18)
  169. b = bit.band(b, 0x3f)
  170. out[#out + 1] = toChar(b)
  171.  
  172. b = bit.blogic_rshift(buffer, 12)
  173. b = bit.band(b, 0x3f)
  174. out[#out + 1] = toChar(b)
  175.  
  176. b = bit.blogic_rshift(buffer, 6)
  177. b = bit.band(b, 0x3f)
  178. out[#out + 1] = toChar(b)
  179.  
  180. out[#out + 1] = PAD
  181. end
  182.  
  183. return table.concat(out)
  184.  
  185. end
  186.  
  187. --- Decodes a Base64 string into an output string of arbitrary bytes.
  188. -- 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.
  189. --
  190. -- @param input The Base64 input to decode.
  191. -- @return The decoded Base64 string, as a string of bytes.
  192. function base64.decode (input)
  193.  
  194. assert(type(input) == "string", "Invalid input, expected type string but got: "..tostring(input).." as a: "..type(input))
  195. assert(#input > 0, "Invalid input, cannot decode an empty string.")
  196.  
  197. local length = #input
  198. -- Ignore any padding.
  199. if PAD then
  200. length = input:find(PAD, 1, true) or (length + 1)
  201. length = length - 1
  202. end
  203. assert(length > 0, "Invalid input, cannot decode a padded string with no bytes: "..tostring(input))
  204.  
  205. local out = {}
  206.  
  207. -- Go through each group of 4 octets to obtain 3 bytes.
  208. local i = 1
  209. while i <= length - 3 do
  210. local buffer = 0
  211.  
  212. -- Read the 4 octets into the buffer, producing a 24-bit integer.
  213. local b = toOctet(input:sub(i, i))
  214. b = bit.blshift(b, 18)
  215. buffer = bit.bor(buffer, b)
  216. i = i + 1
  217.  
  218. b = toOctet(input:sub(i, i))
  219. b = bit.blshift(b, 12)
  220. buffer = bit.bor(buffer, b)
  221. i = i + 1
  222.  
  223. b = toOctet(input:sub(i, i))
  224. b = bit.blshift(b, 6)
  225. buffer = bit.bor(buffer, b)
  226. i = i + 1
  227.  
  228. b = toOctet(input:sub(i, i))
  229. buffer = bit.bor(buffer, b)
  230. i = i + 1
  231.  
  232. -- Append the 3 re-constructed bytes into the output buffer.
  233. b = bit.blogic_rshift(buffer, 16)
  234. b = bit.band(b, 0xff)
  235. out[#out + 1] = b
  236.  
  237. b = bit.blogic_rshift(buffer, 8)
  238. b = bit.band(b, 0xff)
  239. out[#out + 1] = b
  240.  
  241. b = bit.band(buffer, 0xff)
  242. out[#out + 1] = b
  243. end
  244.  
  245. -- Special case 1: Only 2 octets remain, producing 1 byte.
  246. if length % 4 == 2 then
  247. local buffer = 0
  248.  
  249. local b = toOctet(input:sub(i, i))
  250. b = bit.blshift(b, 18)
  251. buffer = bit.bor(buffer, b)
  252. i = i + 1
  253.  
  254. b = toOctet(input:sub(i, i))
  255. b = bit.blshift(b, 12)
  256. buffer = bit.bor(buffer, b)
  257. i = i + 1
  258.  
  259. b = bit.blogic_rshift(buffer, 16)
  260. b = bit.band(b, 0xff)
  261. out[#out + 1] = b
  262.  
  263. -- Special case 2: Only 3 octets remain, producing 2 bytes.
  264. elseif length % 4 == 3 then
  265. local buffer = 0
  266.  
  267. local b = toOctet(input:sub(i, i))
  268. b = bit.blshift(b, 18)
  269. buffer = bit.bor(buffer, b)
  270. i = i + 1
  271.  
  272. b = toOctet(input:sub(i, i))
  273. b = bit.blshift(b, 12)
  274. buffer = bit.bor(buffer, b)
  275. i = i + 1
  276.  
  277. b = toOctet(input:sub(i, i))
  278. b = bit.blshift(b, 6)
  279. buffer = bit.bor(buffer, b)
  280. i = i + 1
  281.  
  282. b = bit.blogic_rshift(buffer, 16)
  283. b = bit.band(b, 0xff)
  284. out[#out + 1] = b
  285.  
  286. b = bit.blogic_rshift(buffer, 8)
  287. b = bit.band(b, 0xff)
  288. out[#out + 1] = b
  289.  
  290. -- Special case 3: One octet remains, we can't get any bytes out of this, throw error.
  291. elseif length % 4 == 1 then
  292. error("Invalid length input string, extra character: "..tostring(input:sub(i, i)))
  293. end
  294.  
  295. return string.char(unpack(out))
  296.  
  297. end
Add Comment
Please, Sign In to add comment