diff --git a/Makefile.am b/Makefile.am
index ee3c1975..f30140eb 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -15,6 +15,7 @@ UTIL_INCLUDE = \
except.hpp \
fixed.hpp \
float.hpp \
+ guid.hpp \
io.hpp \
ip.hpp \
json.hpp \
@@ -38,6 +39,7 @@ UTIL_FILES = \
except.cpp \
fixed.cpp \
float.cpp \
+ guid.cpp \
io.cpp \
ip.cpp \
json.cpp \
diff --git a/guid.cpp b/guid.cpp
new file mode 100644
index 00000000..ca665dd5
--- /dev/null
+++ b/guid.cpp
@@ -0,0 +1,210 @@
+/*
+ * This file is part of libgim.
+ *
+ * libgim is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later
+ * version.
+ *
+ * libgim is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with libgim. If not, see .
+ *
+ * Copyright 2011 Danny Robson
+ */
+
+#include "guid.hpp"
+
+#include "debug.hpp"
+#include "endian.hpp"
+#include "types.hpp"
+
+#include
+#include
+#include
+
+using namespace std;
+
+
+guid::guid (uint32_t _data1,
+ uint16_t _data2,
+ uint16_t _data3,
+ uint8_t _data4[8]):
+ data1 (_data1),
+ data2 (_data2),
+ data3 (_data3)
+{
+ copy (_data4, _data4 + elems (data4), data4);
+}
+
+
+guid::guid (void)
+{
+ ;
+}
+
+
+guid::guid (const char *str) {
+ istringstream is (str);
+ is >> *this;
+}
+
+
+guid::guid (const guid &rhs) {
+ *this = rhs;
+}
+
+
+guid&
+guid::operator= (const guid &rhs) {
+ data1 = rhs.data1;
+ data2 = rhs.data2;
+ data3 = rhs.data3;
+ copy (rhs.data4 + 0, rhs.data4 + elems (rhs.data4), data4 + 0);
+
+ return *this;
+}
+
+
+guid
+guid::from_bytes (const uint8_t *bytes) {
+ guid g;
+
+ g.data1 = *reinterpret_cast (bytes);
+ bytes += sizeof (g.data1);
+
+ g.data2 = *reinterpret_cast (bytes);
+ bytes += sizeof (g.data2);
+
+ g.data3 = *reinterpret_cast (bytes);
+ bytes += sizeof (g.data3);
+
+ for (signed i = 7; i >= 0; --i) {
+ g.data4[i] = *reinterpret_cast (bytes);
+ ++bytes;
+ }
+
+ return g;
+}
+
+
+guid
+guid::from_string (const char *bytes)
+ { return guid (bytes); }
+
+
+guid::type
+guid::get_type (void) const {
+ // Top three bits signal the type
+ unsigned bits = (unsigned)data4[2] >> 5U;
+
+ switch (bits) {
+ case 0x0:
+ case 0x1:
+ case 0x2:
+ case 0x3: return NCS_BACKWARD;
+
+ case 0x4:
+ case 0x5: return STANDARD;
+
+ case 0x6: return COM_BACKWARD;
+
+ case 0x7: return RESERVED;
+ }
+
+ unreachable ();
+}
+
+
+bool
+guid::operator< (const guid &rhs) const {
+ if (data1 != rhs.data1)
+ return data1 < rhs.data1;
+ if (data2 != rhs.data2)
+ return data2 < rhs.data2;
+ if (data3 != rhs.data3)
+ return data3 < rhs.data3;
+
+ for (unsigned i = 0; i < elems (data4); ++i) {
+ if (data4[i] == rhs.data4[i])
+ return data4[i] < rhs.data4[i];
+ }
+
+ // All equal, so not less than
+ return false;
+}
+
+
+bool
+guid::operator== (const guid &rhs) const {
+ return data1 == rhs.data1 &&
+ data2 == rhs.data2 &&
+ data3 == rhs.data3 &&
+ data4[0] == rhs.data4[0] &&
+ data4[1] == rhs.data4[1] &&
+ data4[2] == rhs.data4[2] &&
+ data4[3] == rhs.data4[3] &&
+ data4[4] == rhs.data4[4] &&
+ data4[5] == rhs.data4[5] &&
+ data4[6] == rhs.data4[6] &&
+ data4[7] == rhs.data4[7];
+}
+
+std::ostream&
+operator<< (std::ostream &os, const guid &g) {
+ uint64_t data4_b = (uint64_t)g.data4[0] << 0 |
+ (uint64_t)g.data4[1] << 8 |
+ (uint64_t)g.data4[2] << 16 |
+ (uint64_t)g.data4[3] << 24 |
+ (uint64_t)g.data4[4] << 32 |
+ (uint64_t)g.data4[5] << 40;
+ uint16_t data4_a = (uint16_t)g.data4[6] << 0 |
+ (uint16_t)g.data4[7] << 8;
+
+ os << hex << setfill ('0') << setw (2 * sizeof (g.data1)) << g.data1 << "-"
+ << setw (2 * sizeof (g.data2)) << g.data2 << "-"
+ << setw (2 * sizeof (g.data3)) << g.data3 << "-"
+ << setw (2 * 2) << data4_a << "-"
+ << setw (2 * 6) << data4_b;
+
+ os << dec;
+ return os;
+}
+
+
+std::istream&
+operator>> (std::istream &is, guid &g) {
+ bool braces = '{' == is.peek ();
+ if (braces)
+ is.get ();
+
+ uint8_t dash1, dash2, dash3, dash4a;
+ uint16_t data4_a;
+ uint64_t data4_b;
+
+ is >> hex >> g.data1 >> dash1
+ >> g.data2 >> dash2
+ >> g.data3 >> dash3
+ >> data4_a >> dash4a
+ >> data4_b;
+
+ uint64_t data4 = data4_b | (uint64_t)data4_a << 48;
+ g.data4[0] = data4 & 0xFF; data4 >>= 8;
+ g.data4[1] = data4 & 0xFF; data4 >>= 8;
+ g.data4[2] = data4 & 0xFF; data4 >>= 8;
+ g.data4[3] = data4 & 0xFF; data4 >>= 8;
+ g.data4[4] = data4 & 0xFF; data4 >>= 8;
+ g.data4[5] = data4 & 0xFF; data4 >>= 8;
+ g.data4[6] = data4 & 0xFF; data4 >>= 8;
+ g.data4[7] = data4 & 0xFF; data4 >>= 8;
+
+ if (braces)
+ is.get ();
+
+ return is;
+}
+
diff --git a/guid.hpp b/guid.hpp
new file mode 100644
index 00000000..e9da8571
--- /dev/null
+++ b/guid.hpp
@@ -0,0 +1,62 @@
+/*
+ * This file is part of libgim.
+ *
+ * libgim is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later
+ * version.
+ *
+ * libgim is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with libgim. If not, see .
+ *
+ * Copyright 2011 Danny Robson
+ */
+
+#ifndef __UTIL_GUID_HPP
+#define __UTIL_GUID_HPP
+
+#include
+#include
+
+class guid {
+ public:
+ enum type {
+ NCS_BACKWARD, // 0xx: Network Computing System backward compatibility
+ STANDARD, // 10x: Standard
+ COM_BACKWARD, // 110: Microsoft Component Object Model backward compatibility
+ RESERVED // 111: Reserved for future use
+ };
+
+ private:
+ guid (void);
+
+ public:
+ guid (uint32_t, uint16_t, uint16_t, uint8_t[8]);
+ guid (const char *);
+ guid (const guid&);
+
+ guid& operator= (const guid&);
+
+ static guid from_bytes (const uint8_t *bytes);
+ static guid from_string (const char *bytes);
+
+ uint32_t data1;
+ uint16_t data2;
+ uint16_t data3;
+ uint8_t data4[8];
+
+ type get_type (void) const;
+
+ bool operator< (const guid&) const;
+ bool operator== (const guid&) const;
+};
+
+std::istream& operator>> (std::istream&, guid&);
+std::ostream& operator<< (std::ostream&, const guid&);
+
+#endif