luat_lib_iconv.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. /*
  2. @module iconv
  3. @summary iconv操作
  4. @catalog 外设API
  5. @version 1.0
  6. @date 2023.03.03
  7. @demo
  8. @tag LUAT_USE_ICONV
  9. */
  10. /*
  11. * luaiconv - Performs character set conversions in Lua
  12. * (c) 2005-08 Alexandre Erwin Ittner <aittner@gmail.com>
  13. *
  14. * Permission is hereby granted, free of charge, to any person obtaining
  15. * a copy of this software and associated documentation files (the
  16. * "Software"), to deal in the Software without restriction, including
  17. * without limitation the rights to use, copy, modify, merge, publish,
  18. * distribute, sublicense, and/or sell copies of the Software, and to
  19. * permit persons to whom the Software is furnished to do so, subject to
  20. * the following conditions:
  21. *
  22. * The above copyright notice and this permission notice shall be
  23. * included in all copies or substantial portions of the Software.
  24. *
  25. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  26. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  27. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  28. * IN NO EVENT SHALL THE AUTHOR OR COPYRIGHT HOLDER BE LIABLE FOR ANY
  29. * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  30. * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  31. * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  32. *
  33. * If you use this package in a product, an acknowledgment in the product
  34. * documentation would be greatly appreciated (but it is not required).
  35. *
  36. * $Id: luaiconv.c 54 2008-05-19 00:37:56Z dermeister $
  37. *
  38. */
  39. #include "lua.h"
  40. #include "lauxlib.h"
  41. #include <stdlib.h>
  42. #include "luat_base.h"
  43. #include "luat_malloc.h"
  44. #define LIB_NAME "iconv"
  45. #define LIB_VERSION LIB_NAME " r5"
  46. #define ICONV_TYPENAME "iconv_t"
  47. /* Emulates lua_(un)boxpointer from Lua 5.0 (don't exists on Lua 5.1) */
  48. #define boxptr(L, p) (*(void**)(lua_newuserdata(L, sizeof(void*))) = (p))
  49. #define unboxptr(L, i) (*(void**)(lua_touserdata(L, i)))
  50. /* Table assumed on top */
  51. #define tblseticons(L, c, v) \
  52. lua_pushliteral(L, c); \
  53. lua_pushnumber(L, v); \
  54. lua_settable(L, -3);
  55. #define ERROR_NO_MEMORY 1
  56. #define ERROR_INVALID 2
  57. #define ERROR_INCOMPLETE 3
  58. #define ERROR_UNKNOWN 4
  59. #if 1
  60. #include "iconv.h"
  61. static void push_iconv_t(lua_State *L, iconv_t cd) {
  62. boxptr(L, cd);
  63. luaL_getmetatable(L, ICONV_TYPENAME);
  64. lua_setmetatable(L, -2);
  65. }
  66. static iconv_t get_iconv_t(lua_State *L, int i) {
  67. if (luaL_checkudata(L, i, ICONV_TYPENAME) != NULL) {
  68. iconv_t cd = unboxptr(L, i);
  69. if (cd == (iconv_t) NULL)
  70. luaL_error(L, "attempt to use an invalid " ICONV_TYPENAME);
  71. return cd;
  72. }
  73. luaL_argerror(L, i, "type not match");
  74. return NULL;
  75. }
  76. /*
  77. 打开相应字符编码转换函数
  78. @api iconv.open(tocode, fromcode)
  79. @string 释义:目标编码格式<br>取值:gb2312/ucs2/ucs2be/utf8
  80. @string 释义:源编码格式<br>取值:gb2312/ucs2/ucs2be/utf8
  81. @return table 编码转换函数的转换句柄
  82. @usage
  83. --unicode大端编码 转化为 utf8编码
  84. local cd = iconv.open("utf8", "ucs2be")
  85. */
  86. static int Liconv_open(lua_State *L) {
  87. const char *tocode = luaL_checkstring(L, 1);
  88. const char *fromcode = luaL_checkstring(L, 2);
  89. iconv_t cd = iconv_open(tocode, fromcode);
  90. if (cd != (iconv_t)(-1))
  91. push_iconv_t(L, cd); /* ok */
  92. else
  93. lua_pushnil(L); /* erro */
  94. return 1;
  95. }
  96. /*
  97. 字符编码转换
  98. @api iconv:iconv(inbuf)
  99. @string 释义:待转换字符串
  100. @return number 释义:返回编码转换后的结果<br>取值:0成功,-1失败
  101. @usage
  102. --unicode大端编码 转化为 utf8编码
  103. function ucs2beToUtf8(ucs2s)
  104. local cd = iconv.open("utf8", "ucs2be")
  105. return cd:iconv(ucs2s)
  106. end
  107. */
  108. static int Liconv(lua_State *L) {
  109. iconv_t cd = get_iconv_t(L, 1);
  110. size_t ibleft = lua_rawlen(L, 2);
  111. char *inbuf = (char*) luaL_checkstring(L, 2);
  112. char *outbuf;
  113. char *outbufs;
  114. size_t obsize = (ibleft > 256) ? ibleft : 256;
  115. size_t obleft = obsize;
  116. size_t ret = -1;
  117. int hasone = 0;
  118. outbuf = (char*) luat_heap_malloc(obsize * sizeof(char));
  119. if (outbuf == NULL) {
  120. lua_pushstring(L, "");
  121. lua_pushnumber(L, ERROR_NO_MEMORY);
  122. return 2;
  123. }
  124. outbufs = outbuf;
  125. do {
  126. ret = iconv(cd, &inbuf, &ibleft, &outbuf, &obleft);
  127. if (ret == (size_t)(-1)) {
  128. lua_pushlstring(L, outbufs, obsize - obleft);
  129. if (hasone == 1)
  130. lua_concat(L, 2);
  131. hasone = 1;
  132. // if (errno == EILSEQ) {
  133. // lua_pushnumber(L, ERROR_INVALID);
  134. // free(outbufs);
  135. // return 2; /* Invalid character sequence */
  136. // } else if (errno == EINVAL) {
  137. // lua_pushnumber(L, ERROR_INCOMPLETE);
  138. // free(outbufs);
  139. // return 2; /* Incomplete character sequence */
  140. // } else if (errno == E2BIG) {
  141. // obleft = obsize;
  142. // outbuf = outbufs;
  143. // } else {
  144. lua_pushnumber(L, ERROR_UNKNOWN);
  145. luat_heap_free(outbufs);
  146. return 2; /* Unknown error */
  147. // }
  148. }
  149. } while (ret != (size_t) 0);
  150. lua_pushlstring(L, outbufs, obsize - obleft);
  151. if (hasone == 1)
  152. lua_concat(L, 2);
  153. free(outbufs);
  154. return 1; /* Done */
  155. }
  156. #ifdef HAS_ICONVLIST /* a GNU extension? */
  157. static int push_one(unsigned int cnt, char *names[], void *data) {
  158. lua_State *L = (lua_State*) data;
  159. int n = (int) lua_tonumber(L, -1);
  160. int i;
  161. /* Stack: <tbl> n */
  162. lua_remove(L, -1);
  163. for (i = 0; i < cnt; i++) {
  164. /* Stack> <tbl> */
  165. lua_pushnumber(L, n++);
  166. lua_pushstring(L, names[i]);
  167. /* Stack: <tbl> n <str> */
  168. lua_settable(L, -3);
  169. }
  170. lua_pushnumber(L, n);
  171. /* Stack: <tbl> n */
  172. return 0;
  173. }
  174. static int Liconvlist(lua_State *L) {
  175. lua_newtable(L);
  176. lua_pushnumber(L, 1);
  177. /* Stack: <tbl> 1 */
  178. iconvlist(push_one, (void*) L);
  179. /* Stack: <tbl> n */
  180. lua_remove(L, -1);
  181. return 1;
  182. }
  183. #endif
  184. /*
  185. 关闭字符编码转换
  186. @api iconv.close(cd)
  187. @string iconv.open返回的句柄
  188. @return nil 无返回值
  189. @usage
  190. --关闭字符编码转换
  191. local cd = iconv.open("utf8", "ucs2be")
  192. iconv.close(cd)
  193. */
  194. static int Liconv_close(lua_State *L) {
  195. iconv_t cd = get_iconv_t(L, 1);
  196. if (iconv_close(cd) == 0)
  197. lua_pushboolean(L, 1); /* ok */
  198. else
  199. lua_pushnil(L); /* erro */
  200. return 1;
  201. }
  202. #include "rotable.h"
  203. static const rotable_Reg inconvFuncs[] = {
  204. { "open", Liconv_open , 0},
  205. { "new", Liconv_open , 0},
  206. { "iconv", Liconv , 0},
  207. #ifdef HAS_ICONVLIST
  208. { "list", Liconvlist , 0},
  209. #endif
  210. { "ERROR_NO_MEMORY", NULL, ERROR_NO_MEMORY},
  211. { "ERROR_INVALID", NULL, ERROR_INVALID},
  212. { "ERROR_INCOMPLETE", NULL, ERROR_INCOMPLETE},
  213. { "ERROR_UNKNOWN", NULL, ERROR_UNKNOWN},
  214. { NULL, NULL, NULL}
  215. };
  216. static const rotable_Reg iconvMT[] = {
  217. { "__gc", Liconv_close , 0},
  218. { NULL, NULL, NULL}
  219. };
  220. LUAMOD_API int luaopen_iconv(lua_State *L) {
  221. luat_newlib(L, inconvFuncs);
  222. // luaL_newmetatable(L, ICONV_TYPENAME);
  223. // lua_pushliteral(L, "__index");
  224. // rotable_newidx(L, iconvMT);
  225. // lua_settable(L, -3);
  226. // lua_pop(L, 1);
  227. luaL_newmetatable(L, ICONV_TYPENAME);
  228. lua_pushliteral(L, "__index");
  229. lua_pushvalue(L, -3);
  230. lua_settable(L, -3);
  231. lua_pushliteral(L, "__gc");
  232. lua_pushcfunction(L, Liconv_close);
  233. lua_settable(L, -3);
  234. lua_pop(L, 1);
  235. return 1;
  236. }
  237. #else
  238. #include "rotable.h"
  239. static const rotable_Reg iconvMT[] = {
  240. { NULL, NULL, NULL}
  241. };
  242. #endif