]> Lady’s Gitweb - Pisces/blob - binary.js
Make base32 handling less forgiving
[Pisces] / binary.js
1 // ♓🌟 Piscēs ∷ binary.js
2 // ====================================================================
3 //
4 // Copyright © 2020–2023 Lady [@ Lady’s Computer].
5 //
6 // This Source Code Form is subject to the terms of the Mozilla Public
7 // License, v. 2.0. If a copy of the MPL was not distributed with this
8 // file, You can obtain one at <https://mozilla.org/MPL/2.0/>.
9
10 import { fill, map, reduce } from "./collection.js";
11 import { bind, call } from "./function.js";
12 import { ceil, floor } from "./numeric.js";
13 import { hasOwnProperty, objectCreate } from "./object.js";
14 import {
15 getCodeUnit,
16 rawString,
17 stringFromCodeUnits,
18 stringReplace,
19 } from "./string.js";
20
21 const Buffer = ArrayBuffer;
22 const View = DataView;
23 const TypedArray = Object.getPrototypeOf(Uint8Array);
24 const { prototype: arrayPrototype } = Array;
25 const { prototype: bufferPrototype } = Buffer;
26 const { iterator: iteratorSymbol } = Symbol;
27 const { prototype: rePrototype } = RegExp;
28 const { prototype: typedArrayPrototype } = TypedArray;
29 const { prototype: viewPrototype } = View;
30
31 const { [iteratorSymbol]: arrayIterator } = arrayPrototype;
32 const {
33 next: arrayIteratorNext,
34 } = Object.getPrototypeOf([][iteratorSymbol]());
35 const argumentIterablePrototype = {
36 [iteratorSymbol]() {
37 return {
38 next: bind(
39 arrayIteratorNext,
40 call(arrayIterator, this.args, []),
41 [],
42 ),
43 };
44 },
45 };
46 const binaryCodeUnitIterablePrototype = {
47 [iteratorSymbol]() {
48 return {
49 next: bind(
50 arrayIteratorNext,
51 call(arrayIterator, this, []),
52 [],
53 ),
54 };
55 },
56 };
57
58 const getBufferByteLength =
59 Object.getOwnPropertyDescriptor(bufferPrototype, "byteLength").get;
60 const getTypedArrayBuffer =
61 Object.getOwnPropertyDescriptor(typedArrayPrototype, "buffer").get;
62 const getViewBuffer =
63 Object.getOwnPropertyDescriptor(viewPrototype, "buffer").get;
64 const { exec: reExec } = rePrototype;
65 const {
66 getUint8: viewGetUint8,
67 setUint8: viewSetUint8,
68 setUint16: viewSetUint16,
69 } = viewPrototype;
70
71 /**
72 * Returns an ArrayBuffer for encoding generated from the provided
73 * arguments.
74 */
75 const bufferFromArgs = ($, $s) =>
76 $ instanceof Buffer
77 ? $
78 : $ instanceof View
79 ? call(getViewBuffer, $, [])
80 : $ instanceof TypedArray
81 ? call(getTypedArrayBuffer, $, [])
82 : ((string) =>
83 call(
84 getViewBuffer,
85 reduce(
86 string,
87 (result, ucsCharacter, index) => (
88 call(viewSetUint16, result, [
89 index * 2,
90 getCodeUnit(ucsCharacter, 0),
91 ]), result
92 ),
93 new View(new Buffer(string.length * 2)),
94 ),
95 [],
96 ))(
97 typeof $ == "string"
98 ? $
99 : hasOwnProperty($, "raw")
100 ? rawString(
101 $,
102 ...objectCreate(argumentIterablePrototype, {
103 args: { value: $s },
104 }),
105 )
106 : `${$}`,
107 );
108
109 /**
110 * Returns the result of decoding the provided base16 string into an
111 * ArrayBuffer.
112 *
113 * ※ This function is not exposed.
114 */
115 const decodeBase16 = (source) => {
116 const u4s = map(
117 source,
118 (ucsCharacter) => {
119 const code = getCodeUnit(ucsCharacter, 0);
120 const result = code >= 0x30 && code <= 0x39
121 ? code - 48
122 : code >= 0x41 && code <= 0x46
123 ? code - 55
124 : code >= 0x61 && code <= 0x66
125 ? code - 87
126 : -1;
127 if (result < 0) {
128 throw new RangeError(
129 `Piscēs: Invalid character in Base64: ${ucsCharacter}.`,
130 );
131 } else {
132 return result;
133 }
134 },
135 );
136 const { length } = u4s;
137 if (length % 2 == 1) {
138 // The length is such that an entire letter would be dropped during
139 // a forgiving decode.
140 throw new RangeError(
141 `Piscēs: Base16 string has invalid length: ${source}.`,
142 );
143 } else {
144 // Every letter contributes at least some bits to the result.
145 const dataView = new View(new Buffer(floor(length / 2)));
146 for (let index = 0; index < length - 1;) {
147 call(viewSetUint8, dataView, [
148 floor(index / 2),
149 (u4s[index] << 4) | u4s[++index, index++],
150 ]);
151 }
152 return call(getViewBuffer, dataView, []);
153 }
154 };
155
156 /**
157 * Returns the result of decoding the provided base32 string into an
158 * ArrayBuffer.
159 *
160 * If the second argument is truthy, uses Crockford’s encoding rather
161 * than the RFC’s (see <https://www.crockford.com/base32.html>). This
162 * is more human‐friendly and tolerant. Check digits are not supported.
163 *
164 * ※ This function is not exposed.
165 */
166 const decodeBase32 = (source, wrmg) => {
167 const u5s = map(
168 wrmg
169 ? stringReplace(source, /-/gu, "")
170 : source.length % 8 == 0
171 ? stringReplace(source, /(?:=|={3,4}|={6})$/u, "")
172 : source,
173 (ucsCharacter) => {
174 const code = getCodeUnit(ucsCharacter, 0);
175 const result = wrmg
176 ? code >= 0x30 && code <= 0x39
177 ? code - 48
178 : code >= 0x41 && code <= 0x48
179 ? code - 55
180 : code == 0x49
181 ? 1 // I
182 : code >= 0x4A && code <= 0x4B
183 ? code - 56
184 : code == 0x4C
185 ? 1 // L
186 : code >= 0x4D && code <= 0x4E
187 ? code - 57
188 : code == 0x4F
189 ? 0 // O
190 : code >= 0x50 && code <= 0x54
191 ? code - 58
192 // U is skipped
193 : code >= 0x56 && code <= 0x5A
194 ? code - 59
195 : code >= 0x61 && code <= 0x68
196 ? code - 87
197 : code == 0x69
198 ? 1 // i
199 : code >= 0x6A && code <= 0x6B
200 ? code - 88
201 : code == 0x6C
202 ? 1 // l
203 : code >= 0x6D && code <= 0x6E
204 ? code - 89
205 : code == 0x6F
206 ? 0 // o
207 : code >= 0x70 && code <= 0x74
208 ? code - 90
209 // u is skipped
210 : code >= 0x76 && code <= 0x7A
211 ? code - 91
212 : -1
213 : code >= 0x41 && code <= 0x5A
214 ? code - 65
215 : code >= 0x61 && code <= 0x7A
216 ? code - 97 // same result as above; case insensitive
217 : code >= 0x32 && code <= 0x37
218 ? code - 24 // digits 2–7 map to 26–31
219 : -1;
220 if (result < 0) {
221 throw new RangeError(
222 `Piscēs: Invalid character in Base32: ${ucsCharacter}.`,
223 );
224 } else {
225 return result;
226 }
227 },
228 );
229 const { length } = u5s;
230 const lengthMod8 = length % 8;
231 if (lengthMod8 == 1 || lengthMod8 == 3 || lengthMod8 == 6) {
232 // The length is such that an entire letter would be dropped during
233 // a forgiving decode.
234 throw new RangeError(
235 `Piscēs: Base32 string has invalid length: ${source}.`,
236 );
237 } else {
238 // Every letter contributes at least some bits to the result.
239 const dataView = new View(new Buffer(floor(length * 5 / 8)));
240 for (let index = 0; index < length - 1;) {
241 // The final index is not handled; if the string is not divisible
242 // by 8, some bits might be dropped. This matches the “forgiving
243 // decode” behaviour specified by WhatW·G for base64.
244 const dataIndex = ceil(index * 5 / 8);
245 const remainder = index % 8;
246 if (remainder == 0) {
247 call(viewSetUint8, dataView, [
248 dataIndex,
249 u5s[index] << 3 | u5s[++index] >> 2,
250 ]);
251 } else if (remainder == 1) {
252 call(viewSetUint8, dataView, [
253 dataIndex,
254 u5s[index] << 6 | u5s[++index] << 1 | u5s[++index] >> 4,
255 ]);
256 } else if (remainder == 3) {
257 call(viewSetUint8, dataView, [
258 dataIndex,
259 u5s[index] << 4 | u5s[++index] >> 1,
260 ]);
261 } else if (remainder == 4) {
262 call(viewSetUint8, dataView, [
263 dataIndex,
264 u5s[index] << 7 | u5s[++index] << 2 | u5s[++index] >> 3,
265 ]);
266 } else { // remainder == 6
267 call(viewSetUint8, dataView, [
268 dataIndex,
269 u5s[index] << 5 | u5s[++index, index++],
270 ]);
271 }
272 }
273 return call(getViewBuffer, dataView, []);
274 }
275 };
276
277 /**
278 * Returns the result of decoding the provided base64 string into an
279 * ArrayBuffer.
280 *
281 * ※ This function is not exposed.
282 */
283 const decodeBase64 = (source, safe = false) => {
284 const u6s = map(
285 source.length % 4 == 0
286 ? stringReplace(source, /={1,2}$/u, "")
287 : source,
288 (ucsCharacter) => {
289 const code = getCodeUnit(ucsCharacter, 0);
290 const result = code >= 0x41 && code <= 0x5A
291 ? code - 65
292 : code >= 0x61 && code <= 0x7A
293 ? code - 71
294 : code >= 0x30 && code <= 0x39
295 ? code + 4
296 : code == (safe ? 0x2D : 0x2B)
297 ? 62
298 : code == (safe ? 0x5F : 0x2F)
299 ? 63
300 : -1;
301 if (result < 0) {
302 throw new RangeError(
303 `Piscēs: Invalid character in Base64: ${ucsCharacter}.`,
304 );
305 } else {
306 return result;
307 }
308 },
309 );
310 const { length } = u6s;
311 if (length % 4 == 1) {
312 // The length is such that an entire letter would be dropped during
313 // a forgiving decode.
314 throw new RangeError(
315 `Piscēs: Base64 string has invalid length: ${source}.`,
316 );
317 } else {
318 // Every letter contributes at least some bits to the result.
319 const dataView = new View(new Buffer(floor(length * 3 / 4)));
320 for (let index = 0; index < length - 1;) {
321 // The final index is not handled; if the string is not divisible
322 // by 4, some bits might be dropped. This matches the “forgiving
323 // decode” behaviour specified by WhatW·G for base64.
324 const dataIndex = ceil(index * 3 / 4);
325 const remainder = index % 4;
326 if (remainder == 0) {
327 call(viewSetUint8, dataView, [
328 dataIndex,
329 u6s[index] << 2 | u6s[++index] >> 4,
330 ]);
331 } else if (remainder == 1) {
332 call(viewSetUint8, dataView, [
333 dataIndex,
334 u6s[index] << 4 | u6s[++index] >> 2,
335 ]);
336 } else { // remainder == 2
337 call(viewSetUint8, dataView, [
338 dataIndex,
339 u6s[index] << 6 | u6s[++index, index++],
340 ]);
341 }
342 }
343 return call(getViewBuffer, dataView, []);
344 }
345 };
346
347 /**
348 * Returns the result of encoding the provided ArrayBuffer into a
349 * base16 string.
350 *
351 * ※ This function is not exposed.
352 */
353 const encodeBase16 = (buffer) => {
354 const dataView = new View(buffer);
355 const byteLength = call(getBufferByteLength, buffer, []);
356 const minimumLengthOfResults = byteLength * 2;
357 const resultingCodeUnits = fill(
358 objectCreate(
359 binaryCodeUnitIterablePrototype,
360 { length: { value: minimumLengthOfResults } },
361 ),
362 0x3D,
363 );
364 for (let index = 0; index < byteLength;) {
365 const codeUnitIndex = index * 2;
366 const datum = call(viewGetUint8, dataView, [index++]);
367 const u4s = [datum >> 4, datum & 0xF];
368 for (let u4i = 0; u4i < 2; ++u4i) {
369 const u4 = u4s[u4i];
370 const result = u4 < 10 ? u4 + 48 : u4 < 16 ? u4 + 55 : -1;
371 if (result < 0) {
372 throw new RangeError(
373 `Piscēs: Unexpected Base16 value: ${u4}.`,
374 );
375 } else {
376 resultingCodeUnits[codeUnitIndex + u4i] = result;
377 }
378 }
379 }
380 return stringFromCodeUnits(...resultingCodeUnits);
381 };
382
383 /**
384 * Returns the result of encoding the provided ArrayBuffer into a
385 * base32 string.
386 *
387 * ※ This function is not exposed.
388 */
389 const encodeBase32 = (buffer, wrmg = false) => {
390 const dataView = new View(buffer);
391 const byteLength = call(getBufferByteLength, buffer, []);
392 const minimumLengthOfResults = ceil(byteLength * 8 / 5);
393 const fillByte = wrmg ? 0x2D : 0x3D;
394 const resultingCodeUnits = fill(
395 objectCreate(
396 binaryCodeUnitIterablePrototype,
397 {
398 length: {
399 value: minimumLengthOfResults +
400 (8 - (minimumLengthOfResults % 8)) % 8,
401 },
402 },
403 ),
404 fillByte,
405 );
406 for (let index = 0; index < byteLength;) {
407 const codeUnitIndex = ceil(index * 8 / 5);
408 const currentIndex = codeUnitIndex + +(
409 0b01011 & 1 << index % 5 &&
410 resultingCodeUnits[codeUnitIndex] != fillByte
411 ); // bytes 0, 1 & 3 handle two letters; this is for the second
412 const remainder = currentIndex % 8;
413 const currentByte = call(viewGetUint8, dataView, [index]);
414 const nextByte =
415 0b01011010 & 1 << remainder && ++index < byteLength
416 // digits 1, 3, 4 & 6 span multiple bytes
417 ? call(viewGetUint8, dataView, [index])
418 : 0;
419 const u5 = remainder == 0
420 ? currentByte >> 3
421 : remainder == 1
422 ? (currentByte & 0b00000111) << 2 | nextByte >> 6
423 : remainder == 2
424 ? (currentByte & 0b00111111) >> 1
425 : remainder == 3
426 ? (currentByte & 0b00000001) << 4 | nextByte >> 4
427 : remainder == 4
428 ? (currentByte & 0b00001111) << 1 | nextByte >> 7
429 : remainder == 5
430 ? (currentByte & 0b01111111) >> 2
431 : remainder == 6
432 ? (currentByte & 0b00000011) << 3 | nextByte >> 5
433 : (++index, currentByte & 0b00011111); // remainder == 7
434 const result = wrmg
435 ? u5 < 10 ? u5 + 48 : u5 < 18
436 ? u5 + 55
437 // skip I
438 : u5 < 20
439 ? u5 + 56
440 // skip L
441 : u5 < 22
442 ? u5 + 57
443 // skip O
444 : u5 < 27
445 ? u5 + 58
446 // skip U
447 : u5 < 32
448 ? u5 + 59
449 : -1
450 : u5 < 26
451 ? u5 + 65
452 : u5 < 32
453 ? u5 + 24
454 : -1;
455 if (result < 0) {
456 throw new RangeError(`Piscēs: Unexpected Base32 value: ${u5}.`);
457 } else {
458 resultingCodeUnits[currentIndex] = result;
459 }
460 }
461 const answer = stringFromCodeUnits(...resultingCodeUnits);
462 return wrmg ? answer.replace(/-+$/u, "") : answer;
463 };
464
465 /**
466 * Returns the result of encoding the provided ArrayBuffer into a
467 * base64 string.
468 *
469 * ※ This function is not exposed.
470 */
471 const encodeBase64 = (buffer, safe = false) => {
472 const dataView = new View(buffer);
473 const byteLength = call(getBufferByteLength, buffer, []);
474 const minimumLengthOfResults = ceil(byteLength * 4 / 3);
475 const resultingCodeUnits = fill(
476 objectCreate(
477 binaryCodeUnitIterablePrototype,
478 {
479 length: {
480 value: minimumLengthOfResults +
481 (4 - (minimumLengthOfResults % 4)) % 4,
482 },
483 },
484 ),
485 0x3D,
486 );
487 for (let index = 0; index < byteLength;) {
488 const codeUnitIndex = ceil(index * 4 / 3);
489 const currentIndex = codeUnitIndex + +(
490 index % 3 == 0 && resultingCodeUnits[codeUnitIndex] != 0x3D
491 ); // every third byte handles two letters; this is for the second
492 const remainder = currentIndex % 4;
493 const currentByte = call(viewGetUint8, dataView, [index]);
494 const nextByte = remainder % 3 && ++index < byteLength
495 // digits 1 & 2 span multiple bytes
496 ? call(viewGetUint8, dataView, [index])
497 : 0;
498 const u6 = remainder == 0
499 ? currentByte >> 2
500 : remainder == 1
501 ? (currentByte & 0b00000011) << 4 | nextByte >> 4
502 : remainder == 2
503 ? (currentByte & 0b00001111) << 2 | nextByte >> 6
504 : (++index, currentByte & 0b00111111); // remainder == 3
505 const result = u6 < 26
506 ? u6 + 65
507 : u6 < 52
508 ? u6 + 71
509 : u6 < 62
510 ? u6 - 4
511 : u6 < 63
512 ? (safe ? 0x2D : 0x2B)
513 : u6 < 64
514 ? (safe ? 0x5F : 0x2F)
515 : -1;
516 if (result < 0) {
517 throw new RangeError(`Piscēs: Unexpected Base64 value: ${u6}.`);
518 } else {
519 resultingCodeUnits[currentIndex] = result;
520 }
521 }
522 return stringFromCodeUnits(...resultingCodeUnits);
523 };
524
525 /**
526 * Returns a source string generated from the arguments passed to a
527 * tag function.
528 *
529 * ※ This function is not exposed.
530 */
531 const sourceFromArgs = ($, $s) =>
532 stringReplace(
533 typeof $ == "string" ? $ : hasOwnProperty($, "raw")
534 ? rawString(
535 $,
536 ...objectCreate(argumentIterablePrototype, {
537 args: { value: $s },
538 }),
539 )
540 : `${$}`,
541 /[\t\n\f\r ]+/gu,
542 "",
543 );
544
545 /**
546 * Returns an ArrayBuffer generated from the provided base16 string.
547 *
548 * This function can also be used as a tag for a template literal. The
549 * literal will be interpreted akin to `String.raw`.
550 *
551 * ☡ This function throws if the provided string is not a valid base16
552 * string.
553 */
554 export const base16Binary = ($, ...$s) =>
555 decodeBase16(sourceFromArgs($, $s));
556
557 /**
558 * Returns a (big‐endian) base16 string created from the provided typed
559 * array, buffer, or (16‐bit) string.
560 *
561 * This function can also be used as a tag for a template literal. The
562 * literal will be interpreted akin to `String.raw`.
563 */
564 export const base16String = ($, ...$s) =>
565 encodeBase16(bufferFromArgs($, $s));
566
567 /**
568 * Returns an ArrayBuffer generated from the provided base32 string.
569 *
570 * This function can also be used as a tag for a template literal. The
571 * literal will be interpreted akin to `String.raw`.
572 *
573 * ☡ This function throws if the provided string is not a valid base32
574 * string.
575 */
576 export const base32Binary = ($, ...$s) =>
577 decodeBase32(sourceFromArgs($, $s));
578
579 /**
580 * Returns a (big‐endian) base32 string created from the provided typed
581 * array, buffer, or (16‐bit) string.
582 *
583 * This function can also be used as a tag for a template literal. The
584 * literal will be interpreted akin to `String.raw`.
585 */
586 export const base32String = ($, ...$s) =>
587 encodeBase32(bufferFromArgs($, $s));
588
589 /**
590 * Returns an ArrayBuffer generated from the provided base64 string.
591 *
592 * This function can also be used as a tag for a template literal. The
593 * literal will be interpreted akin to `String.raw`.
594 *
595 * ☡ This function throws if the provided string is not a valid base64
596 * string.
597 */
598 export const base64Binary = ($, ...$s) =>
599 decodeBase64(sourceFromArgs($, $s));
600
601 /**
602 * Returns a (big‐endian) base64 string created from the provided typed
603 * array, buffer, or (16‐bit) string.
604 *
605 * This function can also be used as a tag for a template literal. The
606 * literal will be interpreted akin to `String.raw`.
607 */
608 export const base64String = ($, ...$s) =>
609 encodeBase64(bufferFromArgs($, $s));
610
611 /**
612 * Returns an ArrayBuffer generated from the provided filename‐safe
613 * base64 string.
614 *
615 * This function can also be used as a tag for a template literal. The
616 * literal will be interpreted akin to `String.raw`.
617 *
618 * ☡ This function throws if the provided string is not a valid
619 * filename‐safe base64 string.
620 */
621 export const filenameSafeBase64Binary = ($, ...$s) =>
622 decodeBase64(sourceFromArgs($, $s), true);
623
624 /**
625 * Returns a (big‐endian) filename‐safe base64 string created from the
626 * provided typed array, buffer, or (16‐bit) string.
627 *
628 * This function can also be used as a tag for a template literal. The
629 * literal will be interpreted akin to `String.raw`.
630 */
631 export const filenameSafeBase64String = ($, ...$s) =>
632 encodeBase64(bufferFromArgs($, $s), true);
633
634 /**
635 * Returns whether the provided value is a base16 string.
636 *
637 * ※ This function returns false if the provided value is not a string
638 * primitive.
639 */
640 export const isBase16 = ($) => {
641 if (typeof $ !== "string") {
642 return false;
643 } else {
644 const source = stringReplace($, /[\t\n\f\r ]+/gu, "");
645 return source.length % 2 != 1 &&
646 call(reExec, /[^0-9A-F]/iu, [source]) == null;
647 }
648 };
649
650 /**
651 * Returns whether the provided value is a base32 string.
652 *
653 * ※ This function returns false if the provided value is not a string
654 * primitive.
655 */
656 export const isBase32 = ($) => {
657 if (typeof $ !== "string") {
658 return false;
659 } else {
660 const source = stringReplace($, /[\t\n\f\r ]+/gu, "");
661 const trimmed = source.length % 8 == 0
662 ? stringReplace(source, /(?:=|={3,4}|={6})$/u, "")
663 : source;
664 return trimmed.length % 8 != 1 &&
665 call(reExec, /[^2-7A-Z/]/iu, [trimmed]) == null;
666 }
667 };
668
669 /**
670 * Returns whether the provided value is a Base64 string.
671 *
672 * ※ This function returns false if the provided value is not a string
673 * primitive.
674 */
675 export const isBase64 = ($) => {
676 if (typeof $ !== "string") {
677 return false;
678 } else {
679 const source = stringReplace($, /[\t\n\f\r ]+/gu, "");
680 const trimmed = source.length % 4 == 0
681 ? stringReplace(source, /={1,2}$/u, "")
682 : source;
683 return trimmed.length % 4 != 1 &&
684 call(reExec, /[^0-9A-Za-z+\/]/u, [trimmed]) == null;
685 }
686 };
687
688 /**
689 * Returns whether the provided value is a filename‐safe base64 string.
690 *
691 * ※ This function returns false if the provided value is not a string
692 * primitive.
693 */
694 export const isFilenameSafeBase64 = ($) => {
695 if (typeof $ !== "string") {
696 return false;
697 } else {
698 const source = stringReplace($, /[\t\n\f\r ]+/gu, "");
699 const trimmed = source.length % 4 == 0
700 ? stringReplace(source, /={1,2}$/u, "")
701 : source;
702 return trimmed.length % 4 != 1 &&
703 call(reExec, /[^0-9A-Za-z_-]/u, [trimmed]) == null;
704 }
705 };
706
707 /**
708 * Returns whether the provided value is a W·R·M·G (Crockford) base32
709 * string. Check digits are not supported.
710 *
711 * ※ This function returns false if the provided value is not a string
712 * primitive.
713 */
714 export const isWRMGBase32 = ($) => {
715 if (typeof $ !== "string") {
716 return false;
717 } else {
718 const source = stringReplace($, /[\t\n\f\r ]+/gu, "");
719 const trimmed = stringReplace(source, /-/gu, "");
720 return trimmed.length % 8 != 1 &&
721 call(reExec, /[^0-9A-TV-Z]/iu, [trimmed]) == null;
722 }
723 };
724
725 /**
726 * Returns an ArrayBuffer generated from the provided W·R·M·G
727 * (Crockford) base32 string.
728 *
729 * This function can also be used as a tag for a template literal. The
730 * literal will be interpreted akin to `String.raw`.
731 *
732 * ☡ This function throws if the provided string is not a valid W·R·M·G
733 * base32 string.
734 */
735 export const wrmgBase32Binary = ($, ...$s) =>
736 decodeBase32(sourceFromArgs($, $s), true);
737
738 /**
739 * Returns a (big‐endian) W·R·M·G (Crockford) base32 string created
740 * from the provided typed array, buffer, or (16‐bit) string.
741 *
742 * This function can also be used as a tag for a template literal. The
743 * literal will be interpreted akin to `String.raw`.
744 */
745 export const wrmgBase32String = ($, ...$s) =>
746 encodeBase32(bufferFromArgs($, $s), true);
This page took 0.118534 seconds and 5 git commands to generate.