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