UNPKG

3.37 kBJavaScriptView Raw
1'use strict'
2
3exports.toByteArray = toByteArray
4exports.fromByteArray = fromByteArray
5
6var lookup = []
7var revLookup = []
8var Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array
9
10function init () {
11 var i
12 var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
13 var len = code.length
14
15 for (i = 0; i < len; i++) {
16 lookup[i] = code[i]
17 }
18
19 for (i = 0; i < len; ++i) {
20 revLookup[code.charCodeAt(i)] = i
21 }
22 revLookup['-'.charCodeAt(0)] = 62
23 revLookup['_'.charCodeAt(0)] = 63
24}
25
26init()
27
28function toByteArray (b64) {
29 var i, j, l, tmp, placeHolders, arr
30 var len = b64.length
31
32 if (len % 4 > 0) {
33 throw new Error('Invalid string. Length must be a multiple of 4')
34 }
35
36 // the number of equal signs (place holders)
37 // if there are two placeholders, than the two characters before it
38 // represent one byte
39 // if there is only one, then the three characters before it represent 2 bytes
40 // this is just a cheap hack to not do indexOf twice
41 placeHolders = b64[len - 2] === '=' ? 2 : b64[len - 1] === '=' ? 1 : 0
42
43 // base64 is 4/3 + up to two characters of the original data
44 arr = new Arr(len * 3 / 4 - placeHolders)
45
46 // if there are placeholders, only get up to the last complete 4 chars
47 l = placeHolders > 0 ? len - 4 : len
48
49 var L = 0
50
51 for (i = 0, j = 0; i < l; i += 4, j += 3) {
52 tmp = (revLookup[b64.charCodeAt(i)] << 18) | (revLookup[b64.charCodeAt(i + 1)] << 12) | (revLookup[b64.charCodeAt(i + 2)] << 6) | revLookup[b64.charCodeAt(i + 3)]
53 arr[L++] = (tmp & 0xFF0000) >> 16
54 arr[L++] = (tmp & 0xFF00) >> 8
55 arr[L++] = tmp & 0xFF
56 }
57
58 if (placeHolders === 2) {
59 tmp = (revLookup[b64.charCodeAt(i)] << 2) | (revLookup[b64.charCodeAt(i + 1)] >> 4)
60 arr[L++] = tmp & 0xFF
61 } else if (placeHolders === 1) {
62 tmp = (revLookup[b64.charCodeAt(i)] << 10) | (revLookup[b64.charCodeAt(i + 1)] << 4) | (revLookup[b64.charCodeAt(i + 2)] >> 2)
63 arr[L++] = (tmp >> 8) & 0xFF
64 arr[L++] = tmp & 0xFF
65 }
66
67 return arr
68}
69
70function tripletToBase64 (num) {
71 return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F]
72}
73
74function encodeChunk (uint8, start, end) {
75 var tmp
76 var output = []
77 for (var i = start; i < end; i += 3) {
78 tmp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2])
79 output.push(tripletToBase64(tmp))
80 }
81 return output.join('')
82}
83
84function fromByteArray (uint8) {
85 var tmp
86 var len = uint8.length
87 var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes
88 var output = ''
89 var parts = []
90 var maxChunkLength = 16383 // must be multiple of 3
91
92 // go through the array every three bytes, we'll deal with trailing stuff later
93 for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {
94 parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength)))
95 }
96
97 // pad the end with zeros, but make sure to not forget the extra bytes
98 if (extraBytes === 1) {
99 tmp = uint8[len - 1]
100 output += lookup[tmp >> 2]
101 output += lookup[(tmp << 4) & 0x3F]
102 output += '=='
103 } else if (extraBytes === 2) {
104 tmp = (uint8[len - 2] << 8) + (uint8[len - 1])
105 output += lookup[tmp >> 10]
106 output += lookup[(tmp >> 4) & 0x3F]
107 output += lookup[(tmp << 2) & 0x3F]
108 output += '='
109 }
110
111 parts.push(output)
112
113 return parts.join('')
114}