1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 /** @fileoverview Various string utility functions */
9 * Converts a string to an array of bytes.
10 * @param {string} s The string to convert.
11 * @param {(Array|Uint8Array)=} bytes The Array-like object into which to store
12 * the bytes. A new Array will be created if not provided.
13 * @return {(Array|Uint8Array)} An array of bytes representing the string.
15 function UTIL_StringToBytes(s, bytes) {
16 bytes = bytes || new Array(s.length);
17 for (var i = 0; i < s.length; ++i)
18 bytes[i] = s.charCodeAt(i);
23 * Converts a byte array to a string.
24 * @param {(Uint8Array|Array<number>)} b input byte array.
25 * @return {string} result.
27 function UTIL_BytesToString(b) {
28 return String.fromCharCode.apply(null, b);
32 * Converts a byte array to a hex string.
33 * @param {(Uint8Array|Array<number>)} b input byte array.
34 * @return {string} result.
36 function UTIL_BytesToHex(b) {
37 if (!b) return '(null)';
38 var hexchars = '0123456789ABCDEF';
39 var hexrep = new Array(b.length * 2);
41 for (var i = 0; i < b.length; ++i) {
42 hexrep[i * 2 + 0] = hexchars.charAt((b[i] >> 4) & 15);
43 hexrep[i * 2 + 1] = hexchars.charAt(b[i] & 15);
45 return hexrep.join('');
48 function UTIL_BytesToHexWithSeparator(b, sep) {
49 var hexchars = '0123456789ABCDEF';
50 var stride = 2 + (sep ? 1 : 0);
51 var hexrep = new Array(b.length * stride);
53 for (var i = 0; i < b.length; ++i) {
54 if (sep) hexrep[i * stride + 0] = sep;
55 hexrep[i * stride + stride - 2] = hexchars.charAt((b[i] >> 4) & 15);
56 hexrep[i * stride + stride - 1] = hexchars.charAt(b[i] & 15);
58 return (sep ? hexrep.slice(1) : hexrep).join('');
61 function UTIL_HexToBytes(h) {
62 var hexchars = '0123456789ABCDEFabcdef';
63 var res = new Uint8Array(h.length / 2);
64 for (var i = 0; i < h.length; i += 2) {
65 if (hexchars.indexOf(h.substring(i, i + 1)) == -1) break;
66 res[i / 2] = parseInt(h.substring(i, i + 2), 16);
71 function UTIL_HexToArray(h) {
72 var hexchars = '0123456789ABCDEFabcdef';
73 var res = new Array(h.length / 2);
74 for (var i = 0; i < h.length; i += 2) {
75 if (hexchars.indexOf(h.substring(i, i + 1)) == -1) break;
76 res[i / 2] = parseInt(h.substring(i, i + 2), 16);
81 function UTIL_equalArrays(a, b) {
82 if (!a || !b) return false;
83 if (a.length != b.length) return false;
85 for (var i = 0; i < a.length; ++i)
90 function UTIL_ltArrays(a, b) {
91 if (a.length < b.length) return true;
92 if (a.length > b.length) return false;
93 for (var i = 0; i < a.length; ++i) {
94 if (a[i] < b[i]) return true;
95 if (a[i] > b[i]) return false;
100 function UTIL_gtArrays(a, b) {
101 return UTIL_ltArrays(b, a);
104 function UTIL_geArrays(a, b) {
105 return !UTIL_ltArrays(a, b);
108 function UTIL_unionArrays(a, b) {
110 for (var i = 0; i < a.length; i++) {
113 for (var i = 0; i < b.length; i++) {
123 function UTIL_getRandom(a) {
124 var tmp = new Array(a);
125 var rnd = new Uint8Array(a);
126 window.crypto.getRandomValues(rnd); // Yay!
127 for (var i = 0; i < a; ++i) tmp[i] = rnd[i] & 255;
131 function UTIL_setFavicon(icon) {
132 // Construct a new favion link tag
133 var faviconLink = document.createElement('link');
134 faviconLink.rel = 'Shortcut Icon';
135 faviconLink.type = 'image/x-icon';
136 faviconLink.href = icon;
138 // Remove the old favion, if it exists
139 var head = document.getElementsByTagName('head')[0];
140 var links = head.getElementsByTagName('link');
141 for (var i = 0; i < links.length; i++) {
143 if (link.type == faviconLink.type && link.rel == faviconLink.rel) {
144 head.removeChild(link);
148 // Add in the new one
149 head.appendChild(faviconLink);
152 // Erase all entries in array
153 function UTIL_clear(a) {
154 if (a instanceof Array) {
155 for (var i = 0; i < a.length; ++i)
160 // Type tags used for ASN.1 encoding of ECDSA signatures
162 var UTIL_ASN_INT = 0x02;
164 var UTIL_ASN_SEQUENCE = 0x30;
167 * Parse SEQ(INT, INT) from ASN1 byte array.
168 * @param {(Uint8Array|Array<number>)} a input to parse from.
169 * @return {{'r': !Array<number>, 's': !Array<number>}|null}
171 function UTIL_Asn1SignatureToJson(a) {
172 if (a.length < 6) return null; // Too small to be valid
173 if (a[0] != UTIL_ASN_SEQUENCE) return null;
175 if (l & 0x80) return null; // SEQ.size too large
176 if (a.length != 2 + l) return null; // SEQ size does not match input
178 function parseInt(off) {
179 if (a[off] != UTIL_ASN_INT) return null;
180 var l = a[off + 1] & 255;
181 if (l & 0x80) return null; // INT.size too large
182 if (off + 2 + l > a.length) return null; // Out of bounds
183 return a.slice(off + 2, off + 2 + l);
189 var s = parseInt(2 + 2 + r.length);
192 return {'r': r, 's': s};
196 * Encode a JSON signature {r,s} as an ASN1 SEQ(INT, INT). May modify sig
197 * @param {{'r': (!Array<number>|undefined), 's': !Array<number>}} sig
198 * @return {!Uint8Array}
200 function UTIL_JsonSignatureToAsn1(sig) {
204 // ASN.1 integers are arbitrary length msb first and signed.
205 // sig.r and sig.s are 256 bits msb first but _unsigned_, so we must
206 // prepend a zero byte in case their high bit is set.
207 if (rbytes[0] & 0x80)
209 if (sbytes[0] & 0x80)
212 var len = 4 + rbytes.length + sbytes.length;
213 var buf = new Uint8Array(2 + len);
215 buf[i++] = UTIL_ASN_SEQUENCE;
218 buf[i++] = UTIL_ASN_INT;
219 buf[i++] = rbytes.length;
223 buf[i++] = UTIL_ASN_INT;
224 buf[i++] = sbytes.length;
230 function UTIL_prepend_zero(s, n) {
231 if (s.length == n) return s;
233 for (var i = 0; i < n - l; ++i) {
239 // hr:min:sec.milli string
240 function UTIL_time() {
242 var m = UTIL_prepend_zero((d.getMonth() + 1).toString(), 2);
243 var t = UTIL_prepend_zero(d.getDate().toString(), 2);
244 var H = UTIL_prepend_zero(d.getHours().toString(), 2);
245 var M = UTIL_prepend_zero(d.getMinutes().toString(), 2);
246 var S = UTIL_prepend_zero(d.getSeconds().toString(), 2);
247 var L = UTIL_prepend_zero((d.getMilliseconds() * 1000).toString(), 6);
248 return m + t + ' ' + H + ':' + M + ':' + S + '.' + L;
251 var UTIL_events = [];
252 var UTIL_max_events = 500;
254 function UTIL_fmt(s) {
255 var line = UTIL_time() + ': ' + s;
256 if (UTIL_events.push(line) > UTIL_max_events) {
258 UTIL_events.splice(0, UTIL_events.length - UTIL_max_events);