初始化提交
This commit is contained in:
		
							
								
								
									
										742
									
								
								Plugins/slua_unreal/External/luasocket/mime.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										742
									
								
								Plugins/slua_unreal/External/luasocket/mime.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,742 @@ | ||||
| /*=========================================================================*\ | ||||
| * MIME support functions | ||||
| * LuaSocket toolkit | ||||
| \*=========================================================================*/ | ||||
| #include <string.h> | ||||
|  | ||||
| #include "lua.h" | ||||
| #include "lauxlib.h" | ||||
|  | ||||
| #if !defined(LUA_VERSION_NUM) || (LUA_VERSION_NUM < 501) | ||||
| #include "compat-5.1.h" | ||||
| #endif | ||||
|  | ||||
| #include "mime.h" | ||||
|  | ||||
| #ifndef _WIN32 | ||||
| #pragma clang diagnostic push | ||||
| #pragma clang diagnostic ignored "-Wchar-subscripts" | ||||
| #endif | ||||
|  | ||||
|  | ||||
| namespace NS_SLUA {     | ||||
|  | ||||
| /*=========================================================================*\ | ||||
| * Don't want to trust escape character constants | ||||
| \*=========================================================================*/ | ||||
| typedef unsigned char UC; | ||||
| static const char CRLF[] = "\r\n"; | ||||
| static const char EQCRLF[] = "=\r\n"; | ||||
|  | ||||
| /*=========================================================================*\ | ||||
| * Internal function prototypes. | ||||
| \*=========================================================================*/ | ||||
| static int mime_global_wrp(lua_State *L); | ||||
| static int mime_global_b64(lua_State *L); | ||||
| static int mime_global_unb64(lua_State *L); | ||||
| static int mime_global_qp(lua_State *L); | ||||
| static int mime_global_unqp(lua_State *L); | ||||
| static int mime_global_qpwrp(lua_State *L); | ||||
| static int mime_global_eol(lua_State *L); | ||||
| static int mime_global_dot(lua_State *L); | ||||
|  | ||||
| static size_t dot(int c, size_t state, luaL_Buffer *buffer); | ||||
| static void b64setup(UC *base); | ||||
| static size_t b64encode(UC c, UC *input, size_t size, luaL_Buffer *buffer); | ||||
| static size_t b64pad(const UC *input, size_t size, luaL_Buffer *buffer); | ||||
| static size_t b64decode(UC c, UC *input, size_t size, luaL_Buffer *buffer); | ||||
|  | ||||
| static void qpsetup(UC *cl, UC *unbase); | ||||
| static void qpquote(UC c, luaL_Buffer *buffer); | ||||
| static size_t qpdecode(UC c, UC *input, size_t size, luaL_Buffer *buffer); | ||||
| static size_t qpencode(UC c, UC *input, size_t size,  | ||||
|         const char *marker, luaL_Buffer *buffer); | ||||
| static size_t qppad(UC *input, size_t size, luaL_Buffer *buffer); | ||||
|  | ||||
| /* code support functions */ | ||||
| static luaL_Reg mine_func[] = { | ||||
|     { "dot", mime_global_dot }, | ||||
|     { "b64", mime_global_b64 }, | ||||
|     { "eol", mime_global_eol }, | ||||
|     { "qp", mime_global_qp }, | ||||
|     { "qpwrp", mime_global_qpwrp }, | ||||
|     { "unb64", mime_global_unb64 }, | ||||
|     { "unqp", mime_global_unqp }, | ||||
|     { "wrp", mime_global_wrp }, | ||||
|     { NULL, NULL } | ||||
| }; | ||||
|  | ||||
| /*-------------------------------------------------------------------------*\ | ||||
| * Quoted-printable globals | ||||
| \*-------------------------------------------------------------------------*/ | ||||
| static UC qpclass[256]; | ||||
| static UC qpbase[] = "0123456789ABCDEF"; | ||||
| static UC qpunbase[256]; | ||||
| enum {QP_PLAIN, QP_QUOTED, QP_CR, QP_IF_LAST}; | ||||
|  | ||||
| /*-------------------------------------------------------------------------*\ | ||||
| * Base64 globals | ||||
| \*-------------------------------------------------------------------------*/ | ||||
| static const UC b64base[] = | ||||
|         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | ||||
| static UC b64unbase[256]; | ||||
|  | ||||
| /*=========================================================================*\ | ||||
| * Exported functions | ||||
| \*=========================================================================*/ | ||||
| /*-------------------------------------------------------------------------*\ | ||||
| * Initializes module | ||||
| \*-------------------------------------------------------------------------*/ | ||||
| MIME_API int luaopen_mime_core(lua_State *L) | ||||
| { | ||||
| #if LUA_VERSION_NUM > 501 && !defined(LUA_COMPAT_MODULE) | ||||
|     lua_newtable(L); | ||||
|     luaL_setfuncs(L, mine_func, 0); | ||||
| #else | ||||
|     luaL_openlib(L, "mime", mine_func, 0); | ||||
| #endif | ||||
|     /* make version string available to scripts */ | ||||
|     lua_pushstring(L, "_VERSION"); | ||||
|     lua_pushstring(L, MIME_VERSION); | ||||
|     lua_rawset(L, -3); | ||||
|     /* initialize lookup tables */ | ||||
|     qpsetup(qpclass, qpunbase); | ||||
|     b64setup(b64unbase); | ||||
|     return 1; | ||||
| } | ||||
|  | ||||
| /*=========================================================================*\ | ||||
| * Global Lua functions | ||||
| \*=========================================================================*/ | ||||
| /*-------------------------------------------------------------------------*\ | ||||
| * Incrementaly breaks a string into lines. The string can have CRLF breaks. | ||||
| * A, n = wrp(l, B, length) | ||||
| * A is a copy of B, broken into lines of at most 'length' bytes.  | ||||
| * 'l' is how many bytes are left for the first line of B.  | ||||
| * 'n' is the number of bytes left in the last line of A.  | ||||
| \*-------------------------------------------------------------------------*/ | ||||
| static int mime_global_wrp(lua_State *L) | ||||
| { | ||||
|     size_t size = 0; | ||||
|     int left = (int) luaL_checknumber(L, 1); | ||||
|     const UC *input = (UC *) luaL_optlstring(L, 2, NULL, &size); | ||||
|     const UC *last = input + size; | ||||
|     int length = (int) luaL_optnumber(L, 3, 76); | ||||
|     luaL_Buffer buffer; | ||||
|     /* end of input black-hole */ | ||||
|     if (!input) { | ||||
|         /* if last line has not been terminated, add a line break */ | ||||
|         if (left < length) lua_pushstring(L, CRLF); | ||||
|         /* otherwise, we are done */ | ||||
|         else lua_pushnil(L); | ||||
|         lua_pushnumber(L, length); | ||||
|         return 2; | ||||
|     }  | ||||
|     luaL_buffinit(L, &buffer); | ||||
|     while (input < last) { | ||||
|         switch (*input) { | ||||
|             case '\r': | ||||
|                 break; | ||||
|             case '\n': | ||||
|                 luaL_addstring(&buffer, CRLF); | ||||
|                 left = length; | ||||
|                 break; | ||||
|             default: | ||||
|                 if (left <= 0) { | ||||
|                     left = length; | ||||
|                     luaL_addstring(&buffer, CRLF); | ||||
|                 } | ||||
|                 luaL_addchar(&buffer, *input); | ||||
|                 left--; | ||||
|                 break; | ||||
|         } | ||||
|         input++; | ||||
|     } | ||||
|     luaL_pushresult(&buffer); | ||||
|     lua_pushnumber(L, left); | ||||
|     return 2; | ||||
| } | ||||
|  | ||||
| /*-------------------------------------------------------------------------*\ | ||||
| * Fill base64 decode map.  | ||||
| \*-------------------------------------------------------------------------*/ | ||||
| static void b64setup(UC *unbase)  | ||||
| { | ||||
|     int i; | ||||
|     for (i = 0; i <= 255; i++) unbase[i] = (UC) 255; | ||||
|     for (i = 0; i < 64; i++) unbase[b64base[i]] = (UC) i; | ||||
|     unbase['='] = 0; | ||||
| } | ||||
|  | ||||
| /*-------------------------------------------------------------------------*\ | ||||
| * Acumulates bytes in input buffer until 3 bytes are available.  | ||||
| * Translate the 3 bytes into Base64 form and append to buffer. | ||||
| * Returns new number of bytes in buffer. | ||||
| \*-------------------------------------------------------------------------*/ | ||||
| static size_t b64encode(UC c, UC *input, size_t size,  | ||||
|         luaL_Buffer *buffer) | ||||
| { | ||||
|     input[size++] = c; | ||||
|     if (size == 3) { | ||||
|         UC code[4]; | ||||
|         unsigned long value = 0; | ||||
|         value += input[0]; value <<= 8; | ||||
|         value += input[1]; value <<= 8; | ||||
|         value += input[2];  | ||||
|         code[3] = b64base[value & 0x3f]; value >>= 6; | ||||
|         code[2] = b64base[value & 0x3f]; value >>= 6; | ||||
|         code[1] = b64base[value & 0x3f]; value >>= 6; | ||||
|         code[0] = b64base[value]; | ||||
|         luaL_addlstring(buffer, (char *) code, 4); | ||||
|         size = 0; | ||||
|     } | ||||
|     return size; | ||||
| } | ||||
|  | ||||
| /*-------------------------------------------------------------------------*\ | ||||
| * Encodes the Base64 last 1 or 2 bytes and adds padding '='  | ||||
| * Result, if any, is appended to buffer. | ||||
| * Returns 0. | ||||
| \*-------------------------------------------------------------------------*/ | ||||
| static size_t b64pad(const UC *input, size_t size,  | ||||
|         luaL_Buffer *buffer) | ||||
| { | ||||
|     unsigned long value = 0; | ||||
|     UC code[4] = {'=', '=', '=', '='}; | ||||
|     switch (size) { | ||||
|         case 1: | ||||
|             value = input[0] << 4; | ||||
|             code[1] = b64base[value & 0x3f]; value >>= 6; | ||||
|             code[0] = b64base[value]; | ||||
|             luaL_addlstring(buffer, (char *) code, 4); | ||||
|             break; | ||||
|         case 2: | ||||
|             value = input[0]; value <<= 8;  | ||||
|             value |= input[1]; value <<= 2; | ||||
|             code[2] = b64base[value & 0x3f]; value >>= 6; | ||||
|             code[1] = b64base[value & 0x3f]; value >>= 6; | ||||
|             code[0] = b64base[value]; | ||||
|             luaL_addlstring(buffer, (char *) code, 4); | ||||
|             break; | ||||
|         default: | ||||
|             break; | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| /*-------------------------------------------------------------------------*\ | ||||
| * Acumulates bytes in input buffer until 4 bytes are available.  | ||||
| * Translate the 4 bytes from Base64 form and append to buffer. | ||||
| * Returns new number of bytes in buffer. | ||||
| \*-------------------------------------------------------------------------*/ | ||||
| static size_t b64decode(UC c, UC *input, size_t size,  | ||||
|         luaL_Buffer *buffer) | ||||
| { | ||||
|     /* ignore invalid characters */ | ||||
|     if (b64unbase[c] > 64) return size; | ||||
|     input[size++] = c; | ||||
|     /* decode atom */ | ||||
|     if (size == 4) { | ||||
|         UC decoded[3]; | ||||
|         int valid, value = 0; | ||||
|         value =  b64unbase[input[0]]; value <<= 6; | ||||
|         value |= b64unbase[input[1]]; value <<= 6; | ||||
|         value |= b64unbase[input[2]]; value <<= 6; | ||||
|         value |= b64unbase[input[3]]; | ||||
|         decoded[2] = (UC) (value & 0xff); value >>= 8; | ||||
|         decoded[1] = (UC) (value & 0xff); value >>= 8; | ||||
|         decoded[0] = (UC) value; | ||||
|         /* take care of paddding */ | ||||
|         valid = (input[2] == '=') ? 1 : (input[3] == '=') ? 2 : 3;  | ||||
|         luaL_addlstring(buffer, (char *) decoded, valid); | ||||
|         return 0; | ||||
|     /* need more data */ | ||||
|     } else return size; | ||||
| } | ||||
|  | ||||
| /*-------------------------------------------------------------------------*\ | ||||
| * Incrementally applies the Base64 transfer content encoding to a string | ||||
| * A, B = b64(C, D) | ||||
| * A is the encoded version of the largest prefix of C .. D that is | ||||
| * divisible by 3. B has the remaining bytes of C .. D, *without* encoding. | ||||
| * The easiest thing would be to concatenate the two strings and  | ||||
| * encode the result, but we can't afford that or Lua would dupplicate | ||||
| * every chunk we received. | ||||
| \*-------------------------------------------------------------------------*/ | ||||
| static int mime_global_b64(lua_State *L) | ||||
| { | ||||
|     UC atom[3]; | ||||
|     size_t isize = 0, asize = 0; | ||||
|     const UC *input = (UC *) luaL_optlstring(L, 1, NULL, &isize); | ||||
|     const UC *last = input + isize; | ||||
|     luaL_Buffer buffer; | ||||
|     /* end-of-input blackhole */ | ||||
|     if (!input) { | ||||
|         lua_pushnil(L); | ||||
|         lua_pushnil(L); | ||||
|         return 2; | ||||
|     } | ||||
|     /* make sure we don't confuse buffer stuff with arguments */ | ||||
|     lua_settop(L, 2); | ||||
|     /* process first part of the input */ | ||||
|     luaL_buffinit(L, &buffer); | ||||
|     while (input < last)  | ||||
|         asize = b64encode(*input++, atom, asize, &buffer); | ||||
|     input = (UC *) luaL_optlstring(L, 2, NULL, &isize); | ||||
|     /* if second part is nil, we are done */ | ||||
|     if (!input) { | ||||
|         size_t osize = 0; | ||||
|         asize = b64pad(atom, asize, &buffer); | ||||
|         luaL_pushresult(&buffer); | ||||
|         /* if the output is empty  and the input is nil, return nil */ | ||||
|         lua_tolstring(L, -1, &osize); | ||||
|         if (osize == 0) lua_pushnil(L); | ||||
|         lua_pushnil(L); | ||||
|         return 2; | ||||
|     } | ||||
|     /* otherwise process the second part */ | ||||
|     last = input + isize; | ||||
|     while (input < last)  | ||||
|         asize = b64encode(*input++, atom, asize, &buffer); | ||||
|     luaL_pushresult(&buffer); | ||||
|     lua_pushlstring(L, (char *) atom, asize); | ||||
|     return 2; | ||||
| } | ||||
|  | ||||
| /*-------------------------------------------------------------------------*\ | ||||
| * Incrementally removes the Base64 transfer content encoding from a string | ||||
| * A, B = b64(C, D) | ||||
| * A is the encoded version of the largest prefix of C .. D that is | ||||
| * divisible by 4. B has the remaining bytes of C .. D, *without* encoding. | ||||
| \*-------------------------------------------------------------------------*/ | ||||
| static int mime_global_unb64(lua_State *L) | ||||
| { | ||||
|     UC atom[4]; | ||||
|     size_t isize = 0, asize = 0; | ||||
|     const UC *input = (UC *) luaL_optlstring(L, 1, NULL, &isize); | ||||
|     const UC *last = input + isize; | ||||
|     luaL_Buffer buffer; | ||||
|     /* end-of-input blackhole */ | ||||
|     if (!input) { | ||||
|         lua_pushnil(L); | ||||
|         lua_pushnil(L); | ||||
|         return 2; | ||||
|     } | ||||
|     /* make sure we don't confuse buffer stuff with arguments */ | ||||
|     lua_settop(L, 2); | ||||
|     /* process first part of the input */ | ||||
|     luaL_buffinit(L, &buffer); | ||||
|     while (input < last)  | ||||
|         asize = b64decode(*input++, atom, asize, &buffer); | ||||
|     input = (UC *) luaL_optlstring(L, 2, NULL, &isize); | ||||
|     /* if second is nil, we are done */ | ||||
|     if (!input) { | ||||
|         size_t osize = 0; | ||||
|         luaL_pushresult(&buffer); | ||||
|         /* if the output is empty  and the input is nil, return nil */ | ||||
|         lua_tolstring(L, -1, &osize); | ||||
|         if (osize == 0) lua_pushnil(L); | ||||
|         lua_pushnil(L); | ||||
|         return 2; | ||||
|     } | ||||
|     /* otherwise, process the rest of the input */ | ||||
|     last = input + isize; | ||||
|     while (input < last)  | ||||
|         asize = b64decode(*input++, atom, asize, &buffer); | ||||
|     luaL_pushresult(&buffer); | ||||
|     lua_pushlstring(L, (char *) atom, asize); | ||||
|     return 2; | ||||
| } | ||||
|  | ||||
| /*-------------------------------------------------------------------------*\ | ||||
| * Quoted-printable encoding scheme | ||||
| * all (except CRLF in text) can be =XX | ||||
| * CLRL in not text must be =XX=XX | ||||
| * 33 through 60 inclusive can be plain | ||||
| * 62 through 126 inclusive can be plain | ||||
| * 9 and 32 can be plain, unless in the end of a line, where must be =XX | ||||
| * encoded lines must be no longer than 76 not counting CRLF | ||||
| * soft line-break are =CRLF | ||||
| * To encode one byte, we need to see the next two.  | ||||
| * Worst case is when we see a space, and wonder if a CRLF is comming | ||||
| \*-------------------------------------------------------------------------*/ | ||||
| /*-------------------------------------------------------------------------*\ | ||||
| * Split quoted-printable characters into classes | ||||
| * Precompute reverse map for encoding | ||||
| \*-------------------------------------------------------------------------*/ | ||||
| static void qpsetup(UC *cl, UC *unbase) | ||||
| { | ||||
|     int i; | ||||
|     for (i = 0; i < 256; i++) cl[i] = QP_QUOTED; | ||||
|     for (i = 33; i <= 60; i++) cl[i] = QP_PLAIN; | ||||
|     for (i = 62; i <= 126; i++) cl[i] = QP_PLAIN; | ||||
|     cl['\t'] = QP_IF_LAST;  | ||||
|     cl[' '] = QP_IF_LAST; | ||||
|     cl['\r'] = QP_CR; | ||||
|     for (i = 0; i < 256; i++) unbase[i] = 255; | ||||
|     unbase['0'] = 0; unbase['1'] = 1; unbase['2'] = 2; | ||||
|     unbase['3'] = 3; unbase['4'] = 4; unbase['5'] = 5; | ||||
|     unbase['6'] = 6; unbase['7'] = 7; unbase['8'] = 8; | ||||
|     unbase['9'] = 9; unbase['A'] = 10; unbase['a'] = 10; | ||||
|     unbase['B'] = 11; unbase['b'] = 11; unbase['C'] = 12; | ||||
|     unbase['c'] = 12; unbase['D'] = 13; unbase['d'] = 13; | ||||
|     unbase['E'] = 14; unbase['e'] = 14; unbase['F'] = 15; | ||||
|     unbase['f'] = 15; | ||||
| } | ||||
|  | ||||
| /*-------------------------------------------------------------------------*\ | ||||
| * Output one character in form =XX | ||||
| \*-------------------------------------------------------------------------*/ | ||||
| static void qpquote(UC c, luaL_Buffer *buffer) | ||||
| { | ||||
|     luaL_addchar(buffer, '='); | ||||
|     luaL_addchar(buffer, qpbase[c >> 4]); | ||||
|     luaL_addchar(buffer, qpbase[c & 0x0F]); | ||||
| } | ||||
|  | ||||
| /*-------------------------------------------------------------------------*\ | ||||
| * Accumulate characters until we are sure about how to deal with them. | ||||
| * Once we are sure, output to the buffer, in the correct form.  | ||||
| \*-------------------------------------------------------------------------*/ | ||||
| static size_t qpencode(UC c, UC *input, size_t size,  | ||||
|         const char *marker, luaL_Buffer *buffer) | ||||
| { | ||||
|     input[size++] = c; | ||||
|     /* deal with all characters we can have */ | ||||
|     while (size > 0) { | ||||
|         switch (qpclass[input[0]]) { | ||||
|             /* might be the CR of a CRLF sequence */ | ||||
|             case QP_CR: | ||||
|                 if (size < 2) return size; | ||||
|                 if (input[1] == '\n') { | ||||
|                     luaL_addstring(buffer, marker); | ||||
|                     return 0; | ||||
|                 } else qpquote(input[0], buffer); | ||||
|                 break; | ||||
|             /* might be a space and that has to be quoted if last in line */ | ||||
|             case QP_IF_LAST: | ||||
|                 if (size < 3) return size; | ||||
|                 /* if it is the last, quote it and we are done */ | ||||
|                 if (input[1] == '\r' && input[2] == '\n') { | ||||
|                     qpquote(input[0], buffer); | ||||
|                     luaL_addstring(buffer, marker); | ||||
|                     return 0; | ||||
|                 } else luaL_addchar(buffer, input[0]); | ||||
|                 break; | ||||
|                 /* might have to be quoted always */ | ||||
|             case QP_QUOTED: | ||||
|                 qpquote(input[0], buffer); | ||||
|                 break; | ||||
|                 /* might never have to be quoted */ | ||||
|             default: | ||||
|                 luaL_addchar(buffer, input[0]); | ||||
|                 break; | ||||
|         } | ||||
|         input[0] = input[1]; input[1] = input[2]; | ||||
|         size--; | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| /*-------------------------------------------------------------------------*\ | ||||
| * Deal with the final characters  | ||||
| \*-------------------------------------------------------------------------*/ | ||||
| static size_t qppad(UC *input, size_t size, luaL_Buffer *buffer) | ||||
| { | ||||
|     size_t i; | ||||
|     for (i = 0; i < size; i++) { | ||||
|         if (qpclass[input[i]] == QP_PLAIN) luaL_addchar(buffer, input[i]); | ||||
|         else qpquote(input[i], buffer); | ||||
|     } | ||||
|     if (size > 0) luaL_addstring(buffer, EQCRLF); | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| /*-------------------------------------------------------------------------*\ | ||||
| * Incrementally converts a string to quoted-printable | ||||
| * A, B = qp(C, D, marker) | ||||
| * Marker is the text to be used to replace CRLF sequences found in A. | ||||
| * A is the encoded version of the largest prefix of C .. D that  | ||||
| * can be encoded without doubts.  | ||||
| * B has the remaining bytes of C .. D, *without* encoding. | ||||
| \*-------------------------------------------------------------------------*/ | ||||
| static int mime_global_qp(lua_State *L) | ||||
| { | ||||
|  | ||||
|     size_t asize = 0, isize = 0; | ||||
|     UC atom[3]; | ||||
|     const UC *input = (UC *) luaL_optlstring(L, 1, NULL, &isize); | ||||
|     const UC *last = input + isize; | ||||
|     const char *marker = luaL_optstring(L, 3, CRLF); | ||||
|     luaL_Buffer buffer; | ||||
|     /* end-of-input blackhole */ | ||||
|     if (!input) { | ||||
|         lua_pushnil(L); | ||||
|         lua_pushnil(L); | ||||
|         return 2; | ||||
|     } | ||||
|     /* make sure we don't confuse buffer stuff with arguments */ | ||||
|     lua_settop(L, 3); | ||||
|     /* process first part of input */ | ||||
|     luaL_buffinit(L, &buffer); | ||||
|     while (input < last) | ||||
|         asize = qpencode(*input++, atom, asize, marker, &buffer); | ||||
|     input = (UC *) luaL_optlstring(L, 2, NULL, &isize); | ||||
|     /* if second part is nil, we are done */ | ||||
|     if (!input) { | ||||
|         asize = qppad(atom, asize, &buffer); | ||||
|         luaL_pushresult(&buffer); | ||||
|         if (!(*lua_tostring(L, -1))) lua_pushnil(L); | ||||
|         lua_pushnil(L); | ||||
|         return 2; | ||||
|     } | ||||
|     /* otherwise process rest of input */ | ||||
|     last = input + isize; | ||||
|     while (input < last) | ||||
|         asize = qpencode(*input++, atom, asize, marker, &buffer); | ||||
|     luaL_pushresult(&buffer); | ||||
|     lua_pushlstring(L, (char *) atom, asize); | ||||
|     return 2; | ||||
| } | ||||
|  | ||||
| /*-------------------------------------------------------------------------*\ | ||||
| * Accumulate characters until we are sure about how to deal with them. | ||||
| * Once we are sure, output the to the buffer, in the correct form.  | ||||
| \*-------------------------------------------------------------------------*/ | ||||
| static size_t qpdecode(UC c, UC *input, size_t size, luaL_Buffer *buffer) { | ||||
|     int d; | ||||
|     input[size++] = c; | ||||
|     /* deal with all characters we can deal */ | ||||
|     switch (input[0]) { | ||||
|         /* if we have an escape character */ | ||||
|         case '=':  | ||||
|             if (size < 3) return size;  | ||||
|             /* eliminate soft line break */ | ||||
|             if (input[1] == '\r' && input[2] == '\n') return 0; | ||||
|             /* decode quoted representation */ | ||||
|             c = qpunbase[input[1]]; d = qpunbase[input[2]]; | ||||
|             /* if it is an invalid, do not decode */ | ||||
|             if (c > 15 || d > 15) luaL_addlstring(buffer, (char *)input, 3); | ||||
|             else luaL_addchar(buffer, (char) ((c << 4) + d)); | ||||
|             return 0; | ||||
|         case '\r': | ||||
|             if (size < 2) return size;  | ||||
|             if (input[1] == '\n') luaL_addlstring(buffer, (char *)input, 2); | ||||
|             return 0; | ||||
|         default: | ||||
|             if (input[0] == '\t' || (input[0] > 31 && input[0] < 127)) | ||||
|                 luaL_addchar(buffer, input[0]); | ||||
|             return 0; | ||||
|     } | ||||
| } | ||||
|  | ||||
| /*-------------------------------------------------------------------------*\ | ||||
| * Incrementally decodes a string in quoted-printable | ||||
| * A, B = qp(C, D) | ||||
| * A is the decoded version of the largest prefix of C .. D that  | ||||
| * can be decoded without doubts.  | ||||
| * B has the remaining bytes of C .. D, *without* decoding. | ||||
| \*-------------------------------------------------------------------------*/ | ||||
| static int mime_global_unqp(lua_State *L) | ||||
| { | ||||
|     size_t asize = 0, isize = 0; | ||||
|     UC atom[3]; | ||||
|     const UC *input = (UC *) luaL_optlstring(L, 1, NULL, &isize); | ||||
|     const UC *last = input + isize; | ||||
|     luaL_Buffer buffer; | ||||
|     /* end-of-input blackhole */ | ||||
|     if (!input) { | ||||
|         lua_pushnil(L); | ||||
|         lua_pushnil(L); | ||||
|         return 2; | ||||
|     } | ||||
|     /* make sure we don't confuse buffer stuff with arguments */ | ||||
|     lua_settop(L, 2); | ||||
|     /* process first part of input */ | ||||
|     luaL_buffinit(L, &buffer); | ||||
|     while (input < last) | ||||
|         asize = qpdecode(*input++, atom, asize, &buffer); | ||||
|     input = (UC *) luaL_optlstring(L, 2, NULL, &isize); | ||||
|     /* if second part is nil, we are done */ | ||||
|     if (!input) { | ||||
|         luaL_pushresult(&buffer); | ||||
|         if (!(*lua_tostring(L, -1))) lua_pushnil(L); | ||||
|         lua_pushnil(L); | ||||
|         return 2; | ||||
|     }  | ||||
|     /* otherwise process rest of input */ | ||||
|     last = input + isize; | ||||
|     while (input < last) | ||||
|         asize = qpdecode(*input++, atom, asize, &buffer); | ||||
|     luaL_pushresult(&buffer); | ||||
|     lua_pushlstring(L, (char *) atom, asize); | ||||
|     return 2; | ||||
| } | ||||
|  | ||||
| /*-------------------------------------------------------------------------*\ | ||||
| * Incrementally breaks a quoted-printed string into lines | ||||
| * A, n = qpwrp(l, B, length) | ||||
| * A is a copy of B, broken into lines of at most 'length' bytes.  | ||||
| * 'l' is how many bytes are left for the first line of B.  | ||||
| * 'n' is the number of bytes left in the last line of A.  | ||||
| * There are two complications: lines can't be broken in the middle | ||||
| * of an encoded =XX, and there might be line breaks already | ||||
| \*-------------------------------------------------------------------------*/ | ||||
| static int mime_global_qpwrp(lua_State *L) | ||||
| { | ||||
|     size_t size = 0; | ||||
|     int left = (int) luaL_checknumber(L, 1); | ||||
|     const UC *input = (UC *) luaL_optlstring(L, 2, NULL, &size); | ||||
|     const UC *last = input + size; | ||||
|     int length = (int) luaL_optnumber(L, 3, 76); | ||||
|     luaL_Buffer buffer; | ||||
|     /* end-of-input blackhole */ | ||||
|     if (!input) { | ||||
|         if (left < length) lua_pushstring(L, EQCRLF); | ||||
|         else lua_pushnil(L); | ||||
|         lua_pushnumber(L, length); | ||||
|         return 2; | ||||
|     } | ||||
|     /* process all input */ | ||||
|     luaL_buffinit(L, &buffer); | ||||
|     while (input < last) { | ||||
|         switch (*input) { | ||||
|             case '\r': | ||||
|                 break; | ||||
|             case '\n': | ||||
|                 left = length; | ||||
|                 luaL_addstring(&buffer, CRLF); | ||||
|                 break; | ||||
|             case '=': | ||||
|                 if (left <= 3) { | ||||
|                     left = length; | ||||
|                     luaL_addstring(&buffer, EQCRLF); | ||||
|                 }  | ||||
|                 luaL_addchar(&buffer, *input); | ||||
|                 left--; | ||||
|                 break; | ||||
|             default:  | ||||
|                 if (left <= 1) { | ||||
|                     left = length; | ||||
|                     luaL_addstring(&buffer, EQCRLF); | ||||
|                 } | ||||
|                 luaL_addchar(&buffer, *input); | ||||
|                 left--; | ||||
|                 break; | ||||
|         } | ||||
|         input++; | ||||
|     } | ||||
|     luaL_pushresult(&buffer); | ||||
|     lua_pushnumber(L, left); | ||||
|     return 2; | ||||
| } | ||||
|  | ||||
| /*-------------------------------------------------------------------------*\ | ||||
| * Here is what we do: \n, and \r are considered candidates for line | ||||
| * break. We issue *one* new line marker if any of them is seen alone, or | ||||
| * followed by a different one. That is, \n\n and \r\r will issue two | ||||
| * end of line markers each, but \r\n, \n\r etc will only issue *one* | ||||
| * marker.  This covers Mac OS, Mac OS X, VMS, Unix and DOS, as well as | ||||
| * probably other more obscure conventions. | ||||
| * | ||||
| * c is the current character being processed | ||||
| * last is the previous character | ||||
| \*-------------------------------------------------------------------------*/ | ||||
| #define eolcandidate(c) (c == '\r' || c == '\n') | ||||
| static int eolprocess(int c, int last, const char *marker,  | ||||
|         luaL_Buffer *buffer) | ||||
| { | ||||
|     if (eolcandidate(c)) { | ||||
|         if (eolcandidate(last)) { | ||||
|             if (c == last) luaL_addstring(buffer, marker); | ||||
|             return 0; | ||||
|         } else { | ||||
|             luaL_addstring(buffer, marker); | ||||
|             return c; | ||||
|         } | ||||
|     } else { | ||||
|         luaL_addchar(buffer, (char) c); | ||||
|         return 0; | ||||
|     } | ||||
| } | ||||
|  | ||||
| /*-------------------------------------------------------------------------*\ | ||||
| * Converts a string to uniform EOL convention.  | ||||
| * A, n = eol(o, B, marker) | ||||
| * A is the converted version of the largest prefix of B that can be | ||||
| * converted unambiguously. 'o' is the context returned by the previous  | ||||
| * call. 'n' is the new context. | ||||
| \*-------------------------------------------------------------------------*/ | ||||
| static int mime_global_eol(lua_State *L) | ||||
| { | ||||
|     int ctx = luaL_checkinteger(L, 1); | ||||
|     size_t isize = 0; | ||||
|     const char *input = luaL_optlstring(L, 2, NULL, &isize); | ||||
|     const char *last = input + isize; | ||||
|     const char *marker = luaL_optstring(L, 3, CRLF); | ||||
|     luaL_Buffer buffer; | ||||
|     luaL_buffinit(L, &buffer); | ||||
|     /* end of input blackhole */ | ||||
|     if (!input) { | ||||
|        lua_pushnil(L); | ||||
|        lua_pushnumber(L, 0); | ||||
|        return 2; | ||||
|     } | ||||
|     /* process all input */ | ||||
|     while (input < last) | ||||
|         ctx = eolprocess(*input++, ctx, marker, &buffer); | ||||
|     luaL_pushresult(&buffer); | ||||
|     lua_pushnumber(L, ctx); | ||||
|     return 2; | ||||
| } | ||||
|  | ||||
| /*-------------------------------------------------------------------------*\ | ||||
| * Takes one byte and stuff it if needed.  | ||||
| \*-------------------------------------------------------------------------*/ | ||||
| static size_t dot(int c, size_t state, luaL_Buffer *buffer) | ||||
| { | ||||
|     luaL_addchar(buffer, (char) c); | ||||
|     switch (c) { | ||||
|         case '\r':  | ||||
|             return 1; | ||||
|         case '\n':  | ||||
|             return (state == 1)? 2: 0;  | ||||
|         case '.':   | ||||
|             if (state == 2)  | ||||
|                 luaL_addchar(buffer, '.'); | ||||
|         default: | ||||
|             return 0; | ||||
|     } | ||||
| } | ||||
|  | ||||
| /*-------------------------------------------------------------------------*\ | ||||
| * Incrementally applies smtp stuffing to a string | ||||
| * A, n = dot(l, D) | ||||
| \*-------------------------------------------------------------------------*/ | ||||
| static int mime_global_dot(lua_State *L) | ||||
| { | ||||
|     size_t isize = 0, state = (size_t) luaL_checknumber(L, 1); | ||||
|     const char *input = luaL_optlstring(L, 2, NULL, &isize); | ||||
|     const char *last = input + isize; | ||||
|     luaL_Buffer buffer; | ||||
|     /* end-of-input blackhole */ | ||||
|     if (!input) { | ||||
|         lua_pushnil(L); | ||||
|         lua_pushnumber(L, 2); | ||||
|         return 2; | ||||
|     } | ||||
|     /* process all input */ | ||||
|     luaL_buffinit(L, &buffer); | ||||
|     while (input < last)  | ||||
|         state = dot(*input++, state, &buffer); | ||||
|     luaL_pushresult(&buffer); | ||||
|     lua_pushnumber(L, (lua_Number) state); | ||||
|     return 2; | ||||
| } | ||||
|  | ||||
|  | ||||
| } // end NS_SLUA | ||||
|  | ||||
| #ifndef _WIN32 | ||||
| #pragma clang diagnostic pop | ||||
| #endif | ||||
		Reference in New Issue
	
	Block a user