@@ -2321,6 +2321,7 @@ JSContext *JS_NewContext(JSRuntime *rt)
2321
2321
JS_AddIntrinsicPromise(ctx);
2322
2322
JS_AddIntrinsicBigInt(ctx);
2323
2323
JS_AddIntrinsicWeakRef(ctx);
2324
+ JS_AddIntrinsicBase64(ctx);
2324
2325
2325
2326
JS_AddPerformance(ctx);
2326
2327
@@ -57422,6 +57423,144 @@ static void insert_weakref_record(JSValueConst target,
57422
57423
*pwr = wr;
57423
57424
}
57424
57425
57426
+ /* urlsafe_base64 atob/btoa */
57427
+
57428
+ // Base64 encoding table
57429
+ static const char base64_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
57430
+
57431
+ // btoa: binary to ASCII (base64 encode)
57432
+ char* btoa(JSContext *ctx, const char* bin, size_t len) {
57433
+ if (bin == NULL || len == 0) return NULL;
57434
+ // Calculate output length (including padding)
57435
+ size_t out_len = 4 * ((len + 2) / 3) + 1;
57436
+ // Allocate memory for output string (plus null terminator)
57437
+ char* out = (char*)js_mallocz(ctx, out_len);
57438
+
57439
+ if (out == NULL) return NULL;
57440
+
57441
+ // Base64 encoding process
57442
+ size_t i, j;
57443
+
57444
+ for (i = 0, j = 0; i < len; i += 3, j += 4) {
57445
+ uint32_t triple = (bin[i] << 16);
57446
+ if (i + 1 < len) triple |= (bin[i + 1] << 8);
57447
+ if (i + 2 < len) triple |= bin[i + 2];
57448
+
57449
+ out[j] = base64_table[(triple >> 18) & 0x3F];
57450
+ out[j + 1] = base64_table[(triple >> 12) & 0x3F];
57451
+ out[j + 2] = (i + 1 < len) ? base64_table[(triple >> 6) & 0x3F] : '=';
57452
+ out[j + 3] = (i + 2 < len) ? base64_table[triple & 0x3F] : '=';
57453
+ }
57454
+
57455
+ out[out_len] = '\0';
57456
+ return out;
57457
+ }
57458
+
57459
+ static JSValue js_base64_btoa(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) {
57460
+ const char *fmt_str = NULL;
57461
+ const char *result_str = NULL;
57462
+ JSValue v;
57463
+
57464
+ if (argc > 0) {
57465
+ fmt_str = JS_ToCString(ctx, argv[0]);
57466
+ result_str = btoa(ctx, fmt_str, strlen(fmt_str));
57467
+ v = JS_NewString(ctx, result_str);
57468
+ JS_FreeCString(ctx, fmt_str);
57469
+ return v;
57470
+ } else {
57471
+ return JS_ThrowTypeError(ctx, "ERR_MISSING_ARGS");
57472
+ }
57473
+ }
57474
+
57475
+ static int base64_index(char c) {
57476
+ if (c >= 'A' && c <= 'Z')
57477
+ return c - 'A';
57478
+ if (c >= 'a' && c <= 'z')
57479
+ return c - 'a' + 26;
57480
+ if (c >= '0' && c <= '9')
57481
+ return c - '0' + 52;
57482
+ if (c == '-')
57483
+ return 62;
57484
+ if (c == '_')
57485
+ return 63;
57486
+
57487
+ return -1; // Invalid character
57488
+ }
57489
+
57490
+ // atob: ASCII to binary (base64 decode)
57491
+ char* atob(JSContext *ctx, const char* str) {
57492
+ if (str == NULL) return NULL;
57493
+
57494
+ size_t str_len = strlen(str);
57495
+
57496
+ if (str_len % 4 != 0) return NULL; // Invalid base64 string
57497
+
57498
+ // Calculate output length
57499
+ size_t len = str_len / 4 * 3;
57500
+
57501
+ if (str[str_len - 1] == '=') len--;
57502
+
57503
+ if (str[str_len - 2] == '=') len--;
57504
+
57505
+ // Allocate memory for output data
57506
+ size_t out_len = len+1;
57507
+ char* out = (char*)js_mallocz(ctx, out_len);
57508
+
57509
+ if (out == NULL) return NULL;
57510
+
57511
+ // Base64 decoding process
57512
+ size_t i, j;
57513
+
57514
+ for (i = 0, j = 0; i < str_len; i += 4, j += 3) {
57515
+ int a = base64_index(str[i]);
57516
+ int b = base64_index(str[i + 1]);
57517
+ int c = str[i + 2] == '=' ? 0 : base64_index(str[i + 2]);
57518
+ int d = str[i + 3] == '=' ? 0 : base64_index(str[i + 3]);
57519
+
57520
+ if (a == -1 || b == -1 || c == -1 || d == -1) {
57521
+ js_free(ctx, out);
57522
+ return NULL; // Invalid character
57523
+ }
57524
+
57525
+ uint32_t triple = (a << 18) | (b << 12) | (c << 6) | d;
57526
+ out[j] = (triple >> 16) & 0xFF;
57527
+
57528
+ if (j + 1 < len) out[j + 1] = (triple >> 8) & 0xFF;
57529
+ if (j + 2 < len) out[j + 2] = triple & 0xFF;
57530
+ }
57531
+
57532
+ out[out_len] = '\0';
57533
+ return out;
57534
+ }
57535
+
57536
+
57537
+ static JSValue js_base64_atob(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) {
57538
+ const char *fmt_str = NULL;
57539
+ const char *result_str = NULL;
57540
+ JSValue v;
57541
+
57542
+ if (argc > 0) {
57543
+ fmt_str = JS_ToCString(ctx, argv[0]);
57544
+ result_str = atob(ctx, fmt_str);
57545
+ v = JS_NewString(ctx, result_str);
57546
+ JS_FreeCString(ctx, fmt_str);
57547
+ return v;
57548
+ } else {
57549
+ return JS_ThrowTypeError(ctx, "ERR_MISSING_ARGS");
57550
+ }
57551
+ }
57552
+
57553
+ static const JSCFunctionListEntry js_base64_funcs[] = {
57554
+ JS_CFUNC_DEF("btoa", 1, js_base64_btoa ),
57555
+ JS_CFUNC_DEF("atob", 1, js_base64_atob ),
57556
+ };
57557
+
57558
+ void JS_AddIntrinsicBase64(JSContext *ctx)
57559
+ {
57560
+ JS_SetPropertyFunctionList(ctx, ctx->global_obj, js_base64_funcs, countof(js_base64_funcs));
57561
+ }
57562
+
57563
+
57425
57564
/* CallSite */
57426
57565
57427
57566
static void js_callsite_finalizer(JSRuntime *rt, JSValueConst val)
0 commit comments