-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathcodec.js
214 lines (185 loc) · 6.17 KB
/
codec.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
// Adapted from [base64.js](https://goo.gl/VxhUVz).
//
// Copyright 2007 The Closure Library Authors.
// Modifications Copyright 2016 Mikol Graves.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
(function (context) {
// -----------------------------------------------------------------------------
'use strict';
var id = 'codec';
var dependencies = ['./utf8'];
function factory(utf8) {
/**
* @type {Object}
* @private
*/
var charactersByByte = {};
/**
* @type {Object}
* @private
*/
var bytesByCharacter = {};
/**
* @const {string}
* @private
*/
/* jscs:disable maximumLineLength */
var ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
/* jscs:enable maximumLineLength */
(function () {
for (var x = 0, nx = ALPHABET.length; x < nx; x++) {
charactersByByte[x] = ALPHABET.charAt(x);
bytesByCharacter[charactersByByte[x]] = x;
}
}());
/**
* Base64-encode a string.
*
* @param {string} string A string to encode.
* @return {string} The base64-encoded string.
*/
function encodeString(string) {
return encodeBytes(utf8.asBytes(string));
}
/**
* Base64-decode a string.
*
* @param {string} string Input to decode (any whitespace is ignored).
* @return {string} The decoded value.
*/
function decodeAsString(string) {
return utf8.asString(decodeAsBytes(string));
}
/**
* Base64-encode an array of bytes.
*
* @param {Array<number>} input Bytes (that is numbers in [0, 255]) to encode.
* @return {string} The base64-encoded string.
*/
function encodeBytes(bytes) {
var map = charactersByByte;
var characters = [];
for (var i = 0; i < bytes.length; i += 3) {
var byte1 = bytes[i];
var haveByte2 = i + 1 < bytes.length;
var byte2 = haveByte2 ? bytes[i + 1] : 0;
var haveByte3 = i + 2 < bytes.length;
var byte3 = haveByte3 ? bytes[i + 2] : 0;
var b1 = byte1 >> 2;
var b2 = ((byte1 & 0x03) << 4) | (byte2 >> 4);
var b3 = ((byte2 & 0x0F) << 2) | (byte3 >> 6);
var b4 = byte3 & 0x3F;
if (!haveByte3) {
b4 = 64;
if (!haveByte2) {
b3 = 64;
}
}
characters.push(map[b1], map[b2], map[b3], map[b4]);
}
return characters.join('');
}
/**
* Base64-decode a string to an Array of numbers.
*
* In base-64 decoding, groups of four characters are converted into three
* bytes. If the encoder did not apply padding, the input length may not
* be a multiple of 4.
*
* In this case, the last group will have fewer than 4 characters, and
* padding will be inferred. If the group has one or two characters, it
* decodes to one byte. If the group has three characters, it decodes to
* two bytes.
*
* @param {string} input Input to decode. Any whitespace is ignored, and the
* input maybe encoded with either supported alphabet (or a mix thereof).
* @return {!Array<number>} Bytes representing the decoded value.
*/
function decodeAsBytes(input) {
var bytes = [];
var nx = input.length;
var x = 0;
/**
* @param {number} defaultValue Used for end-of-input.
* @return {number} The next 6-bit value or the default for end-of-input.
*/
function getByte(defaultValue) {
while (x < nx) {
var c = input.charAt(x++);
var b = bytesByCharacter[c];
if (b != null) {
return b;
}
if (!/^[\s\xa0]*$/.test(c)) {
throw Error('Unknown base64 encoding at character: ' + c);
}
// We encountered whitespace: loop around to the next input character.
}
return defaultValue;
}
while (true) {
var byte1 = getByte(-1);
var byte2 = getByte(0);
var byte3 = getByte(64);
var byte4 = getByte(64);
// The common case is that all four bytes are present, so if we have byte4
// we can skip over the truncated input special case handling.
if (byte4 === 64) {
if (byte1 === -1) {
// No input left to decode.
return bytes;
}
// Here we know an intermediate number of bytes are missing. The
// defaults for byte2, byte3 and byte4 apply the inferred padding rules
// per the public API documentation. That is, 1 byte missing should
// yield 2 bytes of output, but 2 or 3 missing bytes yield a single byte
// of output. (Recall that 64 corresponds the padding character).
}
var outByte1 = (byte1 << 2) | (byte2 >> 4);
bytes.push(outByte1);
if (byte3 != 64) {
var outByte2 = ((byte2 << 4) & 0xF0) | (byte3 >> 2);
bytes.push(outByte2);
if (byte4 != 64) {
var outByte3 = ((byte3 << 6) & 0xC0) | byte4;
bytes.push(outByte3);
}
}
}
}
return {
encodeString: encodeString,
decodeAsString: decodeAsString,
encodeBytes: encodeBytes,
decodeAsBytes: decodeAsBytes
};
}
// -----------------------------------------------------------------------------
var n = dependencies.length;
var o = 'object';
var r = /([^-_\s])[-_\s]+([^-_\s])/g;
function s(m, a, b) { return a + b.toUpperCase(); }
context = typeof global === o ? global : typeof window === o ? window : context;
if (typeof define === 'function' && define.amd) {
define(dependencies, function () {
return factory.apply(context, [].slice.call(arguments));
});
} else if (typeof module === o && module.exports) {
for (; n--;) { dependencies[n] = require(dependencies[n]); }
module.exports = factory.apply(context, dependencies);
} else {
for (; n--;) { dependencies[n] = context[dependencies[n]]; }
context[id.replace(r, s)] = factory.apply(context, dependencies);
}
}(this));