Comparison

util-src/encodings.cpp @ 3882:4f88ea5f05ea

util.encodings: Support for ICU for IDNA operations.
author Tobias Markmann <tm@ayena.de>
date Tue, 14 Dec 2010 15:03:37 +0100
parent 2923:util-src/encodings.c@b7049746bd29
child 3764:323169f229fa
comparison
equal deleted inserted replaced
3881:5f3e9d7064a4 3882:4f88ea5f05ea
1 /* Prosody IM
2 -- Copyright (C) 2008-2010 Matthew Wild
3 -- Copyright (C) 2008-2010 Waqas Hussain
4 --
5 -- This project is MIT/X11 licensed. Please see the
6 -- COPYING file in the source package for more information.
7 --
8 */
9
10 /*
11 * encodings.c
12 * Lua library for base64, stringprep and idna encodings
13 */
14
15 // Newer MSVC compilers deprecate strcpy as unsafe, but we use it in a safe way
16 #define _CRT_SECURE_NO_DEPRECATE
17
18 extern "C" {
19 #include <string.h>
20 #include <stdlib.h>
21 #include "lua.h"
22 #include "lauxlib.h"
23 }
24 /***************** BASE64 *****************/
25
26 #define LUALIB_API extern "C"
27
28 static const char code[]=
29 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
30
31 static void base64_encode(luaL_Buffer *b, unsigned int c1, unsigned int c2, unsigned int c3, int n)
32 {
33 unsigned long tuple=c3+256UL*(c2+256UL*c1);
34 int i;
35 char s[4];
36 for (i=0; i<4; i++) {
37 s[3-i] = code[tuple % 64];
38 tuple /= 64;
39 }
40 for (i=n+1; i<4; i++) s[i]='=';
41 luaL_addlstring(b,s,4);
42 }
43
44 static int Lbase64_encode(lua_State *L) /** encode(s) */
45 {
46 size_t l;
47 const unsigned char *s=(const unsigned char*)luaL_checklstring(L,1,&l);
48 luaL_Buffer b;
49 int n;
50 luaL_buffinit(L,&b);
51 for (n=l/3; n--; s+=3) base64_encode(&b,s[0],s[1],s[2],3);
52 switch (l%3)
53 {
54 case 1: base64_encode(&b,s[0],0,0,1); break;
55 case 2: base64_encode(&b,s[0],s[1],0,2); break;
56 }
57 luaL_pushresult(&b);
58 return 1;
59 }
60
61 static void base64_decode(luaL_Buffer *b, int c1, int c2, int c3, int c4, int n)
62 {
63 unsigned long tuple=c4+64L*(c3+64L*(c2+64L*c1));
64 char s[3];
65 switch (--n)
66 {
67 case 3: s[2]=(char) tuple;
68 case 2: s[1]=(char) (tuple >> 8);
69 case 1: s[0]=(char) (tuple >> 16);
70 }
71 luaL_addlstring(b,s,n);
72 }
73
74 static int Lbase64_decode(lua_State *L) /** decode(s) */
75 {
76 size_t l;
77 const char *s=luaL_checklstring(L,1,&l);
78 luaL_Buffer b;
79 int n=0;
80 char t[4];
81 luaL_buffinit(L,&b);
82 for (;;)
83 {
84 int c=*s++;
85 switch (c)
86 {
87 const char *p;
88 default:
89 p=strchr(code,c); if (p==NULL) return 0;
90 t[n++]= (char) (p-code);
91 if (n==4)
92 {
93 base64_decode(&b,t[0],t[1],t[2],t[3],4);
94 n=0;
95 }
96 break;
97 case '=':
98 switch (n)
99 {
100 case 1: base64_decode(&b,t[0],0,0,0,1); break;
101 case 2: base64_decode(&b,t[0],t[1],0,0,2); break;
102 case 3: base64_decode(&b,t[0],t[1],t[2],0,3); break;
103 }
104 n=0;
105 break;
106 case 0:
107 luaL_pushresult(&b);
108 return 1;
109 case '\n': case '\r': case '\t': case ' ': case '\f': case '\b':
110 break;
111 }
112 }
113 }
114
115 static const luaL_Reg Reg_base64[] =
116 {
117 { "encode", Lbase64_encode },
118 { "decode", Lbase64_decode },
119 { NULL, NULL }
120 };
121
122 /***************** STRINGPREP *****************/
123 #ifndef USE_STRINGPREP_ICU
124 /****************** libidn ********************/
125 #include <stringprep.h>
126
127 static int stringprep_prep(lua_State *L, const Stringprep_profile *profile)
128 {
129 size_t len;
130 const char *s;
131 char string[1024];
132 int ret;
133 if(!lua_isstring(L, 1)) {
134 lua_pushnil(L);
135 return 1;
136 }
137 s = lua_tolstring(L, 1, &len);
138 if (len >= 1024) {
139 lua_pushnil(L);
140 return 1; // TODO return error message
141 }
142 strcpy(string, s);
143 ret = stringprep(string, 1024, 0, profile);
144 if (ret == STRINGPREP_OK) {
145 lua_pushstring(L, string);
146 return 1;
147 } else {
148 lua_pushnil(L);
149 return 1; // TODO return error message
150 }
151 }
152
153 #define MAKE_PREP_FUNC(myFunc, prep) \
154 static int myFunc(lua_State *L) { return stringprep_prep(L, prep); }
155
156 MAKE_PREP_FUNC(Lstringprep_nameprep, stringprep_nameprep) /** stringprep.nameprep(s) */
157 MAKE_PREP_FUNC(Lstringprep_nodeprep, stringprep_xmpp_nodeprep) /** stringprep.nodeprep(s) */
158 MAKE_PREP_FUNC(Lstringprep_resourceprep, stringprep_xmpp_resourceprep) /** stringprep.resourceprep(s) */
159 MAKE_PREP_FUNC(Lstringprep_saslprep, stringprep_saslprep) /** stringprep.saslprep(s) */
160
161 static const luaL_Reg Reg_stringprep[] =
162 {
163 { "nameprep", Lstringprep_nameprep },
164 { "nodeprep", Lstringprep_nodeprep },
165 { "resourceprep", Lstringprep_resourceprep },
166 { "saslprep", Lstringprep_saslprep },
167 { NULL, NULL }
168 };
169
170 #else
171 #include <unicode/usprep.h>
172 //#include <unicode/stringpiece.h>
173 #include <unicode/unistr.h>
174 #include <unicode/utrace.h>
175
176 static int icu_stringprep_prep(lua_State *L, const UStringPrepProfile *profile)
177 {
178 size_t len;
179 const char *s;
180 UnicodeString ustr;
181 UErrorCode err = U_ZERO_ERROR;
182 UChar dest[1024];
183 char output[1024];
184 if(!lua_isstring(L, 1)) {
185 lua_pushnil(L);
186 return 1;
187 }
188 s = lua_tolstring(L, 1, &len);
189 if (len >= 1024) {
190 lua_pushnil(L);
191 return 1; // TODO return error message
192 }
193 ustr = UnicodeString::fromUTF8(s);
194 len = usprep_prepare(profile, ustr.getBuffer(), ustr.length(), dest, 1024, 0, NULL, &err);
195 if (U_FAILURE(err)) {
196 lua_pushnil(L);
197 return 1;
198 } else {
199 CheckedArrayByteSink output_sink(output, 1024);
200 UnicodeString dest_str(TRUE, dest, len);
201 dest_str.toUTF8(output_sink);
202 lua_pushstring(L, output);
203 return 1;
204 }
205 }
206
207 UStringPrepProfile *icu_nameprep;
208 UStringPrepProfile *icu_nodeprep;
209 UStringPrepProfile *icu_resourceprep;
210 UStringPrepProfile *icu_saslprep;
211
212 /* initialize global ICU stringprep profiles */
213 void init_icu()
214 {
215 UErrorCode err = U_ZERO_ERROR;
216 utrace_setLevel(UTRACE_VERBOSE);
217 icu_nameprep = usprep_openByType(USPREP_RFC3491_NAMEPREP, &err);
218 icu_nodeprep = usprep_openByType(USPREP_RFC3920_NODEPREP, &err);
219 icu_resourceprep = usprep_openByType(USPREP_RFC3920_RESOURCEPREP, &err);
220 icu_saslprep = usprep_openByType(USPREP_RFC4013_SASLPREP, &err);
221 if (U_FAILURE(err)) fprintf(stderr, "[c] util.encodings: error: %s\n", u_errorName((UErrorCode)err));
222 }
223
224 #define MAKE_PREP_FUNC(myFunc, prep) \
225 static int myFunc(lua_State *L) { return icu_stringprep_prep(L, prep); }
226
227 MAKE_PREP_FUNC(Lstringprep_nameprep, icu_nameprep) /** stringprep.nameprep(s) */
228 MAKE_PREP_FUNC(Lstringprep_nodeprep, icu_nodeprep) /** stringprep.nodeprep(s) */
229 MAKE_PREP_FUNC(Lstringprep_resourceprep, icu_resourceprep) /** stringprep.resourceprep(s) */
230 MAKE_PREP_FUNC(Lstringprep_saslprep, icu_saslprep) /** stringprep.saslprep(s) */
231
232 static const luaL_Reg Reg_stringprep[] =
233 {
234 { "nameprep", Lstringprep_nameprep },
235 { "nodeprep", Lstringprep_nodeprep },
236 { "resourceprep", Lstringprep_resourceprep },
237 { "saslprep", Lstringprep_saslprep },
238 { NULL, NULL }
239 };
240 #endif
241
242 /***************** IDNA *****************/
243 #ifndef USE_STRINGPREP_ICU
244 /****************** libidn ********************/
245 #include <idna.h>
246 #include <idn-free.h>
247 static int Lidna_to_ascii(lua_State *L) /** idna.to_ascii(s) */
248 {
249 size_t len;
250 const char *s = luaL_checklstring(L, 1, &len);
251 char* output = NULL;
252 int ret = idna_to_ascii_8z(s, &output, IDNA_USE_STD3_ASCII_RULES);
253 if (ret == IDNA_SUCCESS) {
254 lua_pushstring(L, output);
255 idn_free(output);
256 return 1;
257 } else {
258 lua_pushnil(L);
259 idn_free(output);
260 return 1; // TODO return error message
261 }
262 }
263
264 static int Lidna_to_unicode(lua_State *L) /** idna.to_unicode(s) */
265 {
266 size_t len;
267 const char *s = luaL_checklstring(L, 1, &len);
268 char* output = NULL;
269 int ret = idna_to_unicode_8z8z(s, &output, 0);
270 if (ret == IDNA_SUCCESS) {
271 lua_pushstring(L, output);
272 idn_free(output);
273 return 1;
274 } else {
275 lua_pushnil(L);
276 idn_free(output);
277 return 1; // TODO return error message
278 }
279 }
280 #else
281 #include <unicode/ustdio.h>
282 #include <unicode/uidna.h>
283 /* IDNA2003 or IDNA2008 ? ? ? */
284 static int Lidna_to_ascii(lua_State *L) /** idna.to_ascii(s) */
285 {
286 size_t len;
287 int32_t out_len;
288 const char *s = luaL_checklstring(L, 1, &len);
289 UnicodeString ustr;
290 UErrorCode err = U_ZERO_ERROR;
291 UChar dest[1024];
292 char output[1024];
293
294 ustr = UnicodeString::fromUTF8(s);
295 out_len = uidna_IDNToASCII(ustr.getBuffer(), ustr.length(), dest, 1024, UIDNA_USE_STD3_RULES, NULL, &err);
296 if (U_FAILURE(err)) {
297 lua_pushnil(L);
298 return 1;
299 } else {
300 CheckedArrayByteSink output_sink(output, 1024);
301 UnicodeString dest_str(TRUE, dest, out_len);
302 dest_str.toUTF8(output_sink);
303 lua_pushstring(L, output);
304 return 1;
305 }
306 }
307
308 static int Lidna_to_unicode(lua_State *L) /** idna.to_unicode(s) */
309 {
310 size_t len;
311 int32_t out_len;
312 const char *s = luaL_checklstring(L, 1, &len);
313 UnicodeString ustr;
314 UErrorCode err = U_ZERO_ERROR;
315 UChar dest[1024];
316 char output[1024];
317
318 ustr = UnicodeString::fromUTF8(s);
319 out_len = uidna_IDNToUnicode(ustr.getBuffer(), ustr.length(), dest, 1024, UIDNA_USE_STD3_RULES, NULL, &err);
320 if (U_FAILURE(err)) {
321 lua_pushnil(L);
322 return 1;
323 } else {
324 CheckedArrayByteSink output_sink(output, 1024);
325 UnicodeString dest_str(TRUE, dest, out_len);
326 dest_str.toUTF8(output_sink);
327 lua_pushstring(L, output);
328 return 1;
329 }
330 }
331 #endif
332
333 static const luaL_Reg Reg_idna[] =
334 {
335 { "to_ascii", Lidna_to_ascii },
336 { "to_unicode", Lidna_to_unicode },
337 { NULL, NULL }
338 };
339
340 /***************** end *****************/
341
342 static const luaL_Reg Reg[] =
343 {
344 { NULL, NULL }
345 };
346
347 LUALIB_API int luaopen_util_encodings(lua_State *L)
348 {
349 #ifdef USE_STRINGPREP_ICU
350 init_icu();
351 #endif
352 luaL_register(L, "encodings", Reg);
353
354 lua_pushliteral(L, "base64");
355 lua_newtable(L);
356 luaL_register(L, NULL, Reg_base64);
357 lua_settable(L,-3);
358
359 lua_pushliteral(L, "stringprep");
360 lua_newtable(L);
361 luaL_register(L, NULL, Reg_stringprep);
362 lua_settable(L,-3);
363
364 lua_pushliteral(L, "idna");
365 lua_newtable(L);
366 luaL_register(L, NULL, Reg_idna);
367 lua_settable(L,-3);
368
369 lua_pushliteral(L, "version"); /** version */
370 lua_pushliteral(L, "-3.14");
371 lua_settable(L,-3);
372 return 1;
373 }