Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 58eaa4c

Browse files
authored
Normative: add option to omit padding (#60)
1 parent 5b0d178 commit 58eaa4c

File tree

5 files changed

+21
-9
lines changed

5 files changed

+21
-9
lines changed

README.md

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ Additional options are supplied in an options bag argument:
4040

4141
- `lastChunkHandling`: Recall that base64 decoding operates on chunks of 4 characters at a time, but the input may have some characters which don't fit evenly into such a chunk of 4 characters. This option determines how the final chunk of characters should be handled. The three options are `"loose"` (the default), which treats the chunk as if it had any necessary `=` padding (but throws if this is not possible, i.e. there is exactly one extra character); `"strict"`, which enforces that the chunk has exactly 4 characters (counting `=` padding) and that [overflow bits](https://datatracker.ietf.org/doc/html/rfc4648#section-3.5) are 0; and `"stop-before-partial"`, which stops decoding before the final chunk unless the final chunk has exactly 4 characters.
4242

43+
- `omitPadding`: When encoding, whether to include `=` padding. Defaults to `false`, i.e., padding is included.
44+
4345
The hex methods do not take any options.
4446

4547
## Writing to an existing Uint8Array
@@ -89,10 +91,6 @@ For base64, you can specify either base64 or base64url for both the encoder and
8991

9092
For hex, both lowercase and uppercase characters (including mixed within the same string) will decode successfully. Output is always lowercase.
9193

92-
### How is `=` padding handled?
93-
94-
Padding is always generated. The base64 decoder allows specifying how to handle inputs without it with the `lastChunkHandling` option.
95-
9694
### How are the extra padding bits handled?
9795

9896
If the length of your input data isn't exactly a multiple of 3 bytes, then encoding it will use either 2 or 3 base64 characters to encode the final 1 or 2 bytes. Since each base64 character is 6 bits, this means you'll be using either 12 or 18 bits to represent 8 or 16 bits, which means you have an extra 4 or 2 bits which don't encode anything.

playground/index-raw.html

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,8 @@ <h3>Basic usage</h3>
8686

8787
<h3>Options</h3>
8888
<p>The base64 methods take an optional options bag which allows specifying the alphabet as either <code>"base64"</code> (the default) or <code>"base64url"</code> (<a href="https://datatracker.ietf.org/doc/html/rfc4648#section-5">the URL-safe variant</a>).</p>
89-
<p>The base64 decoder also allows specifying the behavior for the final chunk with <code>lastChunkHandling</code>. Recall that base64 decoding operates on chunks of 4 characters at a time, but the input may have some characters which don't fit evenly into such a chunk of 4 characters. This option determines how the final chunk of characters should be handled. The three options are <code>"loose"</code> (the default), which treats the chunk as if it had any necessary <code>=</code> padding (but throws if this is not possible, i.e. there is exactly one extra character); <code>"strict"</code>, which enforces that the chunk has exactly 4 characters (counting <code>=</code> padding) and that <a href="https://datatracker.ietf.org/doc/html/rfc4648#section-3.5">overflow bits</a> are 0; and <code>"stop-before-partial"</code>, which stops decoding before the final chunk unless the final chunk has exactly 4 characters.
89+
<p>The base64 decoder also allows specifying the behavior for the final chunk with <code>lastChunkHandling</code>. Recall that base64 decoding operates on chunks of 4 characters at a time, but the input may have some characters which don't fit evenly into such a chunk of 4 characters. This option determines how the final chunk of characters should be handled. The three options are <code>"loose"</code> (the default), which treats the chunk as if it had any necessary <code>=</code> padding (but throws if this is not possible, i.e. there is exactly one extra character); <code>"strict"</code>, which enforces that the chunk has exactly 4 characters (counting <code>=</code> padding) and that <a href="https://datatracker.ietf.org/doc/html/rfc4648#section-3.5">overflow bits</a> are 0; and <code>"stop-before-partial"</code>, which stops decoding before the final chunk unless the final chunk has exactly 4 characters.</p>
90+
<p>The base64 encoder allows omitting padding by specifying <code>omitPadding: true</code>. The default is to include padding.</p>
9091
<p>The hex methods do not have any options.</p>
9192

9293
<pre class="language-js"><code class="language-js">
@@ -109,6 +110,9 @@ <h3>Options</h3>
109110
} catch {
110111
console.log('with lastChunkHandling: "strict", overflow bits are rejected');
111112
}
113+
114+
console.log((new Uint8Array([72])).toBase64()); // 'SA=='
115+
console.log((new Uint8Array([72])).toBase64({ omitPadding: true })); // 'SA'
112116
</code></pre>
113117

114118
<h3>Writing to an existing Uint8Array</h3>

playground/polyfill-core.mjs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ export function uint8ArrayToBase64(arr, options) {
4040
if (alphabet !== 'base64' && alphabet !== 'base64url') {
4141
throw new TypeError('expected alphabet to be either "base64" or "base64url"');
4242
}
43+
let omitPadding = !!opts.omitPadding;
4344

4445
if ('detached' in arr.buffer && arr.buffer.detached) {
4546
throw new TypeError('toBase64 called on array backed by detached buffer');
@@ -63,13 +64,13 @@ export function uint8ArrayToBase64(arr, options) {
6364
lookup[(triplet >> 18) & 63] +
6465
lookup[(triplet >> 12) & 63] +
6566
lookup[(triplet >> 6) & 63] +
66-
'=';
67+
(omitPadding ? '' : '=');
6768
} else if (i + 1 === arr.length) {
6869
let triplet = arr[i] << 16;
6970
result +=
7071
lookup[(triplet >> 18) & 63] +
7172
lookup[(triplet >> 12) & 63] +
72-
'==';
73+
(omitPadding ? '' : '==');
7374
}
7475
return result;
7576
}

spec.html

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,13 @@ <h1>Uint8Array.prototype.toBase64 ( [ _options_ ] )</h1>
2323
1. Let _alphabet_ be ? Get(_opts_, *"alphabet"*).
2424
1. If _alphabet_ is *undefined*, set _alphabet_ to *"base64"*.
2525
1. If _alphabet_ is neither *"base64"* nor *"base64url"*, throw a *TypeError* exception.
26+
1. Let _omitPadding_ be ToBoolean(? Get(_opts_, *"omitPadding"*)).
2627
1. Let _toEncode_ be ? GetUint8ArrayBytes(_O_).
2728
1. If _alphabet_ is *"base64"*, then
28-
1. Let _outAscii_ be the sequence of code points which results from encoding _toEncode_ according to the base64 encoding specified in section 4 of <a href="https://datatracker.ietf.org/doc/html/rfc4648">RFC 4648</a>. Padding is included.
29+
1. Let _outAscii_ be the sequence of code points which results from encoding _toEncode_ according to the base64 encoding specified in section 4 of <a href="https://datatracker.ietf.org/doc/html/rfc4648">RFC 4648</a>. Padding is included if and only if _omitPadding_ is *false*.
2930
1. Else,
3031
1. Assert: _alphabet_ is *"base64url"*.
31-
1. Let _outAscii_ be the sequence of code points which results from encoding _toEncode_ according to the base64url encoding specified in section 5 of <a href="https://datatracker.ietf.org/doc/html/rfc4648">RFC 4648</a>. Padding is included.
32+
1. Let _outAscii_ be the sequence of code points which results from encoding _toEncode_ according to the base64url encoding specified in section 5 of <a href="https://datatracker.ietf.org/doc/html/rfc4648">RFC 4648</a>. Padding is included if and only if _omitPadding_ is *false*.
3233
1. Return CodePointsToString(_outAscii_).
3334
</emu-alg>
3435
</emu-clause>

test-polyfill.mjs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,14 @@ test('standard vectors', async t => {
2626
}
2727
});
2828

29+
test('omitPadding', async t => {
30+
for (let [string, result] of standardBase64Vectors) {
31+
await t.test(JSON.stringify(string), () => {
32+
assert.strictEqual(stringToBytes(string).toBase64({ omitPadding: true }), result.replace(/=/g, ''));
33+
});
34+
}
35+
});
36+
2937
let malformedPadding = ['=', 'Zg=', 'Z===', 'Zm8==', 'Zm9v='];
3038
test('malformed padding', async t => {
3139
for (let string of malformedPadding) {

0 commit comments

Comments
 (0)