UNPKG

4.16 kBJavaScriptView Raw
1/**
2 * Utility functions to work with buffers (Uint8Array).
3 *
4 * @module buffer
5 */
6
7import * as string from './string.js'
8import * as env from './environment.js'
9import * as array from './array.js'
10import * as math from './math.js'
11import * as encoding from './encoding.js'
12import * as decoding from './decoding.js'
13
14/**
15 * @param {number} len
16 */
17export const createUint8ArrayFromLen = len => new Uint8Array(len)
18
19/**
20 * Create Uint8Array with initial content from buffer
21 *
22 * @param {ArrayBuffer} buffer
23 * @param {number} byteOffset
24 * @param {number} length
25 */
26export const createUint8ArrayViewFromArrayBuffer = (buffer, byteOffset, length) => new Uint8Array(buffer, byteOffset, length)
27
28/**
29 * Create Uint8Array with initial content from buffer
30 *
31 * @param {ArrayBuffer} buffer
32 */
33export const createUint8ArrayFromArrayBuffer = buffer => new Uint8Array(buffer)
34
35/* c8 ignore start */
36/**
37 * @param {Uint8Array} bytes
38 * @return {string}
39 */
40const toBase64Browser = bytes => {
41 let s = ''
42 for (let i = 0; i < bytes.byteLength; i++) {
43 s += string.fromCharCode(bytes[i])
44 }
45 // eslint-disable-next-line no-undef
46 return btoa(s)
47}
48/* c8 ignore stop */
49
50/**
51 * @param {Uint8Array} bytes
52 * @return {string}
53 */
54const toBase64Node = bytes => Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength).toString('base64')
55
56/* c8 ignore start */
57/**
58 * @param {string} s
59 * @return {Uint8Array}
60 */
61const fromBase64Browser = s => {
62 // eslint-disable-next-line no-undef
63 const a = atob(s)
64 const bytes = createUint8ArrayFromLen(a.length)
65 for (let i = 0; i < a.length; i++) {
66 bytes[i] = a.charCodeAt(i)
67 }
68 return bytes
69}
70/* c8 ignore stop */
71
72/**
73 * @param {string} s
74 */
75const fromBase64Node = s => {
76 const buf = Buffer.from(s, 'base64')
77 return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength)
78}
79
80/* c8 ignore next */
81export const toBase64 = env.isBrowser ? toBase64Browser : toBase64Node
82
83/* c8 ignore next */
84export const fromBase64 = env.isBrowser ? fromBase64Browser : fromBase64Node
85
86/**
87 * Implements base64url - see https://datatracker.ietf.org/doc/html/rfc4648#section-5
88 * @param {Uint8Array} buf
89 */
90export const toBase64UrlEncoded = buf => toBase64(buf).replaceAll('+', '-').replaceAll('/', '_').replaceAll('=', '')
91
92/**
93 * @param {string} base64
94 */
95export const fromBase64UrlEncoded = base64 => fromBase64(base64.replaceAll('-', '+').replaceAll('_', '/'))
96
97/**
98 * Base64 is always a more efficient choice. This exists for utility purposes only.
99 *
100 * @param {Uint8Array} buf
101 */
102export const toHexString = buf => array.map(buf, b => b.toString(16).padStart(2, '0')).join('')
103
104/**
105 * Note: This function expects that the hex doesn't start with 0x..
106 *
107 * @param {string} hex
108 */
109export const fromHexString = hex => {
110 const hlen = hex.length
111 const buf = new Uint8Array(math.ceil(hlen / 2))
112 for (let i = 0; i < hlen; i += 2) {
113 buf[buf.length - i / 2 - 1] = Number.parseInt(hex.slice(hlen - i - 2, hlen - i), 16)
114 }
115 return buf
116}
117
118/**
119 * Copy the content of an Uint8Array view to a new ArrayBuffer.
120 *
121 * @param {Uint8Array} uint8Array
122 * @return {Uint8Array}
123 */
124export const copyUint8Array = uint8Array => {
125 const newBuf = createUint8ArrayFromLen(uint8Array.byteLength)
126 newBuf.set(uint8Array)
127 return newBuf
128}
129
130/**
131 * Encode anything as a UInt8Array. It's a pun on typescripts's `any` type.
132 * See encoding.writeAny for more information.
133 *
134 * @param {any} data
135 * @return {Uint8Array}
136 */
137export const encodeAny = data => {
138 const encoder = encoding.createEncoder()
139 encoding.writeAny(encoder, data)
140 return encoding.toUint8Array(encoder)
141}
142
143/**
144 * Decode an any-encoded value.
145 *
146 * @param {Uint8Array} buf
147 * @return {any}
148 */
149export const decodeAny = buf => decoding.readAny(decoding.createDecoder(buf))
150
151/**
152 * Shift Byte Array {N} bits to the left. Does not expand byte array.
153 *
154 * @param {Uint8Array} bs
155 * @param {number} N should be in the range of [0-7]
156 */
157export const shiftNBitsLeft = (bs, N) => {
158 if (N === 0) return bs
159 bs = new Uint8Array(bs)
160 bs[0] <<= N
161 for (let i = 1; i < bs.length; i++) {
162 bs[i - 1] |= bs[i] >>> (8 - N)
163 bs[i] <<= N
164 }
165 return bs
166}