base64.lua 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. local String = require("string");
  2. local Bit = require("lockbox.util.bit");
  3. local Stream = require("lockbox.util.stream");
  4. local AND = Bit.band;
  5. local OR = Bit.bor;
  6. local NOT = Bit.bnot;
  7. local LSHIFT = Bit.lshift;
  8. local RSHIFT = Bit.rshift;
  9. local SYMBOLS = {
  10. [0]="A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P",
  11. "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f",
  12. "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v",
  13. "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "+", "/"};
  14. local LOOKUP = {};
  15. for k, v in pairs(SYMBOLS) do
  16. LOOKUP[k] = v;
  17. LOOKUP[v] = k;
  18. end
  19. local Base64 = {};
  20. Base64.fromStream = function(stream)
  21. local bits = 0x00;
  22. local bitCount = 0;
  23. local base64 = {};
  24. local byte = stream();
  25. while byte ~= nil do
  26. bits = OR(LSHIFT(bits, 8), byte);
  27. bitCount = bitCount + 8;
  28. while bitCount >= 6 do
  29. bitCount = bitCount - 6;
  30. local temp = RSHIFT(bits, bitCount);
  31. table.insert(base64, LOOKUP[temp]);
  32. bits = AND(bits, NOT(LSHIFT(0xFFFFFFFF, bitCount)));
  33. end
  34. byte = stream();
  35. end
  36. if (bitCount == 4) then
  37. bits = LSHIFT(bits, 2);
  38. table.insert(base64, LOOKUP[bits]);
  39. table.insert(base64, "=");
  40. elseif (bitCount == 2) then
  41. bits = LSHIFT(bits, 4);
  42. table.insert(base64, LOOKUP[bits]);
  43. table.insert(base64, "==");
  44. end
  45. return table.concat(base64, "");
  46. end
  47. Base64.fromArray = function(array)
  48. local ind = 0;
  49. local streamArray = function()
  50. ind = ind + 1;
  51. return array[ind];
  52. end
  53. return Base64.fromStream(streamArray);
  54. end
  55. Base64.fromString = function(string)
  56. return Base64.fromStream(Stream.fromString(string));
  57. end
  58. Base64.toStream = function(base64)
  59. local stream = coroutine.create(function()
  60. local bits = 0x00;
  61. local bitCount = 0;
  62. local yield = coroutine.yield;
  63. for c in String.gmatch(base64, ".") do
  64. if (c == "=") then
  65. bits = RSHIFT(bits, 2); bitCount = bitCount - 2;
  66. else
  67. bits = LSHIFT(bits, 6); bitCount = bitCount + 6;
  68. bits = OR(bits, LOOKUP[c]);
  69. end
  70. while(bitCount >= 8) do
  71. bitCount = bitCount - 8;
  72. local byte = RSHIFT(bits, bitCount);
  73. bits = AND(bits, NOT(LSHIFT(0xFFFFFFFF, bitCount)));
  74. yield(byte);
  75. end
  76. end
  77. end)
  78. local status = coroutine.status;
  79. return function()
  80. if status(stream) == 'dead' then return nil; end
  81. local _, byte = coroutine.resume(stream);
  82. return byte;
  83. end
  84. end
  85. Base64.toArray = function(base64)
  86. return Stream.toArray(Base64.toStream(base64));
  87. end
  88. Base64.toString = function(base64)
  89. return Stream.toString(Base64.toStream(base64));
  90. end
  91. return Base64;