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.

Add Uint8Array base64 and hex helpers

+232 -6
+202 -6
src/modules/buffer.c
··· 632 632 W_FAIL: return false; 633 633 } 634 634 635 + static ant_value_t js_typedarray_every(ant_t *js, ant_value_t *args, int nargs) { 636 + if (nargs < 1 || !is_callable(args[0])) 637 + return js_mkerr_typed(js, JS_ERR_TYPE, "TypedArray.prototype.every requires a callable"); 638 + 639 + ant_value_t this_val = js_getthis(js); 640 + TypedArrayData *ta_data = buffer_get_typedarray_data(this_val); 641 + if (!ta_data) return js_mkerr(js, "Invalid TypedArray"); 642 + if (!ta_data->buffer || ta_data->buffer->is_detached) 643 + return js_mkerr(js, "Cannot operate on a detached TypedArray"); 644 + 645 + ant_value_t callback = args[0]; 646 + ant_value_t this_arg = nargs > 1 ? args[1] : js_mkundef(); 647 + 648 + for (size_t i = 0; i < ta_data->length; i++) { 649 + ant_value_t value = js_mkundef(); 650 + if (!typedarray_read_value(js, ta_data, i, &value)) return js_false; 651 + 652 + ant_value_t call_args[3] = { value, js_mknum((double)i), this_val }; 653 + ant_value_t result = sv_vm_call(js->vm, js, callback, this_arg, call_args, 3, NULL, false); 654 + if (is_err(result)) return result; 655 + if (!js_truthy(js, result)) return js_false; 656 + } 657 + 658 + return js_true; 659 + } 660 + 635 661 ant_value_t create_arraybuffer_obj(ant_t *js, ArrayBufferData *buffer) { 636 662 ant_value_t ab_obj = js_mkobj(js); 637 663 ant_value_t ab_proto = js_get_ctor_proto(js, "ArrayBuffer", 11); ··· 1977 2003 if (len % 2 != 0) return NULL; 1978 2004 1979 2005 size_t decoded_len = len / 2; 1980 - uint8_t *decoded = malloc(decoded_len); 2006 + size_t alloc_len = decoded_len; 2007 + 2008 + if (alloc_len == 0) alloc_len = 1; 2009 + uint8_t *decoded = malloc(alloc_len); 1981 2010 if (!decoded) return NULL; 1982 2011 1983 2012 for (size_t i = 0; i < decoded_len; i++) { 1984 - unsigned int byte; 1985 - if (sscanf(data + i * 2, "%2x", &byte) != 1) { 1986 - free(decoded); return NULL; 1987 - } 1988 - decoded[i] = (uint8_t)byte; 2013 + unsigned char hi_ch = (unsigned char)data[i * 2]; 2014 + unsigned char lo_ch = (unsigned char)data[i * 2 + 1]; 2015 + int hi; int lo; 2016 + 2017 + if (hi_ch >= '0' && hi_ch <= '9') { hi = hi_ch - '0'; goto have_hi; } 2018 + if (hi_ch >= 'a' && hi_ch <= 'f') { hi = hi_ch - 'a' + 10; goto have_hi; } 2019 + if (hi_ch >= 'A' && hi_ch <= 'F') { hi = hi_ch - 'A' + 10; goto have_hi; } 2020 + goto fail; 2021 + 2022 + have_hi: 2023 + if (lo_ch >= '0' && lo_ch <= '9') { lo = lo_ch - '0'; goto have_lo; } 2024 + if (lo_ch >= 'a' && lo_ch <= 'f') { lo = lo_ch - 'a' + 10; goto have_lo; } 2025 + if (lo_ch >= 'A' && lo_ch <= 'F') { lo = lo_ch - 'A' + 10; goto have_lo; } 2026 + goto fail; 2027 + 2028 + have_lo: 2029 + decoded[i] = (uint8_t)((hi << 4) | lo); 1989 2030 } 1990 2031 1991 2032 *out_len = decoded_len; 1992 2033 return decoded; 2034 + 2035 + fail: 2036 + free(decoded); 2037 + return NULL; 2038 + } 2039 + 2040 + static ant_value_t uint8array_from_bytes(ant_t *js, const uint8_t *bytes, size_t len) { 2041 + ArrayBufferData *buffer = create_array_buffer_data(len); 2042 + if (!buffer) return js_mkerr(js, "Failed to allocate buffer"); 2043 + if (len > 0) memcpy(buffer->data, bytes, len); 2044 + return create_typed_array(js, TYPED_ARRAY_UINT8, buffer, 0, len, "Uint8Array"); 2045 + } 2046 + 2047 + static ant_value_t js_uint8array_fromHex(ant_t *js, ant_value_t *args, int nargs) { 2048 + ant_value_t source = nargs > 0 ? js_tostring_val(js, args[0]) : js_mkstr(js, "", 0); 2049 + if (is_err(source)) return source; 2050 + 2051 + size_t len = 0; 2052 + char *str = js_getstr(js, source, &len); 2053 + 2054 + size_t decoded_len = 0; 2055 + uint8_t *decoded = hex_decode(str, len, &decoded_len); 2056 + if (!decoded) return js_mkerr_typed(js, JS_ERR_SYNTAX, "Invalid hex string"); 2057 + 2058 + ant_value_t result = uint8array_from_bytes(js, decoded, decoded_len); 2059 + free(decoded); 2060 + 2061 + return result; 2062 + } 2063 + 2064 + static ant_value_t js_uint8array_fromBase64(ant_t *js, ant_value_t *args, int nargs) { 2065 + ant_value_t source = nargs > 0 ? js_tostring_val(js, args[0]) : js_mkstr(js, "", 0); 2066 + if (is_err(source)) return source; 2067 + 2068 + size_t len = 0; 2069 + char *str = js_getstr(js, source, &len); 2070 + 2071 + size_t decoded_len = 0; 2072 + uint8_t *decoded = ant_base64_decode(str, len, &decoded_len); 2073 + if (!decoded) return js_mkerr_typed(js, JS_ERR_SYNTAX, "Invalid base64 string"); 2074 + 2075 + ant_value_t result = uint8array_from_bytes(js, decoded, decoded_len); 2076 + free(decoded); 2077 + 2078 + return result; 2079 + } 2080 + 2081 + static ant_value_t js_uint8array_toHex(ant_t *js, ant_value_t *args, int nargs) { 2082 + ant_value_t this_val = js_getthis(js); 2083 + TypedArrayData *ta_data = buffer_get_typedarray_data(this_val); 2084 + 2085 + if (!ta_data || ta_data->type != TYPED_ARRAY_UINT8) 2086 + return js_mkerr(js, "Uint8Array.prototype.toHex called on incompatible receiver"); 2087 + if (!ta_data->buffer || ta_data->buffer->is_detached) 2088 + return js_mkerr(js, "Cannot read from detached Uint8Array"); 2089 + 2090 + uint8_t *data = ta_data->buffer->data + ta_data->byte_offset; 2091 + size_t len = ta_data->byte_length; 2092 + char *hex = malloc(len * 2 + 1); 2093 + 2094 + if (!hex) return js_mkerr(js, "Failed to allocate hex string"); 2095 + for (size_t i = 0; i < len; i++) snprintf(hex + i * 2, 3, "%02x", data[i]); 2096 + 2097 + ant_value_t result = js_mkstr(js, hex, len * 2); 2098 + free(hex); 2099 + 2100 + return result; 2101 + } 2102 + 2103 + static ant_value_t js_uint8array_toBase64(ant_t *js, ant_value_t *args, int nargs) { 2104 + ant_value_t this_val = js_getthis(js); 2105 + TypedArrayData *ta_data = buffer_get_typedarray_data(this_val); 2106 + 2107 + if (!ta_data || ta_data->type != TYPED_ARRAY_UINT8) 2108 + return js_mkerr(js, "Uint8Array.prototype.toBase64 called on incompatible receiver"); 2109 + if (!ta_data->buffer || ta_data->buffer->is_detached) 2110 + return js_mkerr(js, "Cannot read from detached Uint8Array"); 2111 + 2112 + size_t out_len = 0; 2113 + char *encoded = ant_base64_encode( 2114 + ta_data->buffer->data + ta_data->byte_offset, 2115 + ta_data->byte_length, &out_len 2116 + ); 2117 + 2118 + if (!encoded) return js_mkerr(js, "Failed to encode base64"); 2119 + ant_value_t result = js_mkstr(js, encoded, out_len); 2120 + free(encoded); 2121 + 2122 + return result; 2123 + } 2124 + 2125 + static ant_value_t uint8array_set_result(ant_t *js, size_t read, size_t written) { 2126 + ant_value_t result = js_mkobj(js); 2127 + js_set(js, result, "read", js_mknum((double)read)); 2128 + js_set(js, result, "written", js_mknum((double)written)); 2129 + return result; 2130 + } 2131 + 2132 + static ant_value_t uint8array_set_bytes(ant_t *js, const uint8_t *bytes, size_t byte_len, size_t read) { 2133 + ant_value_t this_val = js_getthis(js); 2134 + TypedArrayData *ta_data = buffer_get_typedarray_data(this_val); 2135 + 2136 + if (!ta_data || ta_data->type != TYPED_ARRAY_UINT8) 2137 + return js_mkerr(js, "Uint8Array setFrom called on incompatible receiver"); 2138 + if (!ta_data->buffer || ta_data->buffer->is_detached) 2139 + return js_mkerr(js, "Cannot write to detached Uint8Array"); 2140 + if (byte_len > ta_data->byte_length) 2141 + return js_mkerr_typed(js, JS_ERR_RANGE, "Decoded data does not fit in Uint8Array"); 2142 + 2143 + if (byte_len > 0) memcpy(ta_data->buffer->data + ta_data->byte_offset, bytes, byte_len); 2144 + return uint8array_set_result(js, read, byte_len); 2145 + } 2146 + 2147 + static ant_value_t js_uint8array_setFromHex(ant_t *js, ant_value_t *args, int nargs) { 2148 + ant_value_t source = nargs > 0 ? js_tostring_val(js, args[0]) : js_mkstr(js, "", 0); 2149 + if (is_err(source)) return source; 2150 + 2151 + size_t len = 0; 2152 + char *str = js_getstr(js, source, &len); 2153 + size_t decoded_len = 0; 2154 + 2155 + uint8_t *decoded = hex_decode(str, len, &decoded_len); 2156 + if (!decoded) return js_mkerr_typed(js, JS_ERR_SYNTAX, "Invalid hex string"); 2157 + 2158 + ant_value_t result = uint8array_set_bytes(js, decoded, decoded_len, len); 2159 + free(decoded); 2160 + 2161 + return result; 2162 + } 2163 + 2164 + static ant_value_t js_uint8array_setFromBase64(ant_t *js, ant_value_t *args, int nargs) { 2165 + ant_value_t source = nargs > 0 ? js_tostring_val(js, args[0]) : js_mkstr(js, "", 0); 2166 + if (is_err(source)) return source; 2167 + 2168 + size_t len = 0; 2169 + char *str = js_getstr(js, source, &len); 2170 + size_t decoded_len = 0; 2171 + 2172 + uint8_t *decoded = ant_base64_decode(str, len, &decoded_len); 2173 + if (!decoded) return js_mkerr_typed(js, JS_ERR_SYNTAX, "Invalid base64 string"); 2174 + 2175 + ant_value_t result = uint8array_set_bytes(js, decoded, decoded_len, len); 2176 + free(decoded); 2177 + 2178 + return result; 1993 2179 } 1994 2180 1995 2181 typedef enum { ··· 2770 2956 js_set(js, typedarray_proto, "join", js_mkfun(js_typedarray_join)); 2771 2957 js_set(js, typedarray_proto, "indexOf", js_mkfun(js_typedarray_indexOf)); 2772 2958 js_set(js, typedarray_proto, "includes", js_mkfun(js_typedarray_includes)); 2959 + js_set(js, typedarray_proto, "every", js_mkfun(js_typedarray_every)); 2773 2960 js_set_sym(js, typedarray_proto, get_toStringTag_sym(), js_mkstr(js, "TypedArray", 10)); 2774 2961 2775 2962 g_typedarray_iter_proto = js_mkobj(js); ··· 2813 3000 SETUP_TYPEDARRAY(Float64Array); 2814 3001 SETUP_TYPEDARRAY(BigInt64Array); 2815 3002 SETUP_TYPEDARRAY(BigUint64Array); 3003 + 3004 + ant_value_t uint8array_codec_ctor = js_get(js, glob, "Uint8Array"); 3005 + ant_value_t uint8array_codec_proto = js_get(js, uint8array_codec_ctor, "prototype"); 3006 + js_set(js, uint8array_codec_ctor, "fromHex", js_mkfun(js_uint8array_fromHex)); 3007 + js_set(js, uint8array_codec_ctor, "fromBase64", js_mkfun(js_uint8array_fromBase64)); 3008 + js_set(js, uint8array_codec_proto, "toHex", js_mkfun(js_uint8array_toHex)); 3009 + js_set(js, uint8array_codec_proto, "toBase64", js_mkfun(js_uint8array_toBase64)); 3010 + js_set(js, uint8array_codec_proto, "setFromHex", js_mkfun(js_uint8array_setFromHex)); 3011 + js_set(js, uint8array_codec_proto, "setFromBase64", js_mkfun(js_uint8array_setFromBase64)); 2816 3012 2817 3013 ant_value_t dataview_ctor_obj = js_mkobj(js); 2818 3014 ant_value_t dataview_proto = js_mkobj(js);
+30
tests/test_uint8array_base64_hex.cjs
··· 1 + function assert(condition, message) { 2 + if (!condition) throw new Error(message); 3 + } 4 + 5 + const bytes = new Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]); 6 + 7 + assert(bytes.toHex() === "48656c6c6f20576f726c64", "Uint8Array.prototype.toHex"); 8 + assert(bytes.toBase64() === "SGVsbG8gV29ybGQ=", "Uint8Array.prototype.toBase64"); 9 + 10 + const fromHex = Uint8Array.fromHex("48656c6c6f20576f726c64"); 11 + assert(fromHex.length === bytes.length, "Uint8Array.fromHex length"); 12 + assert(bytes.every((value, index, array) => array === bytes && value === fromHex[index]), "Uint8Array.fromHex bytes"); 13 + 14 + const fromBase64 = Uint8Array.fromBase64("SGVsbG8gV29ybGQ="); 15 + assert(fromBase64.length === bytes.length, "Uint8Array.fromBase64 length"); 16 + assert(bytes.every((value, index) => value === fromBase64[index]), "Uint8Array.fromBase64 bytes"); 17 + 18 + const hexTarget = new Uint8Array(16); 19 + const hexResult = hexTarget.setFromHex("48656c6c6f20576f726c64"); 20 + assert(hexResult.read === 22, "Uint8Array.setFromHex read count"); 21 + assert(hexResult.written === 11, "Uint8Array.setFromHex written count"); 22 + assert(bytes.every((value, index) => value === hexTarget[index]), "Uint8Array.setFromHex bytes"); 23 + 24 + const base64Target = new Uint8Array(16); 25 + const base64Result = base64Target.setFromBase64("SGVsbG8gV29ybGQ="); 26 + assert(base64Result.read === 16, "Uint8Array.setFromBase64 read count"); 27 + assert(base64Result.written === 11, "Uint8Array.setFromBase64 written count"); 28 + assert(bytes.every((value, index) => value === base64Target[index]), "Uint8Array.setFromBase64 bytes"); 29 + 30 + console.log("Uint8Array base64/hex tests completed!");