@@ -15,14 +15,6 @@ const isNode =
1515 globalThis . process . release &&
1616 globalThis . process . release . name ;
1717
18- function browserUtf8ToBase64 ( data : string ) {
19- return btoa ( unescape ( encodeURIComponent ( data ) ) ) ;
20- }
21-
22- function browserBase64ToUtf8 ( data : string ) {
23- return decodeURIComponent ( escape ( atob ( data ) ) ) ;
24- }
25-
2618function nodeUtf8ToBase64 ( data : string ) {
2719 return Buffer . from ( data , "utf-8" ) . toString ( "base64" ) ;
2820}
@@ -31,5 +23,35 @@ function nodeBase64ToUtf8(data: string) {
3123 return Buffer . from ( data , "base64" ) . toString ( "utf-8" ) ;
3224}
3325
26+ // browserUtf8ToBase64 & browserBase64ToUtf8
27+ // (c) Brandon Rylow - CC BY-SA 4.0
28+ // https://stackoverflow.com/a/30106551/206879
29+ function browserUtf8ToBase64 ( data : string ) {
30+ // first we use encodeURIComponent to get percent-encoded UTF-8,
31+ // then we convert the percent encodings into raw bytes which
32+ // can be fed into btoa.
33+ return btoa (
34+ encodeURIComponent ( data ) . replace (
35+ / % ( [ 0 - 9 A - F ] { 2 } ) / g,
36+ function toSolidBytes ( _match , p1 ) {
37+ // @ts -expect-error - we know what we are doing here
38+ return String . fromCharCode ( "0x" + p1 ) ;
39+ }
40+ )
41+ ) ;
42+ }
43+
44+ function browserBase64ToUtf8 ( data : string ) {
45+ // Going backwards: from bytestream, to percent-encoding, to original string.
46+ return decodeURIComponent (
47+ atob ( data )
48+ . split ( "" )
49+ . map ( function ( c ) {
50+ return "%" + ( "00" + c . charCodeAt ( 0 ) . toString ( 16 ) ) . slice ( - 2 ) ;
51+ } )
52+ . join ( "" )
53+ ) ;
54+ }
55+
3456export const utf8ToBase64 = isNode ? nodeUtf8ToBase64 : browserUtf8ToBase64 ;
3557export const base64ToUtf8 = isNode ? nodeBase64ToUtf8 : browserBase64ToUtf8 ;
0 commit comments