1 /** 2 * UUID.js: The RFC-compliant UUID generator for JavaScript. 3 * 4 * @fileOverview 5 * @author LiosK 6 * @version 3.2 7 * @license The MIT License: Copyright (c) 2010-2012 LiosK. 8 */ 9 10 /** @constructor */ 11 var UUID; 12 13 UUID = (function(overwrittenUUID) { 14 15 // Core Component {{{ 16 17 /** @lends UUID */ 18 function UUID() {} 19 20 /** 21 * The simplest function to get an UUID string. 22 * @returns {string} A version 4 UUID string. 23 */ 24 UUID.generate = function() { 25 var rand = UUID._getRandomInt, hex = UUID._hexAligner; 26 return hex(rand(32), 8) // time_low 27 + "-" 28 + hex(rand(16), 4) // time_mid 29 + "-" 30 + hex(0x4000 | rand(12), 4) // time_hi_and_version 31 + "-" 32 + hex(0x8000 | rand(14), 4) // clock_seq_hi_and_reserved clock_seq_low 33 + "-" 34 + hex(rand(48), 12); // node 35 }; 36 37 /** 38 * Returns an unsigned x-bit random integer. 39 * @param {int} x A positive integer ranging from 0 to 53, inclusive. 40 * @returns {int} An unsigned x-bit random integer (0 <= f(x) < 2^x). 41 */ 42 UUID._getRandomInt = function(x) { 43 if (x < 0) return NaN; 44 if (x <= 30) return (0 | Math.random() * (1 << x)); 45 if (x <= 53) return (0 | Math.random() * (1 << 30)) 46 + (0 | Math.random() * (1 << x - 30)) * (1 << 30); 47 return NaN; 48 }; 49 50 /** 51 * Returns a function that converts an integer to a zero-filled string. 52 * @param {int} radix 53 * @returns {function(num, length)} 54 */ 55 UUID._getIntAligner = function(radix) { 56 return function(num, length) { 57 var str = num.toString(radix), i = length - str.length, z = "0"; 58 for (; i > 0; i >>>= 1, z += z) { if (i & 1) { str = z + str; } } 59 return str; 60 }; 61 }; 62 63 UUID._hexAligner = UUID._getIntAligner(16); 64 65 // }}} 66 67 // UUID Object Component {{{ 68 69 /** 70 * Names of each UUID field. 71 * @type string[] 72 * @constant 73 * @since 3.0 74 */ 75 UUID.FIELD_NAMES = ["timeLow", "timeMid", "timeHiAndVersion", 76 "clockSeqHiAndReserved", "clockSeqLow", "node"]; 77 78 /** 79 * Sizes of each UUID field. 80 * @type int[] 81 * @constant 82 * @since 3.0 83 */ 84 UUID.FIELD_SIZES = [32, 16, 16, 8, 8, 48]; 85 86 /** 87 * Generates a version 4 {@link UUID}. 88 * @returns {UUID} A version 4 {@link UUID} object. 89 * @since 3.0 90 */ 91 UUID.genV4 = function() { 92 var rand = UUID._getRandomInt; 93 return new UUID()._init(rand(32), rand(16), // time_low time_mid 94 0x4000 | rand(12), // time_hi_and_version 95 0x80 | rand(6), // clock_seq_hi_and_reserved 96 rand(8), rand(48)); // clock_seq_low node 97 }; 98 99 /** 100 * Converts hexadecimal UUID string to an {@link UUID} object. 101 * @param {string} strId UUID hexadecimal string representation ("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"). 102 * @returns {UUID} {@link UUID} object or null. 103 * @since 3.0 104 */ 105 UUID.parse = function(strId) { 106 var r, p = /^\s*(urn:uuid:|\{)?([0-9a-f]{8})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{2})([0-9a-f]{2})-([0-9a-f]{12})(\})?\s*$/i; 107 if (r = p.exec(strId)) { 108 var l = r[1] || "", t = r[8] || ""; 109 if (((l + t) === "") || 110 (l === "{" && t === "}") || 111 (l.toLowerCase() === "urn:uuid:" && t === "")) { 112 return new UUID()._init(parseInt(r[2], 16), parseInt(r[3], 16), 113 parseInt(r[4], 16), parseInt(r[5], 16), 114 parseInt(r[6], 16), parseInt(r[7], 16)); 115 } 116 } 117 return null; 118 }; 119 120 /** 121 * Initializes {@link UUID} object. 122 * @param {uint32} [timeLow=0] time_low field (octet 0-3). 123 * @param {uint16} [timeMid=0] time_mid field (octet 4-5). 124 * @param {uint16} [timeHiAndVersion=0] time_hi_and_version field (octet 6-7). 125 * @param {uint8} [clockSeqHiAndReserved=0] clock_seq_hi_and_reserved field (octet 8). 126 * @param {uint8} [clockSeqLow=0] clock_seq_low field (octet 9). 127 * @param {uint48} [node=0] node field (octet 10-15). 128 * @returns {UUID} this. 129 */ 130 UUID.prototype._init = function() { 131 var names = UUID.FIELD_NAMES, sizes = UUID.FIELD_SIZES; 132 var bin = UUID._binAligner, hex = UUID._hexAligner; 133 134 /** 135 * List of UUID field values (as integer values). 136 * @type int[] 137 */ 138 this.intFields = new Array(6); 139 140 /** 141 * List of UUID field values (as binary bit string values). 142 * @type string[] 143 */ 144 this.bitFields = new Array(6); 145 146 /** 147 * List of UUID field values (as hexadecimal string values). 148 * @type string[] 149 */ 150 this.hexFields = new Array(6); 151 152 for (var i = 0; i < 6; i++) { 153 var intValue = parseInt(arguments[i] || 0); 154 this.intFields[i] = this.intFields[names[i]] = intValue; 155 this.bitFields[i] = this.bitFields[names[i]] = bin(intValue, sizes[i]); 156 this.hexFields[i] = this.hexFields[names[i]] = hex(intValue, sizes[i] / 4); 157 } 158 159 /** 160 * UUID version number defined in RFC 4122. 161 * @type int 162 */ 163 this.version = (this.intFields.timeHiAndVersion >> 12) & 0xF; 164 165 /** 166 * 128-bit binary bit string representation. 167 * @type string 168 */ 169 this.bitString = this.bitFields.join(""); 170 171 /** 172 * UUID hexadecimal string representation ("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"). 173 * @type string 174 */ 175 this.hexString = this.hexFields[0] + "-" + this.hexFields[1] + "-" + this.hexFields[2] 176 + "-" + this.hexFields[3] + this.hexFields[4] + "-" + this.hexFields[5]; 177 178 /** 179 * UUID string representation as a URN ("urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"). 180 * @type string 181 */ 182 this.urn = "urn:uuid:" + this.hexString; 183 184 return this; 185 }; 186 187 UUID._binAligner = UUID._getIntAligner(2); 188 189 /** 190 * Returns UUID string representation. 191 * @returns {string} {@link UUID#hexString}. 192 */ 193 UUID.prototype.toString = function() { return this.hexString; }; 194 195 /** 196 * Tests if two {@link UUID} objects are equal. 197 * @param {UUID} uuid 198 * @returns {bool} True if two {@link UUID} objects are equal. 199 */ 200 UUID.prototype.equals = function(uuid) { 201 if (!(uuid instanceof UUID)) { return false; } 202 for (var i = 0; i < 6; i++) { 203 if (this.intFields[i] !== uuid.intFields[i]) { return false; } 204 } 205 return true; 206 }; 207 208 // }}} 209 210 // UUID Version 1 Component {{{ 211 212 /** 213 * Generates a version 1 {@link UUID}. 214 * @returns {UUID} A version 1 {@link UUID} object. 215 * @since 3.0 216 */ 217 UUID.genV1 = function() { 218 var now = new Date().getTime(), st = UUID._state; 219 if (now != st.timestamp) { 220 if (now < st.timestamp) { st.sequence++; } 221 st.timestamp = now; 222 st.tick = UUID._getRandomInt(4); 223 } else if (Math.random() < UUID._tsRatio && st.tick < 9984) { 224 // advance the timestamp fraction at a probability 225 // to compensate for the low timestamp resolution 226 st.tick += 1 + UUID._getRandomInt(4); 227 } else { 228 st.sequence++; 229 } 230 231 // format time fields 232 var tf = UUID._getTimeFieldValues(st.timestamp); 233 var tl = tf.low + st.tick; 234 var thav = (tf.hi & 0xFFF) | 0x1000; // set version '0001' 235 236 // format clock sequence 237 st.sequence &= 0x3FFF; 238 var cshar = (st.sequence >>> 8) | 0x80; // set variant '10' 239 var csl = st.sequence & 0xFF; 240 241 return new UUID()._init(tl, tf.mid, thav, cshar, csl, st.node); 242 }; 243 244 /** 245 * Re-initializes version 1 UUID state. 246 * @since 3.0 247 */ 248 UUID.resetState = function() { 249 UUID._state = new UUID._state.constructor(); 250 }; 251 252 /** 253 * Probability to advance the timestamp fraction: the ratio of tick movements to sequence increments. 254 * @type float 255 */ 256 UUID._tsRatio = 1 / 4; 257 258 /** 259 * Persistent state for UUID version 1. 260 * @type UUIDState 261 */ 262 UUID._state = new function UUIDState() { 263 var rand = UUID._getRandomInt; 264 this.timestamp = 0; 265 this.sequence = rand(14); 266 this.node = (rand(8) | 1) * 0x10000000000 + rand(40); // set multicast bit '1' 267 this.tick = rand(4); // timestamp fraction smaller than a millisecond 268 }; 269 270 /** 271 * @param {Date|int} time ECMAScript Date Object or milliseconds from 1970-01-01. 272 * @returns {object} 273 */ 274 UUID._getTimeFieldValues = function(time) { 275 var ts = time - Date.UTC(1582, 9, 15); 276 var hm = ((ts / 0x100000000) * 10000) & 0xFFFFFFF; 277 return { low: ((ts & 0xFFFFFFF) * 10000) % 0x100000000, 278 mid: hm & 0xFFFF, hi: hm >>> 16, timestamp: ts }; 279 }; 280 281 // }}} 282 283 // Misc. Component {{{ 284 285 /** 286 * Reinstalls {@link UUID.generate} method to emulate the interface of UUID.js version 2.x. 287 * @since 3.1 288 * @deprecated Version 2.x. compatible interface is not recommended. 289 */ 290 UUID.makeBackwardCompatible = function() { 291 var f = UUID.generate; 292 UUID.generate = function(o) { 293 return (o && o.version == 1) ? UUID.genV1().hexString : f.call(UUID); 294 }; 295 UUID.makeBackwardCompatible = function() {}; 296 }; 297 298 /** 299 * Preserves the value of 'UUID' global variable set before the load of UUID.js. 300 * @since 3.2 301 * @type object 302 */ 303 UUID.overwrittenUUID = overwrittenUUID; 304 305 // }}} 306 307 return UUID; 308 309 })(UUID); 310 311 // vim: et ts=2 sw=2 fdm=marker fmr& 312