erlang各种有用的函数包括一些有用nif封装,还有一些性能测试case。
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

266 lines
9.0 KiB

преди 5 години
  1. /* ex: ts=4 sw=4 et
  2. *
  3. * Copyright (c) 2011-2016 Sergey Urbanovich
  4. * http://github.com/urbanserj/cbase64-erlang-nif
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a copy
  7. * of this software and associated documentation files (the "Software"), to deal
  8. * in the Software without restriction, including without limitation the rights
  9. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. * copies of the Software, and to permit persons to whom the Software is
  11. * furnished to do so, subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be included in
  14. * all copies or substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22. * THE SOFTWARE.
  23. */
  24. #include "stdint.h"
  25. #include "erl_nif.h"
  26. #define min(X, Y) ((X) < (Y) ? (X) : (Y))
  27. #define TIMESLICE 10
  28. #define SPEEDUP 30
  29. #define REDUCTIONS 2000
  30. #define ITER (REDUCTIONS * SPEEDUP / TIMESLICE)
  31. static const char cb64[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  32. inline void encodeblock(const uint8_t in[3], uint8_t out[4], size_t len)
  33. {
  34. out[0] = cb64[ (in[0] >> 2) & 0x3f ];
  35. out[1] = cb64[ ((in[0] << 4) + (--len ? in[1] >> 4 : 0)) & 0x3f ];
  36. out[2] = len ? cb64[ ((in[1] << 2) + (--len ? in[2] >> 6 : 0)) & 0x3f ] : '=';
  37. out[3] = len ? cb64[ in[2] & 0x3f ] : '=';
  38. }
  39. static ERL_NIF_TERM encode(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
  40. {
  41. ERL_NIF_TERM tdst, tsrc;
  42. ErlNifBinary src, dst;
  43. if ( enif_inspect_binary(env, argv[0], &src) ) {
  44. tsrc = argv[0];
  45. } else if ( enif_inspect_iolist_as_binary(env, argv[0], &src) ) {
  46. tsrc = enif_make_binary(env, &src);
  47. } else {
  48. return enif_make_badarg(env);
  49. }
  50. if (src.size == 0) {
  51. return argv[0];
  52. }
  53. uint8_t *data;
  54. size_t size = (src.size + 2) / 3 * 4;
  55. if (argc == 1) {
  56. data = enif_make_new_binary(env, size, &tdst);
  57. } else {
  58. tdst = argv[1];
  59. if ( !enif_inspect_binary(env, argv[1], &dst) ) {
  60. return enif_make_badarg(env);
  61. }
  62. data = dst.data;
  63. }
  64. int i = size / 4 - 1;
  65. if (argc == 3) {
  66. if ( !enif_get_int(env, argv[2], &i) ) {
  67. return enif_make_badarg(env);
  68. }
  69. } else {
  70. /* last block */
  71. encodeblock(src.data + i * 3, data + i * 4, src.size - i * 3);
  72. i--;
  73. }
  74. int reductions = 0;
  75. for (; i >= 0; i--) {
  76. encodeblock(src.data + i * 3, data + i * 4, 3);
  77. reductions += 3;
  78. if (reductions >= ITER) {
  79. if (enif_consume_timeslice(env, TIMESLICE)) {
  80. ERL_NIF_TERM schargv[3] = {tsrc, tdst, enif_make_int(env, i)};
  81. return enif_schedule_nif(env, "encode", 0, &encode, 3, schargv);
  82. }
  83. reductions = 0;
  84. }
  85. }
  86. return tdst;
  87. }
  88. #define DECODE_ERROR 0xff
  89. #define DECODE_OK 0x00
  90. #define B64(_) \
  91. ( (_) >= 'A' && (_) <= 'Z' ? 25 - 'Z' + (_) : \
  92. (_) >= 'a' && (_) <= 'z' ? 51 - 'z' + (_) : \
  93. (_) >= '0' && (_) <= '9' ? 61 - '9' + (_) : \
  94. (_) == '+' ? 62 : (_) ? 63 : DECODE_ERROR )
  95. static const int cd64[256] = {
  96. B64( 0), B64( 1), B64( 2), B64( 3), B64( 4), B64( 5), B64( 6), B64( 7),
  97. B64( 8), B64( 9), B64( 10), B64( 11), B64( 12), B64( 13), B64( 14), B64( 15),
  98. B64( 16), B64( 17), B64( 18), B64( 19), B64( 20), B64( 21), B64( 22), B64( 23),
  99. B64( 24), B64( 25), B64( 26), B64( 27), B64( 28), B64( 29), B64( 30), B64( 31),
  100. B64( 32), B64( 33), B64( 34), B64( 35), B64( 36), B64( 37), B64( 38), B64( 39),
  101. B64( 40), B64( 41), B64( 42), B64( 43), B64( 44), B64( 45), B64( 46), B64( 47),
  102. B64( 48), B64( 49), B64( 50), B64( 51), B64( 52), B64( 53), B64( 54), B64( 55),
  103. B64( 56), B64( 57), B64( 58), B64( 59), B64( 60), B64( 61), B64( 62), B64( 63),
  104. B64( 64), B64( 65), B64( 66), B64( 67), B64( 68), B64( 69), B64( 70), B64( 71),
  105. B64( 72), B64( 73), B64( 74), B64( 75), B64( 76), B64( 77), B64( 78), B64( 79),
  106. B64( 80), B64( 81), B64( 82), B64( 83), B64( 84), B64( 85), B64( 86), B64( 87),
  107. B64( 88), B64( 89), B64( 90), B64( 91), B64( 92), B64( 93), B64( 94), B64( 95),
  108. B64( 96), B64( 97), B64( 98), B64( 99), B64(100), B64(101), B64(102), B64(103),
  109. B64(104), B64(105), B64(106), B64(107), B64(108), B64(109), B64(110), B64(111),
  110. B64(112), B64(113), B64(114), B64(115), B64(116), B64(117), B64(118), B64(119),
  111. B64(120), B64(121), B64(122), B64(123), B64(124), B64(125), B64(126), B64(127),
  112. B64(128), B64(129), B64(130), B64(131), B64(132), B64(133), B64(134), B64(135),
  113. B64(136), B64(137), B64(138), B64(139), B64(140), B64(141), B64(142), B64(143),
  114. B64(144), B64(145), B64(146), B64(147), B64(148), B64(149), B64(150), B64(151),
  115. B64(152), B64(153), B64(154), B64(155), B64(156), B64(157), B64(158), B64(159),
  116. B64(160), B64(161), B64(162), B64(163), B64(164), B64(165), B64(166), B64(167),
  117. B64(168), B64(169), B64(170), B64(171), B64(172), B64(173), B64(174), B64(175),
  118. B64(176), B64(177), B64(178), B64(179), B64(180), B64(181), B64(182), B64(183),
  119. B64(184), B64(185), B64(186), B64(187), B64(188), B64(189), B64(190), B64(191),
  120. B64(192), B64(193), B64(194), B64(195), B64(196), B64(197), B64(198), B64(199),
  121. B64(200), B64(201), B64(202), B64(203), B64(204), B64(205), B64(206), B64(207),
  122. B64(208), B64(209), B64(210), B64(211), B64(212), B64(213), B64(214), B64(215),
  123. B64(216), B64(217), B64(218), B64(219), B64(220), B64(221), B64(222), B64(223),
  124. B64(224), B64(225), B64(226), B64(227), B64(228), B64(229), B64(230), B64(231),
  125. B64(232), B64(233), B64(234), B64(235), B64(236), B64(237), B64(238), B64(239),
  126. B64(240), B64(241), B64(242), B64(243), B64(244), B64(245), B64(246), B64(247),
  127. B64(248), B64(249), B64(250), B64(251), B64(252), B64(253), B64(254), B64(255)
  128. };
  129. inline uint8_t decodeblock(const uint8_t in[4], uint8_t out[3])
  130. {
  131. int code;
  132. size_t it = 0;
  133. unsigned int val = 0;
  134. for (;it < 4; ++it) {
  135. if ( (code = cd64[in[it]]) == DECODE_ERROR )
  136. return DECODE_ERROR;
  137. val = (val << 6) + code;
  138. }
  139. out[0] = (val >> 16) & 0xff;
  140. out[1] = (val >> 8) & 0xff;
  141. out[2] = val & 0xff;
  142. return DECODE_OK;
  143. }
  144. inline uint8_t decodeblock_tail(const uint8_t in[4], uint8_t out[3])
  145. {
  146. int code;
  147. size_t it = 0;
  148. unsigned int val = 0;
  149. if ( in[0] == '=' || in[1] == '=' ||
  150. (in[2] == '=' && in[3] != '=') )
  151. return DECODE_ERROR;
  152. for (;it < 4; ++it) {
  153. val <<= 6;
  154. if ( in[it] == '=' )
  155. continue;
  156. if ( (code = cd64[in[it]]) == DECODE_ERROR )
  157. return DECODE_ERROR;
  158. val += code;
  159. }
  160. out[0] = (val >> 16) & 0xff;
  161. if ( in[2] != '=' )
  162. out[1] = (val >> 8) & 0xff;
  163. if ( in[3] != '=' )
  164. out[2] = val & 0xff;
  165. return DECODE_OK;
  166. }
  167. static ERL_NIF_TERM decode(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
  168. {
  169. ERL_NIF_TERM tdst, tsrc;
  170. ErlNifBinary src, dst;
  171. if ( enif_inspect_binary(env, argv[0], &src) ) {
  172. tsrc = argv[0];
  173. } else if ( enif_inspect_iolist_as_binary(env, argv[0], &src) ) {
  174. tsrc = enif_make_binary(env, &src);
  175. } else {
  176. return enif_make_badarg(env);
  177. }
  178. if (src.size == 0) {
  179. return argv[0];
  180. }
  181. if (src.size % 4 != 0) {
  182. return enif_make_badarg(env);
  183. }
  184. uint8_t *data;
  185. size_t size =
  186. src.size/4*3
  187. - (src.data[src.size - 1] == '=' ? 1 : 0)
  188. - (src.data[src.size - 2] == '=' ? 1 : 0);
  189. if (argc == 1) {
  190. data = enif_make_new_binary(env, size, &tdst);
  191. } else {
  192. tdst = argv[1];
  193. if ( !enif_inspect_binary(env, argv[1], &dst) ) {
  194. return enif_make_badarg(env);
  195. }
  196. data = dst.data;
  197. }
  198. int i = src.size / 4 - 1;
  199. if (argc == 3) {
  200. if ( !enif_get_int(env, argv[2], &i) ) {
  201. return enif_make_badarg(env);
  202. }
  203. } else {
  204. /* last block */
  205. if ( decodeblock_tail(src.data + i*4, data + i*3) ) {
  206. return enif_make_badarg(env);
  207. }
  208. i--;
  209. }
  210. int reductions = 0;
  211. for (; i >= 0; i--) {
  212. if ( decodeblock(src.data + i*4, data + i*3) ) {
  213. return enif_make_badarg(env);
  214. }
  215. reductions += 4;
  216. if (reductions >= ITER) {
  217. if (enif_consume_timeslice(env, TIMESLICE)) {
  218. ERL_NIF_TERM schargv[3] = {tsrc, tdst, enif_make_int(env, i)};
  219. return enif_schedule_nif(env, "decode", 0, &decode, 3, schargv);
  220. }
  221. reductions = 0;
  222. }
  223. }
  224. return tdst;
  225. }
  226. static ErlNifFunc nif_funcs[] =
  227. {
  228. {"encode", 1, encode},
  229. {"decode", 1, decode}
  230. };
  231. ERL_NIF_INIT(cbase64, nif_funcs, NULL, NULL, NULL, NULL)