MIRROR: javascript for 馃悳's, a tiny runtime with big ambitions
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at master 286 lines 8.9 kB view raw
1#include <stdlib.h> 2#include <string.h> 3#include <stdint.h> 4#include <stdbool.h> 5 6#include "ant.h" 7#include "ptr.h" 8#include "base64.h" 9#include "errors.h" 10#include "internal.h" 11#include "descriptors.h" 12 13#include "modules/buffer.h" 14#include "modules/symbol.h" 15#include "modules/textcodec.h" 16#include "modules/string_decoder.h" 17 18#define SD_ENC_UTF8 0 19#define SD_ENC_UTF16LE 1 20#define SD_ENC_UTF16BE 2 21#define SD_ENC_LATIN1 3 22#define SD_ENC_HEX 4 23#define SD_ENC_BASE64 5 24 25typedef struct { 26 int encoding; 27 td_state_t *td; 28 uint8_t pending[2]; 29 int pending_len; 30} sd_state_t; 31 32static ant_value_t g_string_decoder_proto = 0; 33 34enum { STRING_DECODER_NATIVE_TAG = 0x53444543u }; // SDEC 35 36static sd_state_t *sd_get_state(ant_value_t obj) { 37 return (sd_state_t *)js_get_native(obj, STRING_DECODER_NATIVE_TAG); 38} 39 40static void sd_finalize(ant_t *js, ant_object_t *obj) { 41 ant_value_t value = js_obj_from_ptr(obj); 42 sd_state_t *st = (sd_state_t *)js_get_native(value, STRING_DECODER_NATIVE_TAG); 43 if (st) { free(st->td); free(st); } 44 js_clear_native(value, STRING_DECODER_NATIVE_TAG); 45} 46 47static int sd_parse_encoding(const char *s, size_t len) { 48 static const struct { const char *label; uint8_t llen; int enc; } map[] = { 49 {"utf8", 4, SD_ENC_UTF8}, 50 {"utf-8", 5, SD_ENC_UTF8}, 51 {"utf16le", 7, SD_ENC_UTF16LE}, 52 {"utf-16le", 8, SD_ENC_UTF16LE}, 53 {"ucs2", 4, SD_ENC_UTF16LE}, 54 {"ucs-2", 5, SD_ENC_UTF16LE}, 55 {"latin1", 6, SD_ENC_LATIN1}, 56 {"binary", 6, SD_ENC_LATIN1}, 57 {"ascii", 5, SD_ENC_LATIN1}, 58 {"hex", 3, SD_ENC_HEX}, 59 {"base64", 6, SD_ENC_BASE64}, 60 {"base64url", 9, SD_ENC_BASE64}, 61 {NULL, 0, 0} 62 }; 63 for (int i = 0; map[i].label; i++) { 64 if (len == map[i].llen && strncasecmp(s, map[i].label, len) == 0) 65 return map[i].enc; 66 } 67 return SD_ENC_UTF8; 68} 69 70static const char *sd_encoding_name(int enc) { 71switch (enc) { 72 case SD_ENC_UTF16LE: return "utf-16le"; 73 case SD_ENC_LATIN1: return "latin1"; 74 case SD_ENC_HEX: return "hex"; 75 case SD_ENC_BASE64: return "base64"; 76 default: return "utf-8"; 77}} 78 79static ant_value_t sd_latin1_to_str(ant_t *js, const uint8_t *src, size_t len) { 80 char *out = malloc(len * 2 + 1); 81 if (!out) return js_mkerr(js, "out of memory"); 82 size_t o = 0; 83 84 for (size_t i = 0; i < len; i++) { 85 uint8_t b = src[i]; 86 87 if (b < 0x80) out[o++] = (char)b; 88 else { 89 out[o++] = (char)(0xC0 | (b >> 6)); 90 out[o++] = (char)(0x80 | (b & 0x3F)); 91 }} 92 93 ant_value_t result = js_mkstr(js, out, o); 94 free(out); 95 96 return result; 97} 98 99static ant_value_t sd_hex_decode(ant_t *js, const uint8_t *src, size_t len) { 100 static const char hex[] = "0123456789abcdef"; 101 if (len == 0) return js_mkstr(js, "", 0); 102 103 char *out = malloc(len * 2 + 1); 104 if (!out) return js_mkerr(js, "out of memory"); 105 for (size_t i = 0; i < len; i++) { 106 out[i*2] = hex[(src[i] >> 4) & 0xF]; 107 out[i*2+1] = hex[src[i] & 0xF]; 108 } 109 110 ant_value_t result = js_mkstr(js, out, len * 2); 111 free(out); 112 113 return result; 114} 115 116static ant_value_t sd_base64_write(ant_t *js, sd_state_t *st, const uint8_t *src, size_t len, bool flush) { 117 size_t total = (size_t)st->pending_len + len; 118 if (total == 0) return js_mkstr(js, "", 0); 119 120 uint8_t *work = malloc(total); 121 if (!work) return js_mkerr(js, "out of memory"); 122 123 if (st->pending_len > 0) 124 memcpy(work, st->pending, (size_t)st->pending_len); 125 if (src && len > 0) 126 memcpy(work + st->pending_len, src, len); 127 128 size_t encode_len = flush ? total : (total / 3) * 3; 129 int new_pending = (int)(total - encode_len); 130 131 ant_value_t result; 132 if (encode_len == 0) result = js_mkstr(js, "", 0); else { 133 size_t out_len; 134 char *out = ant_base64_encode(work, encode_len, &out_len); 135 if (!out) { free(work); return js_mkerr(js, "out of memory"); } 136 result = js_mkstr(js, out, out_len); 137 free(out); 138 } 139 140 st->pending_len = new_pending; 141 if (new_pending > 0) 142 memcpy(st->pending, work + encode_len, (size_t)new_pending); 143 144 free(work); 145 return result; 146} 147 148static ant_value_t sd_do_write(ant_t *js, sd_state_t *st, const uint8_t *src, size_t len, bool flush) { 149switch (st->encoding) { 150 case SD_ENC_UTF8: 151 case SD_ENC_UTF16LE: 152 case SD_ENC_UTF16BE: 153 return td_decode(js, st->td, src, len, !flush); 154 case SD_ENC_LATIN1: 155 if (!src || len == 0) return js_mkstr(js, "", 0); 156 return sd_latin1_to_str(js, src, len); 157 case SD_ENC_HEX: 158 if (!src || len == 0) return js_mkstr(js, "", 0); 159 return sd_hex_decode(js, src, len); 160 case SD_ENC_BASE64: 161 return sd_base64_write(js, st, src, len, flush); 162 default: 163 return js_mkstr(js, "", 0); 164}} 165 166static ant_value_t js_sd_get_encoding(ant_t *js, ant_value_t *args, int nargs) { 167 sd_state_t *st = sd_get_state(js->this_val); 168 if (!st) return js_mkstr(js, "utf-8", 5); 169 const char *name = sd_encoding_name(st->encoding); 170 return js_mkstr(js, name, strlen(name)); 171} 172 173static ant_value_t js_sd_write(ant_t *js, ant_value_t *args, int nargs) { 174 sd_state_t *st = sd_get_state(js->this_val); 175 176 if (!st) return js_mkerr_typed(js, JS_ERR_TYPE, "Invalid StringDecoder"); 177 if (nargs < 1) return js_mkstr(js, "", 0); 178 179 if (vtype(args[0]) == T_STR) { 180 size_t slen; 181 const char *s = js_getstr(js, args[0], &slen); 182 return s ? js_mkstr(js, s, slen) : js_mkstr(js, "", 0); 183 } 184 185 const uint8_t *src = NULL; 186 size_t len = 0; 187 if (is_object_type(args[0])) 188 buffer_source_get_bytes(js, args[0], &src, &len); 189 190 return sd_do_write(js, st, src, len, false); 191} 192 193static ant_value_t js_sd_end(ant_t *js, ant_value_t *args, int nargs) { 194 sd_state_t *st = sd_get_state(js->this_val); 195 if (!st) return js_mkerr_typed(js, JS_ERR_TYPE, "Invalid StringDecoder"); 196 197 const uint8_t *src = NULL; 198 size_t len = 0; 199 if (nargs > 0 && is_object_type(args[0])) 200 buffer_source_get_bytes(js, args[0], &src, &len); 201 202 return sd_do_write(js, st, src, len, true); 203} 204 205ant_value_t string_decoder_create(ant_t *js, ant_value_t encoding) { 206 int enc = SD_ENC_UTF8; 207 if (!is_undefined(encoding)) { 208 ant_value_t label_val = (vtype(encoding) == T_STR) ? encoding : coerce_to_str(js, encoding); 209 if (!is_err(label_val) && vtype(label_val) == T_STR) { 210 size_t llen; 211 const char *label = js_getstr(js, label_val, &llen); 212 if (label) enc = sd_parse_encoding(label, llen); 213 }} 214 215 sd_state_t *st = calloc(1, sizeof(sd_state_t)); 216 if (!st) return js_mkerr(js, "out of memory"); 217 st->encoding = enc; 218 219 if (enc == SD_ENC_UTF8 || enc == SD_ENC_UTF16LE || enc == SD_ENC_UTF16BE) { 220 td_encoding_t td_enc = (enc == SD_ENC_UTF16LE) ? TD_ENC_UTF16LE : (enc == SD_ENC_UTF16BE) ? TD_ENC_UTF16BE : TD_ENC_UTF8; 221 st->td = td_state_new(td_enc, false, false); 222 if (!st->td) { free(st); return js_mkerr(js, "out of memory"); } 223 } 224 225 ant_value_t obj = js_mkobj(js); 226 ant_value_t proto = js_instance_proto_from_new_target(js, g_string_decoder_proto); 227 228 if (is_object_type(proto)) js_set_proto_init(obj, proto); 229 js_set_native(obj, st, STRING_DECODER_NATIVE_TAG); 230 js_set_finalizer(obj, sd_finalize); 231 232 return obj; 233} 234 235ant_value_t string_decoder_decode_bytes( 236 ant_t *js, ant_value_t decoder, 237 const uint8_t *src, size_t len, bool flush 238) { 239 sd_state_t *st = sd_get_state(decoder); 240 if (!st) return js_mkerr_typed(js, JS_ERR_TYPE, "Invalid StringDecoder"); 241 return sd_do_write(js, st, src, len, flush); 242} 243 244ant_value_t string_decoder_decode_value( 245 ant_t *js, ant_value_t decoder, 246 ant_value_t chunk, bool flush 247) { 248 sd_state_t *st = sd_get_state(decoder); 249 if (!st) return js_mkerr_typed(js, JS_ERR_TYPE, "Invalid StringDecoder"); 250 251 if (vtype(chunk) == T_STR) { 252 size_t slen = 0; 253 const char *s = js_getstr(js, chunk, &slen); 254 return s ? js_mkstr(js, s, slen) : js_mkstr(js, "", 0); 255 } 256 257 const uint8_t *src = NULL; 258 size_t len = 0; 259 if (is_object_type(chunk)) 260 buffer_source_get_bytes(js, chunk, &src, &len); 261 262 return sd_do_write(js, st, src, len, flush); 263} 264 265static ant_value_t js_sd_ctor(ant_t *js, ant_value_t *args, int nargs) { 266 if (vtype(js->new_target) == T_UNDEF) 267 return js_mkerr_typed(js, JS_ERR_TYPE, "StringDecoder constructor requires 'new'"); 268 269 ant_value_t encoding = nargs > 0 ? args[0] : js_mkundef(); 270 return string_decoder_create(js, encoding); 271} 272 273ant_value_t string_decoder_library(ant_t *js) { 274 g_string_decoder_proto = js_mkobj(js); 275 276 js_set_getter_desc(js, g_string_decoder_proto, "encoding", 8, js_mkfun(js_sd_get_encoding), JS_DESC_C); 277 js_set(js, g_string_decoder_proto, "write", js_mkfun(js_sd_write)); 278 js_set(js, g_string_decoder_proto, "end", js_mkfun(js_sd_end)); 279 js_set_sym(js, g_string_decoder_proto, get_toStringTag_sym(), js_mkstr(js, "StringDecoder", 13)); 280 281 ant_value_t ctor = js_make_ctor(js, js_sd_ctor, g_string_decoder_proto, "StringDecoder", 13); 282 ant_value_t lib = js_mkobj(js); 283 js_set(js, lib, "StringDecoder", ctor); 284 285 return lib; 286}