Page MenuHomePhorge

string_decoder.c
No OneTemporary

Size
7 KB
Referenced Files
None
Subscribers
None

string_decoder.c

#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include "ant.h"
#include "base64.h"
#include "errors.h"
#include "internal.h"
#include "descriptors.h"
#include "modules/buffer.h"
#include "modules/symbol.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 ant_value_t g_string_decoder_proto = 0;
static sd_state_t *sd_get_state(ant_value_t obj) {
ant_value_t s = js_get_slot(obj, SLOT_DATA);
if (vtype(s) != T_NUM) return NULL;
return (sd_state_t *)(uintptr_t)(size_t)js_getnum(s);
}
static void sd_finalize(ant_t *js, ant_object_t *obj) {
if (!obj->extra_slots) return;
ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots;
for (uint8_t i = 0; i < obj->extra_count; i++) {
if (entries[i].slot == SLOT_DATA && vtype(entries[i].value) == T_NUM) {
sd_state_t *st = (sd_state_t *)(uintptr_t)(size_t)js_getnum(entries[i].value);
if (st) { free(st->td); free(st); }
return;
}}
}
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) {
char *out = malloc(len * 2 + 1);
if (!out) return js_mkerr(js, "out of memory");
size_t o = 0;
for (size_t i = 0; i < len; i++) {
uint8_t b = src[i];
if (b < 0x80) out[o++] = (char)b;
else {
out[o++] = (char)(0xC0 | (b >> 6));
out[o++] = (char)(0x80 | (b & 0x3F));
}}
ant_value_t result = js_mkstr(js, out, o);
free(out);
return result;
}
static ant_value_t sd_hex_decode(ant_t *js, const uint8_t *src, size_t len) {
static const char hex[] = "0123456789abcdef";
if (len == 0) return js_mkstr(js, "", 0);
char *out = malloc(len * 2 + 1);
if (!out) return js_mkerr(js, "out of memory");
for (size_t i = 0; i < len; i++) {
out[i*2] = hex[(src[i] >> 4) & 0xF];
out[i*2+1] = hex[src[i] & 0xF];
}
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_t *js, ant_value_t *args, int nargs) {
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_t *js, ant_value_t *args, int nargs) {
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]) == T_STR) {
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_t *js, ant_value_t *args, int nargs) {
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 ant_value_t js_sd_ctor(ant_t *js, ant_value_t *args, int nargs) {
if (vtype(js->new_target) == T_UNDEF)
return js_mkerr_typed(js, JS_ERR_TYPE, "StringDecoder constructor requires 'new'");
int enc = SD_ENC_UTF8;
if (nargs > 0 && !is_undefined(args[0])) {
ant_value_t label_val = (vtype(args[0]) == T_STR) ? args[0] : coerce_to_str(js, args[0]);
if (!is_err(label_val) && vtype(label_val) == T_STR) {
size_t llen;
const char *label = js_getstr(js, label_val, &llen);
if (label) enc = sd_parse_encoding(label, llen);
}}
sd_state_t *st = calloc(1, sizeof(sd_state_t));
if (!st) return js_mkerr(js, "out of memory");
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 js_mkerr(js, "out of memory"); }
}
ant_value_t obj = js_mkobj(js);
ant_value_t proto = js_instance_proto_from_new_target(js, g_string_decoder_proto);
if (is_object_type(proto)) js_set_proto_init(obj, proto);
js_set_slot(obj, SLOT_DATA, ANT_PTR(st));
js_set_finalizer(obj, sd_finalize);
return obj;
}
ant_value_t string_decoder_library(ant_t *js) {
g_string_decoder_proto = js_mkobj(js);
js_set_getter_desc(js, g_string_decoder_proto, "encoding", 8, js_mkfun(js_sd_get_encoding), JS_DESC_C);
js_set(js, g_string_decoder_proto, "write", js_mkfun(js_sd_write));
js_set(js, g_string_decoder_proto, "end", js_mkfun(js_sd_end));
js_set_sym(js, g_string_decoder_proto, get_toStringTag_sym(), js_mkstr(js, "StringDecoder", 13));
ant_value_t ctor = js_make_ctor(js, js_sd_ctor, g_string_decoder_proto, "StringDecoder", 13);
ant_value_t lib = js_mkobj(js);
js_set(js, lib, "StringDecoder", ctor);
return lib;
}

File Metadata

Mime Type
text/x-c
Expires
Fri, Apr 3, 9:49 PM (2 d)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
521702
Default Alt Text
string_decoder.c (7 KB)

Event Timeline