88
99'use strict'
1010
11- const base64 = require ( 'base64-js' )
1211const ieee754 = require ( 'ieee754' )
1312const customInspectSymbol =
1413 ( typeof Symbol === 'function' && typeof Symbol [ 'for' ] === 'function' ) // eslint-disable-line dot-notation
@@ -393,6 +392,7 @@ Buffer.isEncoding = function isEncoding (encoding) {
393392 case 'latin1' :
394393 case 'binary' :
395394 case 'base64' :
395+ case 'base64url' :
396396 case 'ucs2' :
397397 case 'ucs-2' :
398398 case 'utf16le' :
@@ -484,7 +484,8 @@ function byteLength (string, encoding) {
484484 case 'hex' :
485485 return len >>> 1
486486 case 'base64' :
487- return base64ToBytes ( string ) . length
487+ case 'base64url' :
488+ return base64ByteLength ( string , len )
488489 default :
489490 if ( loweredCase ) {
490491 return mustMatch ? - 1 : utf8ByteLength ( string ) // assume utf8
@@ -550,7 +551,10 @@ function slowToString (encoding, start, end) {
550551 return latin1Slice ( this , start , end )
551552
552553 case 'base64' :
553- return base64Slice ( this , start , end )
554+ return base64Slice ( this , start , end , base64Charset , true )
555+
556+ case 'base64url' :
557+ return base64Slice ( this , start , end , base64UrlCharset , false )
554558
555559 case 'ucs2' :
556560 case 'ucs-2' :
@@ -1015,7 +1019,62 @@ function asciiWrite (buf, string, offset, length) {
10151019}
10161020
10171021function base64Write ( buf , string , offset , length ) {
1018- return blitBuffer ( base64ToBytes ( string ) , buf , offset , length )
1022+ const src = string . replace ( / [ ^ + / 0 - 9 A - Z a - z - _ = ] / g, '' )
1023+ const eq = src . indexOf ( '=' )
1024+ const dst = buf
1025+
1026+ let srcLen = eq >= 0 ? eq : src . length
1027+ let srcPos = 0
1028+ let dstLen = length
1029+ let dstPos = offset
1030+
1031+ while ( srcLen >= 4 && dstLen >= 3 ) {
1032+ const t1 = base64Table [ src . charCodeAt ( srcPos ++ ) ]
1033+ const t2 = base64Table [ src . charCodeAt ( srcPos ++ ) ]
1034+ const t3 = base64Table [ src . charCodeAt ( srcPos ++ ) ]
1035+ const t4 = base64Table [ src . charCodeAt ( srcPos ++ ) ]
1036+
1037+ dst [ dstPos ++ ] = ( t1 << 2 ) | ( t2 >> 4 )
1038+ dst [ dstPos ++ ] = ( t2 << 4 ) | ( t3 >> 2 )
1039+ dst [ dstPos ++ ] = ( t3 << 6 ) | ( t4 >> 0 )
1040+
1041+ srcLen -= 4
1042+ dstLen -= 3
1043+ }
1044+
1045+ {
1046+ let w1 , w2 , w3 , w4
1047+
1048+ while ( srcLen && dstLen ) {
1049+ const w = base64Table [ src . charCodeAt ( srcPos ) ]
1050+
1051+ switch ( srcPos & 3 ) {
1052+ case 0 :
1053+ w1 = w
1054+ break
1055+ case 1 :
1056+ w2 = w
1057+ dst [ dstPos ++ ] = ( w1 << 2 ) | ( w2 >> 4 )
1058+ dstLen --
1059+ break
1060+ case 2 :
1061+ w3 = w
1062+ dst [ dstPos ++ ] = ( w2 << 4 ) | ( w3 >> 2 )
1063+ dstLen --
1064+ break
1065+ case 3 :
1066+ w4 = w
1067+ dst [ dstPos ++ ] = ( w3 << 6 ) | ( w4 >> 0 )
1068+ dstLen --
1069+ break
1070+ }
1071+
1072+ srcPos ++
1073+ srcLen --
1074+ }
1075+ }
1076+
1077+ return dstPos - offset
10191078}
10201079
10211080function ucs2Write ( buf , string , offset , length ) {
@@ -1091,6 +1150,7 @@ Buffer.prototype.write = function write (string, offset, length, encoding) {
10911150 return asciiWrite ( this , string , offset , length )
10921151
10931152 case 'base64' :
1153+ case 'base64url' :
10941154 // Warning: maxLength not taken into account in base64Write
10951155 return base64Write ( this , string , offset , length )
10961156
@@ -1115,12 +1175,53 @@ Buffer.prototype.toJSON = function toJSON () {
11151175 }
11161176}
11171177
1118- function base64Slice ( buf , start , end ) {
1119- if ( start === 0 && end === buf . length ) {
1120- return base64 . fromByteArray ( buf )
1121- } else {
1122- return base64 . fromByteArray ( buf . slice ( start , end ) )
1178+ function base64Slice ( buf , start , end , charset , pad ) {
1179+ end = Math . min ( buf . length , end )
1180+
1181+ let left = end - start
1182+ let i = start
1183+ let str = ''
1184+
1185+ while ( left >= 3 ) {
1186+ const c1 = buf [ i ++ ]
1187+ const c2 = buf [ i ++ ]
1188+ const c3 = buf [ i ++ ]
1189+
1190+ str += charset [ c1 >> 2 ]
1191+ str += charset [ ( ( c1 & 3 ) << 4 ) | ( c2 >> 4 ) ]
1192+ str += charset [ ( ( c2 & 15 ) << 2 ) | ( c3 >> 6 ) ]
1193+ str += charset [ c3 & 63 ]
1194+
1195+ left -= 3
1196+ }
1197+
1198+ switch ( left ) {
1199+ case 1 : {
1200+ const c1 = buf [ i ++ ]
1201+
1202+ str += charset [ c1 >> 2 ]
1203+ str += charset [ ( c1 & 3 ) << 4 ]
1204+
1205+ if ( pad ) str += '=='
1206+
1207+ break
1208+ }
1209+
1210+ case 2 : {
1211+ const c1 = buf [ i ++ ]
1212+ const c2 = buf [ i ++ ]
1213+
1214+ str += charset [ c1 >> 2 ]
1215+ str += charset [ ( ( c1 & 3 ) << 4 ) | ( c2 >> 4 ) ]
1216+ str += charset [ ( c2 & 15 ) << 2 ]
1217+
1218+ if ( pad ) str += '='
1219+
1220+ break
1221+ }
11231222 }
1223+
1224+ return str
11241225}
11251226
11261227function utf8Slice ( buf , start , end ) {
@@ -2109,26 +2210,6 @@ function boundsError (value, length, type) {
21092210// HELPER FUNCTIONS
21102211// ================
21112212
2112- const INVALID_BASE64_RE = / [ ^ + / 0 - 9 A - Z a - z - _ ] / g
2113-
2114- function base64clean ( str ) {
2115- // Node takes equal signs as end of the Base64 encoding
2116- str = str . split ( '=' ) [ 0 ]
2117- // Node strips out invalid characters like \n and \t from the string, base64-js does not
2118- str = str . trim ( ) . replace ( INVALID_BASE64_RE , '' )
2119- // Node converts strings with length < 2 to ''
2120- if ( str . length < 2 ) return ''
2121- // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not
2122- while ( str . length % 4 !== 0 ) {
2123- str = str + '='
2124- }
2125- return str
2126- }
2127-
2128- function base64ToBytes ( str ) {
2129- return base64 . toByteArray ( base64clean ( str ) )
2130- }
2131-
21322213function writeInvalid ( buf , pos ) {
21332214 // U+FFFD (Replacement Character)
21342215 buf [ pos ++ ] = 0xef
@@ -2137,13 +2218,18 @@ function writeInvalid (buf, pos) {
21372218 return pos
21382219}
21392220
2140- function blitBuffer ( src , dst , offset , length ) {
2141- let i
2142- for ( i = 0 ; i < length ; ++ i ) {
2143- if ( ( i + offset >= dst . length ) || ( i >= src . length ) ) break
2144- dst [ i + offset ] = src [ i ]
2221+ function base64ByteLength ( str , bytes ) {
2222+ // Handle padding
2223+ if ( bytes > 0 && str . charCodeAt ( bytes - 1 ) === 0x3d ) {
2224+ bytes --
2225+ }
2226+
2227+ if ( bytes > 1 && str . charCodeAt ( bytes - 1 ) === 0x3d ) {
2228+ bytes --
21452229 }
2146- return i
2230+
2231+ // Base64 ratio: 3/4
2232+ return ( bytes * 3 ) >>> 2
21472233}
21482234
21492235// ArrayBuffer or Uint8Array objects from other contexts (i.e. iframes) do not pass
@@ -2195,6 +2281,33 @@ const hexCharValueTable = [
21952281]
21962282/* eslint-enable no-multi-spaces, indent */
21972283
2284+ const base64Charset =
2285+ 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
2286+
2287+ const base64UrlCharset =
2288+ 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_'
2289+
2290+ /* eslint-disable no-multi-spaces, indent */
2291+ const base64Table = [
2292+ - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
2293+ - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
2294+ - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
2295+ - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
2296+ - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
2297+ - 1 , - 1 , - 1 , 62 , - 1 , 62 , - 1 , 63 ,
2298+ 52 , 53 , 54 , 55 , 56 , 57 , 58 , 59 ,
2299+ 60 , 61 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
2300+ - 1 , 0 , 1 , 2 , 3 , 4 , 5 , 6 ,
2301+ 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 ,
2302+ 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 ,
2303+ 23 , 24 , 25 , - 1 , - 1 , - 1 , - 1 , 63 ,
2304+ - 1 , 26 , 27 , 28 , 29 , 30 , 31 , 32 ,
2305+ 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 ,
2306+ 41 , 42 , 43 , 44 , 45 , 46 , 47 , 48 ,
2307+ 49 , 50 , 51 , - 1 , - 1 , - 1 , - 1 , - 1
2308+ ]
2309+ /* eslint-enable no-multi-spaces, indent */
2310+
21982311// Return not function with Error if BigInt not supported
21992312function defineBigIntMethod ( fn ) {
22002313 return typeof BigInt === 'undefined' ? BufferBigIntNotDefined : fn
0 commit comments