Mercurial > pub > ImplabJs
comparison src/implab/Uuid.js @ 0:fc2517695ee1
Initial commit, draft import of existing work
author | cin |
---|---|
date | Thu, 01 Jun 2017 13:20:03 +0300 |
parents | |
children | 93fb6c09f2e1 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:fc2517695ee1 |
---|---|
1 // uuid.js | |
2 // | |
3 // Copyright (c) 2010-2012 Robert Kieffer | |
4 // MIT License - http://opensource.org/licenses/mit-license.php | |
5 define( | |
6 [], | |
7 function () { | |
8 'use strict'; | |
9 | |
10 var _window = 'undefined' !== typeof window ? window : null; | |
11 | |
12 // Unique ID creation requires a high quality random # generator. We | |
13 // feature | |
14 // detect to determine the best RNG source, normalizing to a function | |
15 // that | |
16 // returns 128-bits of randomness, since that's what's usually required | |
17 var _rng, _mathRNG, _nodeRNG, _whatwgRNG, _previousRoot; | |
18 | |
19 function setupBrowser() { | |
20 // Allow for MSIE11 msCrypto | |
21 var _crypto = _window.crypto || _window.msCrypto; | |
22 | |
23 if (!_rng && _crypto && _crypto.getRandomValues) { | |
24 // WHATWG crypto-based RNG - http://wiki.whatwg.org/wiki/Crypto | |
25 // | |
26 // Moderately fast, high quality | |
27 try { | |
28 var _rnds8 = new Uint8Array(16); | |
29 _whatwgRNG = _rng = function whatwgRNG() { | |
30 _crypto.getRandomValues(_rnds8); | |
31 return _rnds8; | |
32 }; | |
33 _rng(); | |
34 } catch (e) {} | |
35 } | |
36 | |
37 if (!_rng) { | |
38 // Math.random()-based (RNG) | |
39 // | |
40 // If all else fails, use Math.random(). It's fast, but is of | |
41 // unspecified | |
42 // quality. | |
43 var _rnds = new Array(16); | |
44 _mathRNG = _rng = function () { | |
45 for (var i = 0, r; i < 16; i++) { | |
46 if ((i & 0x03) === 0) { | |
47 r = Math.random() * 0x100000000; | |
48 } | |
49 _rnds[i] = r >>> ((i & 0x03) << 3) & 0xff; | |
50 } | |
51 | |
52 return _rnds; | |
53 }; | |
54 if ('undefined' !== typeof console && console.warn) { | |
55 console | |
56 .warn("[SECURITY] node-uuid: crypto not usable, falling back to insecure Math.random()"); | |
57 } | |
58 } | |
59 } | |
60 | |
61 function setupNode() { | |
62 // Node.js crypto-based RNG - | |
63 // http://nodejs.org/docs/v0.6.2/api/crypto.html | |
64 // | |
65 // Moderately fast, high quality | |
66 if ('function' === typeof require) { | |
67 try { | |
68 var _rb = require('crypto').randomBytes; | |
69 _nodeRNG = _rng = _rb && function () { | |
70 return _rb(16); | |
71 }; | |
72 _rng(); | |
73 } catch (e) {} | |
74 } | |
75 } | |
76 | |
77 if (_window) { | |
78 setupBrowser(); | |
79 } else { | |
80 setupNode(); | |
81 } | |
82 | |
83 // Buffer class to use | |
84 var BufferClass = ('function' === typeof Buffer) ? Buffer : Array; | |
85 | |
86 // Maps for number <-> hex string conversion | |
87 var _byteToHex = []; | |
88 var _hexToByte = {}; | |
89 for (var i = 0; i < 256; i++) { | |
90 _byteToHex[i] = (i + 0x100).toString(16).substr(1); | |
91 _hexToByte[_byteToHex[i]] = i; | |
92 } | |
93 | |
94 // **`parse()` - Parse a UUID into it's component bytes** | |
95 function parse(s, buf, offset) { | |
96 var i = (buf && offset) || 0, | |
97 ii = 0; | |
98 | |
99 buf = buf || []; | |
100 s.toLowerCase().replace(/[0-9a-f]{2}/g, function (oct) { | |
101 if (ii < 16) { // Don't overflow! | |
102 buf[i + ii++] = _hexToByte[oct]; | |
103 } | |
104 }); | |
105 | |
106 // Zero out remaining bytes if string was short | |
107 while (ii < 16) { | |
108 buf[i + ii++] = 0; | |
109 } | |
110 | |
111 return buf; | |
112 } | |
113 | |
114 // **`unparse()` - Convert UUID byte array (ala parse()) into a string** | |
115 function unparse(buf, offset) { | |
116 var i = offset || 0, | |
117 bth = _byteToHex; | |
118 return bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]] + | |
119 bth[buf[i++]] + '-' + bth[buf[i++]] + bth[buf[i++]] + '-' + | |
120 bth[buf[i++]] + bth[buf[i++]] + '-' + bth[buf[i++]] + | |
121 bth[buf[i++]] + '-' + bth[buf[i++]] + bth[buf[i++]] + | |
122 bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]]; | |
123 } | |
124 | |
125 // **`v1()` - Generate time-based UUID** | |
126 // | |
127 // Inspired by https://github.com/LiosK/UUID.js | |
128 // and http://docs.python.org/library/uuid.html | |
129 | |
130 // random #'s we need to init node and clockseq | |
131 var _seedBytes = _rng(); | |
132 | |
133 // Per 4.5, create and 48-bit node id, (47 random bits + multicast bit = | |
134 // 1) | |
135 var _nodeId = [ | |
136 _seedBytes[0] | 0x01, | |
137 _seedBytes[1], | |
138 _seedBytes[2], | |
139 _seedBytes[3], | |
140 _seedBytes[4], | |
141 _seedBytes[5] | |
142 ]; | |
143 | |
144 // Per 4.2.2, randomize (14 bit) clockseq | |
145 var _clockseq = (_seedBytes[6] << 8 | _seedBytes[7]) & 0x3fff; | |
146 | |
147 // Previous uuid creation time | |
148 var _lastMSecs = 0, | |
149 _lastNSecs = 0; | |
150 | |
151 // See https://github.com/broofa/node-uuid for API details | |
152 function v1(options, buf, offset) { | |
153 var i = buf && offset || 0; | |
154 var b = buf || []; | |
155 | |
156 options = options || {}; | |
157 | |
158 var clockseq = (options.clockseq != null) ? options.clockseq : _clockseq; | |
159 | |
160 // UUID timestamps are 100 nano-second units since the Gregorian | |
161 // epoch, | |
162 // (1582-10-15 00:00). JSNumbers aren't precise enough for this, so | |
163 // time is handled internally as 'msecs' (integer milliseconds) and | |
164 // 'nsecs' | |
165 // (100-nanoseconds offset from msecs) since unix epoch, 1970-01-01 | |
166 // 00:00. | |
167 var msecs = (options.msecs != null) ? options.msecs : new Date() | |
168 .getTime(); | |
169 | |
170 // Per 4.2.1.2, use count of uuid's generated during the current | |
171 // clock | |
172 // cycle to simulate higher resolution clock | |
173 var nsecs = (options.nsecs != null) ? options.nsecs : _lastNSecs + 1; | |
174 | |
175 // Time since last uuid creation (in msecs) | |
176 var dt = (msecs - _lastMSecs) + (nsecs - _lastNSecs) / 10000; | |
177 | |
178 // Per 4.2.1.2, Bump clockseq on clock regression | |
179 if (dt < 0 && options.clockseq == null) { | |
180 clockseq = clockseq + 1 & 0x3fff; | |
181 } | |
182 | |
183 // Reset nsecs if clock regresses (new clockseq) or we've moved onto | |
184 // a new | |
185 // time interval | |
186 if ((dt < 0 || msecs > _lastMSecs) && options.nsecs == null) { | |
187 nsecs = 0; | |
188 } | |
189 | |
190 // Per 4.2.1.2 Throw error if too many uuids are requested | |
191 if (nsecs >= 10000) { | |
192 throw new Error( | |
193 'uuid.v1(): Can\'t create more than 10M uuids/sec'); | |
194 } | |
195 | |
196 _lastMSecs = msecs; | |
197 _lastNSecs = nsecs; | |
198 _clockseq = clockseq; | |
199 | |
200 // Per 4.1.4 - Convert from unix epoch to Gregorian epoch | |
201 msecs += 12219292800000; | |
202 | |
203 // `time_low` | |
204 var tl = ((msecs & 0xfffffff) * 10000 + nsecs) % 0x100000000; | |
205 b[i++] = tl >>> 24 & 0xff; | |
206 b[i++] = tl >>> 16 & 0xff; | |
207 b[i++] = tl >>> 8 & 0xff; | |
208 b[i++] = tl & 0xff; | |
209 | |
210 // `time_mid` | |
211 var tmh = (msecs / 0x100000000 * 10000) & 0xfffffff; | |
212 b[i++] = tmh >>> 8 & 0xff; | |
213 b[i++] = tmh & 0xff; | |
214 | |
215 // `time_high_and_version` | |
216 b[i++] = tmh >>> 24 & 0xf | 0x10; // include version | |
217 b[i++] = tmh >>> 16 & 0xff; | |
218 | |
219 // `clock_seq_hi_and_reserved` (Per 4.2.2 - include variant) | |
220 b[i++] = clockseq >>> 8 | 0x80; | |
221 | |
222 // `clock_seq_low` | |
223 b[i++] = clockseq & 0xff; | |
224 | |
225 // `node` | |
226 var node = options.node || _nodeId; | |
227 for (var n = 0; n < 6; n++) { | |
228 b[i + n] = node[n]; | |
229 } | |
230 | |
231 return buf ? buf : unparse(b); | |
232 } | |
233 | |
234 // **`v4()` - Generate random UUID** | |
235 | |
236 // See https://github.com/broofa/node-uuid for API details | |
237 function v4(options, buf, offset) { | |
238 // Deprecated - 'format' argument, as supported in v1.2 | |
239 var i = buf && offset || 0; | |
240 | |
241 if (typeof (options) === 'string') { | |
242 buf = (options === 'binary') ? new BufferClass(16) : null; | |
243 options = null; | |
244 } | |
245 options = options || {}; | |
246 | |
247 var rnds = options.random || (options.rng || _rng)(); | |
248 | |
249 // Per 4.4, set bits for version and `clock_seq_hi_and_reserved` | |
250 rnds[6] = (rnds[6] & 0x0f) | 0x40; | |
251 rnds[8] = (rnds[8] & 0x3f) | 0x80; | |
252 | |
253 // Copy bytes to buffer, if provided | |
254 if (buf) { | |
255 for (var ii = 0; ii < 16; ii++) { | |
256 buf[i + ii] = rnds[ii]; | |
257 } | |
258 } | |
259 | |
260 return buf || unparse(rnds); | |
261 } | |
262 | |
263 // Export public API | |
264 var uuid = function() { | |
265 return new String(v4()); | |
266 }; | |
267 uuid.v1 = v1; | |
268 uuid.v4 = v4; | |
269 uuid.create = v4; | |
270 uuid.empty = "00000000-0000-0000-0000-000000000000"; | |
271 uuid.parse = parse; | |
272 uuid.unparse = unparse; | |
273 uuid.BufferClass = BufferClass; | |
274 uuid._rng = _rng; | |
275 uuid._mathRNG = _mathRNG; | |
276 uuid._nodeRNG = _nodeRNG; | |
277 uuid._whatwgRNG = _whatwgRNG; | |
278 | |
279 return uuid; | |
280 }); |