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. 4 5 /** @fileoverview Various string utility functions */ 6 'use strict'; 7 8 /** 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. 14 */ 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); 19 return bytes; 20 } 21 22 /** 23 * Converts a byte array to a string. 24 * @param {(Uint8Array|Array.<number>)} b input byte array. 25 * @return {string} result. 26 */ 27 function UTIL_BytesToString(b) { 28 return String.fromCharCode.apply(null, b); 29 } 30 31 /** 32 * Converts a byte array to a hex string. 33 * @param {(Uint8Array|Array.<number>)} b input byte array. 34 * @return {string} result. 35 */ 36 function UTIL_BytesToHex(b) { 37 if (!b) return '(null)'; 38 var hexchars = '0123456789ABCDEF'; 39 var hexrep = new Array(b.length * 2); 40 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); 44 } 45 return hexrep.join(''); 46 } 47 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); 52 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); 57 } 58 return (sep ? hexrep.slice(1) : hexrep).join(''); 59 } 60 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); 67 } 68 return res; 69 } 70 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); 77 } 78 return res; 79 } 80 81 function UTIL_equalArrays(a, b) { 82 if (!a || !b) return false; 83 if (a.length != b.length) return false; 84 var accu = 0; 85 for (var i = 0; i < a.length; ++i) 86 accu |= a[i] ^ b[i]; 87 return accu === 0; 88 } 89 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; 96 } 97 return false; 98 } 99 100 function UTIL_gtArrays(a, b) { 101 return UTIL_ltArrays(b, a); 102 } 103 104 function UTIL_geArrays(a, b) { 105 return !UTIL_ltArrays(a, b); 106 } 107 108 function UTIL_unionArrays(a, b) { 109 var obj = {}; 110 for (var i = 0; i < a.length; i++) { 111 obj[a[i]] = a[i]; 112 } 113 for (var i = 0; i < b.length; i++) { 114 obj[b[i]] = b[i]; 115 } 116 var union = []; 117 for (var k in obj) { 118 union.push(obj[k]); 119 } 120 return union; 121 } 122 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; 128 return tmp; 129 } 130 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; 137 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++) { 142 var link = links[i]; 143 if (link.type == faviconLink.type && link.rel == faviconLink.rel) { 144 head.removeChild(link); 145 } 146 } 147 148 // Add in the new one 149 head.appendChild(faviconLink); 150 } 151 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) 156 a[i] = 0; 157 } 158 } 159 160 /** 161 * Parse SEQ(INT, INT) from ASN1 byte array. 162 * @param {(Uint8Array|Array.<number>)} a input to parse from. 163 * @return {{'r': !Array.<number>, 's': !Array.<number>}|null} 164 */ 165 function UTIL_Asn1SignatureToJson(a) { 166 if (a.length < 6) return null; // Too small to be valid 167 if (a[0] != 0x30) return null; // Not SEQ 168 var l = a[1] & 255; 169 if (l & 0x80) return null; // SEQ.size too large 170 if (a.length != 2 + l) return null; // SEQ size does not match input 171 172 function parseInt(off) { 173 if (a[off] != 0x02) return null; // Not INT 174 var l = a[off + 1] & 255; 175 if (l & 0x80) return null; // INT.size too large 176 if (off + 2 + l > a.length) return null; // Out of bounds 177 return a.slice(off + 2, off + 2 + l); 178 } 179 180 var r = parseInt(2); 181 if (!r) return null; 182 183 var s = parseInt(2 + 2 + r.length); 184 if (!s) return null; 185 186 return {'r': r, 's': s}; 187 } 188 189 // hr:min:sec.milli string 190 function UTIL_time() { 191 var d = new Date(); 192 var m = '000' + d.getMilliseconds(); 193 var s = d.toTimeString().substring(0, 8) + '.' + m.substring(m.length - 3); 194 return s; 195 } 196 var UTIL_events = []; 197 var UTIL_max_events = 500; 198 199 function UTIL_fmt(s) { 200 var line = UTIL_time() + ' ' + s; 201 if (UTIL_events.push(line) > UTIL_max_events) { 202 // Drop from head. 203 UTIL_events.splice(0, UTIL_events.length - UTIL_max_events); 204 } 205 return line; 206 } 207