@@ -391,54 +391,93 @@ JS::Result<std::string> ConvertJSValueToByteString(JSContext *cx, JS::Handle<JS:
391
391
return byteString;
392
392
}
393
393
394
+ JS::Result<std::string> ConvertJSValueToByteString (JSContext *cx, std::string v) {
395
+ JS::RootedValue s (cx);
396
+ s.setString (JS_NewStringCopyN (cx, v.c_str (), v.length ()));
397
+ return ConvertJSValueToByteString (cx, s);
398
+ }
399
+
394
400
// Maps an encoded character to a value in the Base64 alphabet, per
395
401
// RFC 4648, Table 1. Invalid input characters map to UINT8_MAX.
396
402
// https://datatracker.ietf.org/doc/html/rfc4648#section-4
397
403
398
- static const uint8_t base64DecodeTable[] = {
399
- // clang-format off
400
- /* 0 */ 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 ,
401
- /* 8 */ 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 ,
402
- /* 16 */ 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 ,
403
- /* 24 */ 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 ,
404
- /* 32 */ 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 ,
405
- /* 40 */ 255 , 255 , 255 ,
404
+ constexpr uint8_t nonAlphabet = 255 ;
405
+
406
+ // clang-format off
407
+ const uint8_t base64DecodeTable[128 ] = {
408
+ /* 0 */ nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet,
409
+ /* 8 */ nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet,
410
+ /* 16 */ nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet,
411
+ /* 24 */ nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet,
412
+ /* 32 */ nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet,
413
+ /* 40 */ nonAlphabet, nonAlphabet, nonAlphabet,
406
414
62 /* + */ ,
407
- 255 , 255 , 255 ,
415
+ nonAlphabet, nonAlphabet, nonAlphabet ,
408
416
63 /* / */ ,
409
417
410
418
/* 48 */ /* 0 - 9 */ 52 , 53 , 54 , 55 , 56 , 57 , 58 , 59 ,
411
- /* 56 */ 60 , 61 , 255 , 255 , 255 , 255 , 255 , 255 ,
419
+ /* 56 */ 60 , 61 , nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet ,
412
420
413
- /* 64 */ 255 , /* A - Z */ 0 , 1 , 2 , 3 , 4 , 5 , 6 ,
421
+ /* 64 */ nonAlphabet , /* A - Z */ 0 , 1 , 2 , 3 , 4 , 5 , 6 ,
414
422
/* 72 */ 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 ,
415
423
/* 80 */ 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 ,
416
- /* 88 */ 23 , 24 , 25 , 255 , 255 , 255 , 255 , 255 ,
417
- /* 96 */ 255 , /* a - z */ 26 , 27 , 28 , 29 , 30 , 31 , 32 ,
424
+ /* 88 */ 23 , 24 , 25 , nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet ,
425
+ /* 96 */ nonAlphabet , /* a - z */ 26 , 27 , 28 , 29 , 30 , 31 , 32 ,
418
426
/* 104 */ 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 ,
419
427
/* 112 */ 41 , 42 , 43 , 44 , 45 , 46 , 47 , 48 ,
420
- /* 120 */ 49 , 50 , 51 , 255 , 255 , 255 , 255 , 255 ,
428
+ /* 120 */ 49 , 50 , 51 , nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet ,
421
429
};
430
+
431
+ const uint8_t base64URLDecodeTable[128 ] = {
432
+ /* 0 */ nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet,
433
+ /* 8 */ nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet,
434
+ /* 16 */ nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet,
435
+ /* 24 */ nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet,
436
+ /* 32 */ nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet,
437
+ /* 40 */ nonAlphabet, nonAlphabet, nonAlphabet, 62 , nonAlphabet, 62 , nonAlphabet, 63 ,
438
+ /* 48 */ 52 , 53 , 54 , 55 , 56 , 57 , 58 , 59 ,
439
+ /* 56 */ 60 , 61 , nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet,
440
+ /* 64 */ nonAlphabet, 0 , 1 , 2 , 3 , 4 , 5 , 6 ,
441
+ /* 72 */ 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 ,
442
+ /* 80 */ 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 ,
443
+ /* 88 */ 23 , 24 , 25 , nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet, 63 ,
444
+ /* 96 */ nonAlphabet, 26 , 27 , 28 , 29 , 30 , 31 , 32 ,
445
+ /* 104 */ 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 ,
446
+ /* 112 */ 41 , 42 , 43 , 44 , 45 , 46 , 47 , 48 ,
447
+ /* 120 */ 49 , 50 , 51 , nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet, nonAlphabet
448
+ };
449
+
450
+ const char base64EncodeTable[65 ] = " ABCDEFGHIJKLMNOPQRSTUVWXYZ"
451
+ " abcdefghijklmnopqrstuvwxyz"
452
+ " 0123456789+/" ;
453
+
454
+ const char base64URLEncodeTable[65 ] = " ABCDEFGHIJKLMNOPQRSTUVWXYZ"
455
+ " abcdefghijklmnopqrstuvwxyz"
456
+ " 0123456789-_" ;
457
+
422
458
// clang-format on
423
459
424
- bool base64CharacterToValue (char character, uint8_t *value) {
460
+ bool base64CharacterToValue (char character, uint8_t *value, const uint8_t *decodeTable ) {
425
461
static const size_t mask = 127 ;
426
462
auto index = static_cast <size_t >(character);
427
463
428
464
if (index & ~mask) {
429
465
return false ;
430
466
}
431
- *value = base64DecodeTable [index & mask];
467
+ *value = decodeTable [index & mask];
432
468
433
469
return *value != 255 ;
434
470
}
435
471
436
- inline JS::Result<mozilla::Ok> base64Decode4to3 (std::string_view input, std::string &output) {
472
+ inline JS::Result<mozilla::Ok> base64Decode4to3 (std::string_view input, std::string &output,
473
+ const uint8_t *decodeTable) {
437
474
uint8_t w, x, y, z;
438
475
// 8.1 Find the code point pointed to by position in the second column of Table 1: The Base 64
439
476
// Alphabet of RFC 4648. Let n be the number given in the first cell of the same row. [RFC4648]
440
- if (!base64CharacterToValue (input[0 ], &w) || !base64CharacterToValue (input[1 ], &x) ||
441
- !base64CharacterToValue (input[2 ], &y) || !base64CharacterToValue (input[3 ], &z)) {
477
+ if (!base64CharacterToValue (input[0 ], &w, decodeTable) ||
478
+ !base64CharacterToValue (input[1 ], &x, decodeTable) ||
479
+ !base64CharacterToValue (input[2 ], &y, decodeTable) ||
480
+ !base64CharacterToValue (input[3 ], &z, decodeTable)) {
442
481
return JS::Result<mozilla::Ok>(JS::Error ());
443
482
}
444
483
@@ -451,12 +490,14 @@ inline JS::Result<mozilla::Ok> base64Decode4to3(std::string_view input, std::str
451
490
return mozilla::Ok ();
452
491
}
453
492
454
- inline JS::Result<mozilla::Ok> base64Decode3to2 (std::string_view input, std::string &output) {
493
+ inline JS::Result<mozilla::Ok> base64Decode3to2 (std::string_view input, std::string &output,
494
+ const uint8_t *decodeTable) {
455
495
uint8_t w, x, y;
456
496
// 8.1 Find the code point pointed to by position in the second column of Table 1: The Base 64
457
497
// Alphabet of RFC 4648. Let n be the number given in the first cell of the same row. [RFC4648]
458
- if (!base64CharacterToValue (input[0 ], &w) || !base64CharacterToValue (input[1 ], &x) ||
459
- !base64CharacterToValue (input[2 ], &y)) {
498
+ if (!base64CharacterToValue (input[0 ], &w, decodeTable) ||
499
+ !base64CharacterToValue (input[1 ], &x, decodeTable) ||
500
+ !base64CharacterToValue (input[2 ], &y, decodeTable)) {
460
501
return JS::Result<mozilla::Ok>(JS::Error ());
461
502
}
462
503
// 9. If buffer is not empty, it contains either 12 or 18 bits. If it contains 12 bits, then
@@ -469,11 +510,13 @@ inline JS::Result<mozilla::Ok> base64Decode3to2(std::string_view input, std::str
469
510
return mozilla::Ok ();
470
511
}
471
512
472
- inline JS::Result<mozilla::Ok> base64Decode2to1 (std::string_view input, std::string &output) {
513
+ inline JS::Result<mozilla::Ok> base64Decode2to1 (std::string_view input, std::string &output,
514
+ const uint8_t *decodeTable) {
473
515
uint8_t w, x;
474
516
// 8.1 Find the code point pointed to by position in the second column of Table 1: The Base 64
475
517
// Alphabet of RFC 4648. Let n be the number given in the first cell of the same row. [RFC4648]
476
- if (!base64CharacterToValue (input[0 ], &w) || !base64CharacterToValue (input[1 ], &x)) {
518
+ if (!base64CharacterToValue (input[0 ], &w, decodeTable) ||
519
+ !base64CharacterToValue (input[1 ], &x, decodeTable)) {
477
520
return JS::Result<mozilla::Ok>(JS::Error ());
478
521
}
479
522
// 9. If buffer is not empty, it contains either 12 or 18 bits. If it contains 12 bits, then
@@ -499,7 +542,8 @@ bool isAsciiWhitespace(char c) {
499
542
}
500
543
501
544
// https://infra.spec.whatwg.org/#forgiving-base64-decode
502
- JS::Result<std::string> forgivingBase64Decode (std::string_view data) {
545
+ JS::Result<std::string> forgivingBase64Decode (std::string_view data,
546
+ const uint8_t *decodeTable = base64DecodeTable) {
503
547
// 1. Remove all ASCII whitespace from data.
504
548
// ASCII whitespace is U+0009 TAB, U+000A LF, U+000C FF, U+000D CR, or U+0020 SPACE.
505
549
auto hasWhitespace = std::find_if (data.begin (), data.end (), &isAsciiWhitespace);
@@ -558,17 +602,17 @@ JS::Result<std::string> forgivingBase64Decode(std::string_view data) {
558
602
// dealt with some characters.
559
603
560
604
while (data_view.length () >= 4 ) {
561
- MOZ_TRY (base64Decode4to3 (data_view, output));
605
+ MOZ_TRY (base64Decode4to3 (data_view, output, decodeTable ));
562
606
data_view.remove_prefix (4 );
563
607
}
564
608
565
609
switch (data_view.length ()) {
566
610
case 3 : {
567
- MOZ_TRY (base64Decode3to2 (data_view, output));
611
+ MOZ_TRY (base64Decode3to2 (data_view, output, decodeTable ));
568
612
break ;
569
613
}
570
614
case 2 : {
571
- MOZ_TRY (base64Decode2to1 (data_view, output));
615
+ MOZ_TRY (base64Decode2to1 (data_view, output, decodeTable ));
572
616
break ;
573
617
}
574
618
case 1 :
@@ -612,12 +656,8 @@ bool atob(JSContext *cx, unsigned argc, Value *vp) {
612
656
return true ;
613
657
}
614
658
615
- const char base[65 ] = " ABCDEFGHIJKLMNOPQRSTUVWXYZ"
616
- " abcdefghijklmnopqrstuvwxyz"
617
- " 0123456789+/" ;
618
-
619
659
inline uint8_t CharTo8Bit (char character) { return uint8_t (character); }
620
- inline void base64Encode3to4 (std::string_view data, std::string &output) {
660
+ inline void base64Encode3to4 (std::string_view data, std::string &output, const char *encodeTable ) {
621
661
uint32_t b32 = 0 ;
622
662
int i, j = 18 ;
623
663
@@ -627,24 +667,24 @@ inline void base64Encode3to4(std::string_view data, std::string &output) {
627
667
}
628
668
629
669
for (i = 0 ; i < 4 ; ++i) {
630
- output += base [(uint32_t )((b32 >> j) & 0x3F )];
670
+ output += encodeTable [(uint32_t )((b32 >> j) & 0x3F )];
631
671
j -= 6 ;
632
672
}
633
673
}
634
674
635
- inline void base64Encode2to4 (std::string_view data, std::string &output) {
675
+ inline void base64Encode2to4 (std::string_view data, std::string &output, const char *encodeTable ) {
636
676
uint8_t src0 = CharTo8Bit (data[0 ]);
637
677
uint8_t src1 = CharTo8Bit (data[1 ]);
638
- output += base [(uint32_t )((src0 >> 2 ) & 0x3F )];
639
- output += base [(uint32_t )(((src0 & 0x03 ) << 4 ) | ((src1 >> 4 ) & 0x0F ))];
640
- output += base [(uint32_t )((src1 & 0x0F ) << 2 )];
678
+ output += encodeTable [(uint32_t )((src0 >> 2 ) & 0x3F )];
679
+ output += encodeTable [(uint32_t )(((src0 & 0x03 ) << 4 ) | ((src1 >> 4 ) & 0x0F ))];
680
+ output += encodeTable [(uint32_t )((src1 & 0x0F ) << 2 )];
641
681
output += ' =' ;
642
682
}
643
683
644
- inline void base64Encode1to4 (std::string_view data, std::string &output) {
684
+ inline void base64Encode1to4 (std::string_view data, std::string &output, const char *encodeTable ) {
645
685
uint8_t src0 = CharTo8Bit (data[0 ]);
646
- output += base [(uint32_t )((src0 >> 2 ) & 0x3F )];
647
- output += base [(uint32_t )((src0 & 0x03 ) << 4 )];
686
+ output += encodeTable [(uint32_t )((src0 >> 2 ) & 0x3F )];
687
+ output += encodeTable [(uint32_t )((src0 & 0x03 ) << 4 )];
648
688
output += ' =' ;
649
689
output += ' =' ;
650
690
}
@@ -654,23 +694,23 @@ inline void base64Encode1to4(std::string_view data, std::string &output) {
654
694
// section 4 of RFC 4648 to data and return the result. [RFC4648] Note: This is named
655
695
// forgiving-base64 encode for symmetry with forgiving-base64 decode, which is different from the
656
696
// RFC as it defines error handling for certain inputs.
657
- std::string forgivingBase64Encode (std::string_view data) {
697
+ std::string forgivingBase64Encode (std::string_view data, const char *encodeTable ) {
658
698
int length = data.length ();
659
699
std::string output = " " ;
660
700
// The Base64 version of a string will be at least 133% the size of the string.
661
701
output.reserve (length * 1.33 );
662
702
while (length >= 3 ) {
663
- base64Encode3to4 (data, output);
703
+ base64Encode3to4 (data, output, encodeTable );
664
704
data.remove_prefix (3 );
665
705
length -= 3 ;
666
706
}
667
707
668
708
switch (length) {
669
709
case 2 :
670
- base64Encode2to4 (data, output);
710
+ base64Encode2to4 (data, output, encodeTable );
671
711
break ;
672
712
case 1 :
673
- base64Encode1to4 (data, output);
713
+ base64Encode1to4 (data, output, encodeTable );
674
714
break ;
675
715
case 0 :
676
716
break ;
@@ -702,7 +742,7 @@ bool btoa(JSContext *cx, unsigned argc, Value *vp) {
702
742
}
703
743
auto byteString = byteStringResult.unwrap ();
704
744
705
- auto result = forgivingBase64Encode (byteString);
745
+ auto result = forgivingBase64Encode (byteString, GlobalProperties::base64EncodeTable );
706
746
707
747
JSString *str = JS_NewStringCopyN (cx, result.c_str (), result.length ());
708
748
if (!str) {
0 commit comments