Something went wrong. Try again.
MIRROR: javascript for 🐜's, a tiny runtime with big ambitions ant.themackabu.dev
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291#include <stdlib.h>#include <string.h>#include <stdint.h>#include <stdbool.h>
#include "ant.h"#include "cfunc.h"#include "ptr.h"#include "utf8.h"#include "base64.h"#include "errors.h"#include "internal.h"#include "utils.h"#include "descriptors.h"
#include "modules/buffer.h"#include "modules/textcodec.h"#include "modules/string_decoder.h"
#define SD_ENC_UTF8 0#define SD_ENC_UTF16LE 1#define SD_ENC_UTF16BE 2#define SD_ENC_LATIN1 3#define SD_ENC_HEX 4#define SD_ENC_BASE64 5
typedef struct { int encoding; td_state_t *td; uint8_t pending[2]; int pending_len;} sd_state_t;
static constexpr uint32_t STRING_DECODER_NATIVE_TAG = Ant_NativeTag("SDEC");
static sd_state_t *sd_get_state(ant_value_t obj) { return (sd_state_t *)js_get_native(obj, STRING_DECODER_NATIVE_TAG);}
static void sd_finalize(ant_t *js, ant_object_t *obj) { ant_value_t value = js_obj_from_ptr(obj); sd_state_t *st = (sd_state_t *)js_get_native(value, STRING_DECODER_NATIVE_TAG); if (st) { free(st->td); free(st); } js_clear_native(value, STRING_DECODER_NATIVE_TAG);}
static int sd_parse_encoding(const char *s, size_t len) { static const struct { const char *label; uint8_t llen; int enc; } map[] = { {"utf8", 4, SD_ENC_UTF8}, {"utf-8", 5, SD_ENC_UTF8}, {"utf16le", 7, SD_ENC_UTF16LE}, {"utf-16le", 8, SD_ENC_UTF16LE}, {"ucs2", 4, SD_ENC_UTF16LE}, {"ucs-2", 5, SD_ENC_UTF16LE}, {"latin1", 6, SD_ENC_LATIN1}, {"binary", 6, SD_ENC_LATIN1}, {"ascii", 5, SD_ENC_LATIN1}, {"hex", 3, SD_ENC_HEX}, {"base64", 6, SD_ENC_BASE64}, {"base64url", 9, SD_ENC_BASE64}, {NULL, 0, 0} }; for (int i = 0; map[i].label; i++) { if (len == map[i].llen && strncasecmp(s, map[i].label, len) == 0) return map[i].enc; } return SD_ENC_UTF8;}
static const char *sd_encoding_name(int enc) {switch (enc) { case SD_ENC_UTF16LE: return "utf-16le"; case SD_ENC_LATIN1: return "latin1"; case SD_ENC_HEX: return "hex"; case SD_ENC_BASE64: return "base64"; default: return "utf-8";}}
static ant_value_t sd_latin1_to_str(ant_t *js, const uint8_t *src, size_t len) { size_t out_len = 0; char *out = latin1_to_utf8(src, len, &out_len); if (!out) return js_mkerr(js, "out of memory");
ant_value_t result = js_mkstr(js, out, out_len); free(out); return result;}
static ant_value_t sd_hex_decode(ant_t *js, const uint8_t *src, size_t len) { if (len == 0) return js_mkstr(js, "", 0); char *out = malloc(len * 2 + 1); if (!out) return js_mkerr(js, "out of memory"); hex_encode(src, len, out); ant_value_t result = js_mkstr(js, out, len * 2); free(out); return result;}
static ant_value_t sd_base64_write(ant_t *js, sd_state_t *st, const uint8_t *src, size_t len, bool flush) { size_t total = (size_t)st->pending_len + len; if (total == 0) return js_mkstr(js, "", 0);
uint8_t *work = malloc(total); if (!work) return js_mkerr(js, "out of memory");
if (st->pending_len > 0) memcpy(work, st->pending, (size_t)st->pending_len); if (src && len > 0) memcpy(work + st->pending_len, src, len);
size_t encode_len = flush ? total : (total / 3) * 3; int new_pending = (int)(total - encode_len);
ant_value_t result; if (encode_len == 0) result = js_mkstr(js, "", 0); else { size_t out_len; char *out = ant_base64_encode(work, encode_len, &out_len); if (!out) { free(work); return js_mkerr(js, "out of memory"); } result = js_mkstr(js, out, out_len); free(out); }
st->pending_len = new_pending; if (new_pending > 0) memcpy(st->pending, work + encode_len, (size_t)new_pending);
free(work); return result;}
static ant_value_t sd_do_write(ant_t *js, sd_state_t *st, const uint8_t *src, size_t len, bool flush) {switch (st->encoding) { case SD_ENC_UTF8: case SD_ENC_UTF16LE: case SD_ENC_UTF16BE: return td_decode(js, st->td, src, len, !flush); case SD_ENC_LATIN1: if (!src || len == 0) return js_mkstr(js, "", 0); return sd_latin1_to_str(js, src, len); case SD_ENC_HEX: if (!src || len == 0) return js_mkstr(js, "", 0); return sd_hex_decode(js, src, len); case SD_ENC_BASE64: return sd_base64_write(js, st, src, len, flush); default: return js_mkstr(js, "", 0);}}
static ant_value_t js_sd_get_encoding(ant_params_t) { sd_state_t *st = sd_get_state(js->this_val); if (!st) return js_mkstr(js, "utf-8", 5); const char *name = sd_encoding_name(st->encoding); return js_mkstr(js, name, strlen(name));}
static ant_value_t js_sd_write(ant_params_t) { sd_state_t *st = sd_get_state(js->this_val); if (!st) return js_mkerr_typed(js, JS_ERR_TYPE, "Invalid StringDecoder"); if (nargs < 1) return js_mkstr(js, "", 0);
if (vtype(args[0]) == kTypeString) { size_t slen; const char *s = js_getstr(js, args[0], &slen); return s ? js_mkstr(js, s, slen) : js_mkstr(js, "", 0); }
const uint8_t *src = NULL; size_t len = 0; if (is_object_type(args[0])) buffer_source_get_bytes(js, args[0], &src, &len);
return sd_do_write(js, st, src, len, false);}
static ant_value_t js_sd_end(ant_params_t) { sd_state_t *st = sd_get_state(js->this_val); if (!st) return js_mkerr_typed(js, JS_ERR_TYPE, "Invalid StringDecoder");
const uint8_t *src = NULL; size_t len = 0; if (nargs > 0 && is_object_type(args[0])) buffer_source_get_bytes(js, args[0], &src, &len);
return sd_do_write(js, st, src, len, true);}
static inline __attribute__((always_inline)) int sd_encoding_from_value(ant_t *js, ant_value_t encoding) { int enc = SD_ENC_UTF8; if (!is_undefined(encoding)) { ant_value_t label_val = (vtype(encoding) == kTypeString) ? encoding : coerce_to_str(js, encoding); if (!is_err(label_val) && vtype(label_val) == kTypeString) { size_t llen; const char *label = js_getstr(js, label_val, &llen); if (label) enc = sd_parse_encoding(label, llen); }}
return enc;}
static inline __attribute__((always_inline)) sd_state_t *sd_state_new(int enc) { sd_state_t *st = calloc(1, sizeof(sd_state_t)); if (!st) return NULL; st->encoding = enc;
if (enc == SD_ENC_UTF8 || enc == SD_ENC_UTF16LE || enc == SD_ENC_UTF16BE) { td_encoding_t td_enc = (enc == SD_ENC_UTF16LE) ? TD_ENC_UTF16LE : (enc == SD_ENC_UTF16BE) ? TD_ENC_UTF16BE : TD_ENC_UTF8; st->td = td_state_new(td_enc, false, false); if (!st->td) { free(st); return NULL; } }
return st;}
static inline __attribute__((always_inline)) void sd_attach(ant_value_t obj, ant_value_t proto, sd_state_t *st) { if (is_object_type(proto)) js_set_proto_init(obj, proto); js_set_native(obj, st, STRING_DECODER_NATIVE_TAG); js_set_finalizer(obj, sd_finalize);}
ant_value_t string_decoder_create(ant_t *js, ant_value_t encoding, ant_value_t new_target) { sd_state_t *st = sd_state_new(sd_encoding_from_value(js, encoding)); if (!st) return js_mkerr(js, "out of memory");
ant_value_t obj = Ant_Object_CreateBare(js); ant_value_t proto = js_instance_proto_from_new_target(js, js->builtins.string_decoder_proto, new_target); sd_attach(obj, proto, st);
return obj;}
ant_value_t string_decoder_decode_value( ant_t *js, ant_value_t decoder, ant_value_t chunk, bool flush) { sd_state_t *st = sd_get_state(decoder); if (!st) return js_mkerr_typed(js, JS_ERR_TYPE, "Invalid StringDecoder");
if (vtype(chunk) == kTypeString) { size_t slen = 0; const char *s = js_getstr(js, chunk, &slen); return s ? js_mkstr(js, s, slen) : js_mkstr(js, "", 0); }
const uint8_t *src = NULL; size_t len = 0; if (is_object_type(chunk)) buffer_source_get_bytes(js, chunk, &src, &len); return sd_do_write(js, st, src, len, flush);}
// StringDecoder.call(this, enc) without new initializes `this` in placestatic __attribute__((noinline)) ant_value_t sd_init_this(ant_t *js, ant_value_t self, ant_value_t encoding) { if (sd_get_state(self)) return self;
sd_state_t *st = sd_state_new(sd_encoding_from_value(js, encoding)); if (!st) return js_mkerr(js, "out of memory");
sd_attach(self, js->builtins.string_decoder_proto, st); return self;}
static ant_value_t js_sd_ctor(ant_params_t) { ant_value_t encoding = nargs > 0 ? args[0] : js_mkundef();
if (!is_undefined(call_new_target) || !is_object_type(js->this_val)) return string_decoder_create(js, encoding, call_new_target); return sd_init_this(js, js->this_val, encoding);}
ant_value_t string_decoder_library(ant_t *js) { js->builtins.string_decoder_proto = Ant_Object_CreateBare(js); js_set_getter_desc(js, js->builtins.string_decoder_proto, "encoding", 8, Ant_Function_Create(js_sd_get_encoding), JS_DESC_C); js_set(js, js->builtins.string_decoder_proto, "write", Ant_Function_CreateWithArity(js_sd_write, 1)); js_set(js, js->builtins.string_decoder_proto, "end", Ant_Function_CreateWithArity(js_sd_end, 1)); js_set_tostringtag(js, js->builtins.string_decoder_proto, js_mkstr(js, "StringDecoder", 13));
ant_value_t ctor = Ant_Function_CreateConstructor(js, js_sd_ctor, js->builtins.string_decoder_proto, "StringDecoder", 1); ant_value_t lib = Ant_Object_CreateBare(js); js_set(js, lib, "StringDecoder", ctor); return lib;}