base64to
This library provides replacement functions to btoa()
and atob()
, that work faster for large input strings in the current virtual machine version, that i used at the time of writing this document (v8 9.1.269.35, Deno 1.11.5, Chrome 91.0.4472.114).
Bonus features:
- Custom characters for
+
,/
and=
. - Padding char (
=
) can be disabled in encoding, and it’s optional in decoding (any non-ABC char at the end will be ignored by the base64 decoder). - Convert
string|Uint8Array
->string|Uint8Array
. - Convert into existing
Uint8Array
buffer. - Convert
Uint8Array
inplace within the same memory block (for encoding there must be extra space at the end). - Convert
Deno.Reader
->Deno.Reader
.
btoa()
and atob()
The replacement functions for btoa
= encode64
atob
= decode64ToString
encode64(data: string|Uint8Array, cPlus='+', cSlash='/', padding='='): string
decode64ToString(ascii: string|Uint8Array, cPlus='+', cSlash='/'): string
cPlus
is the custom char for code62
(default ‘+’).cSlash
is the custom char for code63
(default ‘/’).padding
is the custom char for padding (default ‘=’). This can be empty string, to disable the padding.
Example:
import {encode64, decode64ToString} from 'https://deno.land/x/base64to@v0.0.2/mod.ts';
console.log(btoa('Data string')); // prints: RGF0YSBzdHJpbmc=
console.log(encode64('Data string')); // prints: RGF0YSBzdHJpbmc=
console.log(atob('RGF0YSBzdHJpbmc=')); // prints: Data string
console.log(decode64ToString('RGF0YSBzdHJpbmc=')); // prints: Data string
console.log(encode64('Data string', '-', '_', '#')); // prints: RGF0YSBzdHJpbmc#
console.log(decode64ToString('RGF0YSBzdHJpbmc#####!!')); // prints: Data string
decode64ToString()
ignores non-ABC characters at the end (treats them as padding chars).
Base64 encoding and decoding Uint8Array
encode64(data: string|Uint8Array, cPlus='+', cSlash='/', padding='='): string
decode64(ascii: string|Uint8Array, into?: Uint8Array, cPlus='+', cSlash='/'): Uint8Array
encode64ToBytes(data: string|Uint8Array, into?: Uint8Array, cPlus='+', cSlash='/', padding='='): Uint8Array
decode64ToString(ascii: string|Uint8Array, cPlus='+', cSlash='/'): string
The most common use is:
encode64()
:Uint8Array
->string
decode64()
:string
-> back toUint8Array
Basicly, these 4 functions allow to base64-encode and base64-decode string|Uint8Array
<-> string|Uint8Array
in all directions.
Functions that return Uint8Array
by default create new Uint8Array
buffers for the result.
But they also can receive an existing buffer (through the argument called into
), and if the provided object is big enough, it will be used for the result.
In this case these functions return the into
object.
If into
was not big enough for the result, a new object is created and returned.
It’s possible to pass the same object to both data
(ascii
) and into
, or they can be subarrays of the same underlying buffer.
In this case the base64 encoding/decoding will occure inplace, overwriting the original data.
Because decoding process produces shorter result (each 4 input bytes are converted to 3 output bytes), for decode64(ascii, into)
the ascii
and the into
can be the same object.
import {decode64} from 'https://deno.land/x/base64to@v0.0.2/mod.ts';
let encoded = new TextEncoder().encode('RGF0YSBzdHJpbmc=');
// decode inplace
let decoded = decode64(encoded, encoded);
console.log(decoded.buffer == encoded.buffer); // prints: true
console.log(String.fromCharCode(...decoded)); // prints: Data string
For encode64ToBytes(data, into)
you need to care, that the into
object is at least Math.ceil(data.length * 4/3) + 2
long (there can be up to 2 padding characters) for inplace encoding.
import {encode64ToBytes} from 'https://deno.land/x/base64to@v0.0.2/mod.ts';
let data = new TextEncoder().encode('Data string');
let buffer = new Uint8Array(Math.ceil(data.length * 4 / 3) + 2);
buffer.set(data);
// now buffer[0 .. data.length] is the 'Data string' string, but there's enough extra space for encoding
// encode inplace
let encoded = encode64ToBytes(buffer.subarray(0, data.length), buffer);
console.log(encoded.buffer == buffer.buffer); // prints: true
console.log(String.fromCharCode(...encoded)); // prints: RGF0YSBzdHJpbmc=
Base64 encoding and decoding Deno.Reader streams
encode64Reader(reader: Deno.Reader, cPlus='+', cSlash='/', padding='='): Deno.Reader
decode64Reader(reader: Deno.Reader, cPlus='+', cSlash='/'): Deno.Reader
The following example base64-encodes your /etc/passwd
file, and prints it to the Deno.stdout
:
import {encode64Reader} from 'https://deno.land/x/base64to@v0.0.2/mod.ts';
let fh = await Deno.open('/etc/passwd');
await Deno.copy(encode64Reader(fh), Deno.stdout);
fh.close();
The following example chains /etc/passwd
-> encode64Reader
-> decode64Reader
-> Deno.stdout
.
import {encode64Reader, decode64Reader} from 'https://deno.land/x/base64to@v0.0.2/mod.ts';
let fh = await Deno.open('/etc/passwd');
await Deno.copy(decode64Reader(encode64Reader(fh)), Deno.stdout);
fh.close();
btoa()
and atob()
Performance compared to The benchmark code can be found in this file: tests/performance.test.ts.
In brief, the functions that this library provides are slower than the navive functions, when operating on 16-byte data samples.
btoa: 434,783 ops/sec
encode64(string): 178,571 ops/sec
encode64(Uint8Array): 192,308 ops/sec
encode64ToBytes(string): 1,000,000 ops/sec
encode64ToBytes(Uint8Array): 909,091 ops/sec
atob: 250,000 ops/sec
decode64ToString(string): 151,515 ops/sec
decode64ToString(Uint8Array): 200,000 ops/sec
decode64(string): 833,333 ops/sec
decode64(Uint8Array): 714,286 ops/sec
Another conclusion is that converting from/to Uint8Array can be faster than the native functions do.
For 100-byte samples:
btoa: 454,545 ops/sec
encode64(string): 250,000 ops/sec
encode64(Uint8Array): 172,414 ops/sec
encode64ToBytes(string): 1,250,000 ops/sec
encode64ToBytes(Uint8Array): 769,231 ops/sec
atob: 99,010 ops/sec
decode64ToString(string): 181,818 ops/sec
decode64ToString(Uint8Array): 75,188 ops/sec
decode64(string): 909,091 ops/sec
decode64(Uint8Array): 1,111,111 ops/sec
encode64()
is still slower than btoa()
, but decode64ToString()
is faster than atob()
.
For 1000-byte:
btoa: 78,125 ops/sec
encode64(string): 103,093 ops/sec
encode64(Uint8Array): 116,279 ops/sec
encode64ToBytes(string): 212,766 ops/sec
encode64ToBytes(Uint8Array): 357,143 ops/sec
atob: 15,873 ops/sec
decode64ToString(string): 36,630 ops/sec
decode64ToString(Uint8Array): 38,023 ops/sec
decode64(string): 208,333 ops/sec
decode64(Uint8Array): 344,828 ops/sec
For 10_000-byte:
btoa: 8,403 ops/sec
encode64(string): 21,186 ops/sec
encode64(Uint8Array): 28,249 ops/sec
encode64ToBytes(string): 28,169 ops/sec
encode64ToBytes(Uint8Array): 40,000 ops/sec
atob: 1,618 ops/sec
decode64ToString(string): 4,257 ops/sec
decode64ToString(Uint8Array): 4,502 ops/sec
decode64(string): 22,676 ops/sec
decode64(Uint8Array): 37,453 ops/sec