From 5021d9cfd78b87921cda49a7628a733eec4e4050 Mon Sep 17 00:00:00 2001 From: Daniel Poelzleithner Date: Sat, 30 Jul 2011 23:42:24 +0200 Subject: [PATCH 1/3] implement buffer and binary support allows Guid objects to be created with predefined value allows pure hexadecimal and Buffer values which gets converted to the normal form. exports for value in binary string through Buffer and pure hex string --- guid.js | 118 +++++++++++++++++++++++++++++++++++++++++++++++--- tests/test.js | 43 ++++++++++++++++++ 2 files changed, 154 insertions(+), 7 deletions(-) create mode 100644 tests/test.js diff --git a/guid.js b/guid.js index 4140e99..582f4a1 100644 --- a/guid.js +++ b/guid.js @@ -1,4 +1,5 @@ var validator = new RegExp("^[a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{12}$", "i"); +var hex_validator = new RegExp("^[a-z0-9]{32}$", "i"); function gen(count) { var out = ""; @@ -8,21 +9,103 @@ function gen(count) { return out; } +var _bin2hex = [ + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' +]; + +var _hex2bin = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, // 0-9 + 0,10,11,12,13,14,15, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A-F + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,10,11,12,13,14,15, 0, 0, 0, 0, 0, 0, 0, 0, 0, // a-f + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +]; + +function bin2hex(str) { + var len = str.length; + var rv = ''; + var i = 0; + var c; + + while (len-- > 0) { + if(str instanceof Buffer) + c = str[i++]; + else + c = str.charCodeAt(i++); + + rv += _bin2hex[(c & 0xf0) >> 4]; + rv += _bin2hex[(c & 0x0f)]; + } + return rv; +} + +function hex2bin(str) { + var len = str.length; + var rv = []; + var i = 0; + + var c1; + var c2; + + while (len > 1) { + h1 = str.charAt(i++); + c1 = h1.charCodeAt(0); + h2 = str.charAt(i++); + c2 = h2.charCodeAt(0); + + rv.push((_hex2bin[c1] << 4) + _hex2bin[c2]); + len -= 2; + } + + return rv; +} + +function hex2uuid(hex) { + return hex.substr(0, 8) + "-" + + hex.substr(8, 4) + "-" + + hex.substr(12, 4) + "-" + + hex.substr(16, 4) + "-" + + hex.substr(20); +} + + function Guid(guid) { if (!guid) throw new TypeError("Invalid argument; `value` has no value."); var value = Guid.EMPTY; + var bin = null; if (guid && guid instanceof Guid) { + // Guid instances value = Guid.toString(); - - } else if (guid && Object.prototype.toString.call(guid) === "[object String]" && Guid.isGuid(guid)) { - value = guid; + } else if (guid && guid instanceof Buffer) { + // binary buffer + value = hex2uuid(bin2hex(guid)); + } else if (guid && Object.prototype.toString.call(guid) === "[object String]" && Guid.isGuid(guid, true)) { + if(guid.length == 32) // value is a pure hex string + value = hex2uuid(guid) + else + value = guid; } - + this.equals = function(other) { // Comparing string `value` against provided `guid` will auto-call // toString on `guid` for comparison + if (typeof(other) == 'string') { + return (other === this.toString()); + } return Guid.isGuid(other) && value == other; }; @@ -37,22 +120,43 @@ function Guid(guid) { this.toJSON = function() { return value; }; + + this.toHex = function() { + return value.split("-").join("") + } + + this.toArray = function() { + return hex2bin(this.toHex()) + } + + this.toBytes = function() { + if(bin) return bin + return bin = new Buffer(this.toArray()); + } Object.defineProperty(this, "value", { get: function() { return value; }, enumerable: true }); + + Object.defineProperty(this, "bytes", { + get: function() { return this.toBytes(); }, + enumerable: true + }); }; Object.defineProperty(Guid, "EMPTY", { value: "00000000-0000-0000-0000-000000000000" }); -Guid.isGuid = function(value) { - return value && (value instanceof Guid || validator.test(value.toString())); +Guid.isGuid = function(value, loose) { + return value && (value instanceof Guid || validator.test(value.toString()) || + loose && hex_validator.test(value.toString())); }; -Guid.create = function() { +Guid.create = function(value) { + if(value) + return new Guid(value); return new Guid([gen(2), gen(1), gen(1), gen(1), gen(3)].join("-")); }; diff --git a/tests/test.js b/tests/test.js new file mode 100644 index 0000000..3ad4bc9 --- /dev/null +++ b/tests/test.js @@ -0,0 +1,43 @@ +var Guid = require('../guid'); +var vows = require('vows'), + assert = require('assert'); + + +module.exports = tests = {} + + +tests.suite1 = vows.describe('guid tests').addBatch({ +"test1": { + "raw interface": function() { + var g = Guid.raw(); + assert.ok(g); + assert.equal(typeof(g), 'string') + assert.equal(g.length, 36) + return + }, + + "object interface": function() { + var tar = [109, 210, 117, 221, 229, 152, 237, 212, 77, 119, 59, 248, 68, 107, 97, 183]; + + var g = Guid.create("6dd275dd-e598-edd4-4d77-3bf8446b61b7"); + 'm\xd2u\xdd\xe5\x98\xed\xd4Mw;\xf8Dka\xb7' + assert.ok(g.equals("6dd275dd-e598-edd4-4d77-3bf8446b61b7"), "not equal to string"); + + assert.equal(g.toHex(), '6dd275dde598edd44d773bf8446b61b7'); + assert.equal(g.value, new Guid.create('6dd275dde598edd44d773bf8446b61b7').value); + assert.deepEqual(g.toArray(), + tar, + "array is not equal"); + + buf = g.toBytes(); + assert.ok(buf instanceof Buffer, "buffer"); + for(var i = 0; i < tar.length; i++) + assert.equal(buf[i], tar[i], "buffer differs"); + + var g2 = Guid.create(buf); + assert.equal(g.value, g2.value, "copy over buffer failed"); + } +}, +}); + +console.log(vows) From 984041e4d28f0066738132dd35542e86d7093e6c Mon Sep 17 00:00:00 2001 From: Daniel Poelzleithner Date: Sun, 31 Jul 2011 09:50:14 +0200 Subject: [PATCH 2/3] allow binary strings as argument must be of size 16 to be accepted --- guid.js | 14 +++++++++----- tests/test.js | 4 ++++ 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/guid.js b/guid.js index 582f4a1..69e919d 100644 --- a/guid.js +++ b/guid.js @@ -93,11 +93,15 @@ function Guid(guid) { } else if (guid && guid instanceof Buffer) { // binary buffer value = hex2uuid(bin2hex(guid)); - } else if (guid && Object.prototype.toString.call(guid) === "[object String]" && Guid.isGuid(guid, true)) { - if(guid.length == 32) // value is a pure hex string - value = hex2uuid(guid) - else - value = guid; + } else if (guid && Object.prototype.toString.call(guid) === "[object String]") { + if(Guid.isGuid(guid, true)) { + if(guid.length == 32) // value is a pure hex string + value = hex2uuid(guid) + else + value = guid; + } else if (guid.length == 16) { + value = hex2uuid(bin2hex(guid)); + } } this.equals = function(other) { diff --git a/tests/test.js b/tests/test.js index 3ad4bc9..a6a37ec 100644 --- a/tests/test.js +++ b/tests/test.js @@ -36,6 +36,10 @@ tests.suite1 = vows.describe('guid tests').addBatch({ var g2 = Guid.create(buf); assert.equal(g.value, g2.value, "copy over buffer failed"); + + var g3 = Guid.create('\x00\x00\x00\x00\x00\x00\x00\x00\xab\xcd\x12\x34\x56\x78\x90\x12'); + assert.equal(g3.value, "00000000-0000-0000-abcd-123456789012") + } }, }); From 32e6a2c544297b267cc1156aa424362dbab56e37 Mon Sep 17 00:00:00 2001 From: Daniel Poelzleithner Date: Tue, 2 Aug 2011 16:26:19 +0200 Subject: [PATCH 3/3] add inspect method for better console repersentation --- guid.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/guid.js b/guid.js index 69e919d..10b7f78 100644 --- a/guid.js +++ b/guid.js @@ -138,6 +138,10 @@ function Guid(guid) { return bin = new Buffer(this.toArray()); } + this.inspect = function() { + return "" + } + Object.defineProperty(this, "value", { get: function() { return value; }, enumerable: true