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
);