--- uuid.c 2004/01/18 19:22:54 1.35
+++ uuid.c 2004/01/18 19:59:12 1.36
@@ -51,8 +51,82 @@
#include "uuid_bm.h"
#include "uuid_ac.h"
+/* maximum number of 100ns ticks of the actual resolution of system clock
+ (which in our case is 1us (= 1000ns) because we use gettimeofday(2) */
+#define UUIDS_PER_TICK 10
+
+/* time offset between UUID and Unix Epoch time according to standards.
+ (UUID UTC base time is October 15, 1582
+ Unix UTC base time is January 1, 1970) */
+#define UUID_TIMEOFFSET "01B21DD213814000"
+
+/* IEEE 802 MAC address encoding/decoding bit fields
+
+ ATTENTION:
+
+ In case no real/physical IEEE 802 address is available, both
+ "draft-leach-uuids-guids-01" (section "4. Node IDs when no IEEE 802
+ network card is available") and RFC 2518 (section "6.4.1 Node Field
+ Generation Without the IEEE 802 Address") recommend (quoted from RFC
+ 2518):
+
+ "The ideal solution is to obtain a 47 bit cryptographic quality
+ random number, and use it as the low 47 bits of the node ID, with
+ the most significant bit of the first octet of the node ID set to
+ 1. This bit is the unicast/multicast bit, which will never be set
+ in IEEE 802 addresses obtained from network cards; hence, there can
+ never be a conflict between UUIDs generated by machines with and
+ without network cards."
+
+ This clearly explains that the intention is to use IEEE 802 multicast
+ addresses. Unfortunately, it incorrectly explains how to implement
+ this! It actually is the "*LEAST* significant bit of the first octet
+ of the node ID" in a memory and hexadecimal string representation of
+ a 48-bit IEEE 802 MAC address.
+
+ Unfortunately, even the reference implementation included in the
+ expired IETF "draft-leach-uuids-guids-01" incorrectly set the
+ multicast bit with an OR bit operation and an incorrect mask of
+ 0x80. Hence, multiple other UUID implementations can be found on the
+ Internet which inherited this bug.
+
+ Luckily, neither DCE 1.1 nor ISO/IEC 11578:1996 are affected by this
+ problem. They disregard the topic of missing IEEE 802 addresses
+ entirely, and thus avoid adopting this bug from the original draft
+ and code ;-)
+
+ The reason for the bug in the standards seems to be that the
+ multicast bit actually is the *MOST* significant bit in IEEE 802.3
+ (Ethernet) _transmission order_ of an IEEE 802 MAC address. The
+ authors seem to be confused by this and especially were not aware
+ that the bitwise order of an octet from a MAC address memory and
+ hexadecimal string representation is still always from left (MSB, bit
+ 7) to right (LSB, bit 0).
+
+ For more information on this, see especially "Understanding
+ Physical Addresses" in "Ethernet -- The Definitive Guide",
+ p.43, and section "ETHERNET MULTICAST ADDRESSES" in
+ http://www.iana.org/assignments/ethernet-numbers.
+
+ Hence, we do it the intended/correct way and generate a real IEEE 802
+ multicast address, but with a brain-dead compile-time option one can
+ nevertheless enforce the broken generation of IEEE 802 MAC addresses.
+ For the decoding we always use the correct way, of course. */
+
+/* encoding */
+#ifdef WITH_RFC2518
+#define IEEE_MAC_MCBIT_ENC BM_OCTET(1,0,0,0,0,0,0,0)
+#else
+#define IEEE_MAC_MCBIT_ENC BM_OCTET(0,0,0,0,0,0,0,1)
+#endif
+#define IEEE_MAC_LOBIT_ENC BM_OCTET(0,0,0,0,0,0,1,0)
+
+/* decoding */
+#define IEEE_MAC_MCBIT_DEC BM_OCTET(0,0,0,0,0,0,0,1)
+#define IEEE_MAC_LOBIT_DEC BM_OCTET(0,0,0,0,0,0,1,0)
+
/* IEEE 802 MAC address octet length */
-#define MAC_OCTETS 6
+#define IEEE_MAC_OCTETS 6
/* UUID binary representation according to UUID standards */
typedef struct {
@@ -61,7 +135,7 @@
uuid_uint16_t time_hi_and_version; /* bits 48-59 of time field plus 4 bit version */
uuid_uint8_t clock_seq_hi_and_reserved; /* bits 8-13 of clock sequence field plus 2 bit variant */
uuid_uint8_t clock_seq_low; /* bits 0-7 of clock sequence field */
- uuid_uint8_t node[MAC_OCTETS]; /* bits 0-47 of node MAC address */
+ uuid_uint8_t node[IEEE_MAC_OCTETS]; /* bits 0-47 of node MAC address */
} uuid_obj_t;
/* abstract data type (ADT) of API */
@@ -69,7 +143,7 @@
uuid_obj_t obj; /* inlined UUID object */
prng_t *prng; /* RPNG sub-object */
md5_t *md5; /* MD5 sub-object */
- uuid_uint8_t mac[MAC_OCTETS]; /* pre-determined MAC address */
+ uuid_uint8_t mac[IEEE_MAC_OCTETS]; /* pre-determined MAC address */
struct timeval time_last; /* last retrieved timestamp */
unsigned long time_seq; /* last timestamp sequence counter */
};
@@ -125,19 +199,6 @@
return UUID_RC_OK;
}
-/* set UUID object to represents "Nil UUID" */
-uuid_rc_t uuid_nil(uuid_t *uuid)
-{
- /* argument sanity check */
- if (uuid == NULL)
- return UUID_RC_ARG;
-
- /* clear all octets to create "Nil UUID" */
- memset((void *)&(uuid->obj), '\0', sizeof(uuid->obj));
-
- return UUID_RC_OK;
-}
-
/* check whether UUID object represents "Nil UUID" */
uuid_rc_t uuid_isnil(uuid_t *uuid, int *result)
{
@@ -211,9 +272,9 @@
return UUID_RC_OK;
}
-/* unpack UUID binary presentation into UUID object
+/* INTERNAL: unpack UUID binary presentation into UUID object
(allows in-place operation for internal efficiency!) */
-uuid_rc_t uuid_unpack(uuid_t *uuid, const void *buf)
+static uuid_rc_t uuid_import_bin(uuid_t *uuid, const void *data_ptr, size_t data_len)
{
const uuid_uint8_t *in;
uuid_uint32_t tmp32;
@@ -221,11 +282,11 @@
unsigned int i;
/* sanity check argument(s) */
- if (uuid == NULL || buf == NULL)
+ if (uuid == NULL || data_ptr == NULL || data_len < UUID_LEN_BIN)
return UUID_RC_ARG;
- /* treat input buffer as octet stream */
- in = (const uuid_uint8_t *)buf;
+ /* treat input data_ptrfer as octet stream */
+ in = (const uuid_uint8_t *)data_ptr;
/* unpack "time_low" field */
tmp32 = *in++;
@@ -257,9 +318,9 @@
return UUID_RC_OK;
}
-/* pack UUID object into binary representation
+/* INTERNAL: pack UUID object into binary representation
(allows in-place operation for internal efficiency!) */
-uuid_rc_t uuid_pack(uuid_t *uuid, void **buf)
+static uuid_rc_t uuid_export_bin(uuid_t *uuid, void **data_ptr, size_t *data_len)
{
uuid_uint8_t *out;
uuid_uint32_t tmp32;
@@ -267,16 +328,26 @@
unsigned int i;
/* sanity check argument(s) */
- if (uuid == NULL || buf == NULL)
+ if (uuid == NULL || data_ptr == NULL)
return UUID_RC_ARG;
- /* optionally allocate octet buffer */
- if (*buf == NULL)
- if ((*buf = malloc(sizeof(uuid_t))) == NULL)
+ /* optionally allocate octet data_ptrfer */
+ if (*data_ptr == NULL) {
+ if ((*data_ptr = malloc(sizeof(uuid_t))) == NULL)
+ return UUID_RC_MEM;
+ if (data_len != NULL)
+ *data_len = UUID_LEN_BIN;
+ }
+ else {
+ if (data_len == NULL)
+ return UUID_RC_ARG;
+ if (*data_len < UUID_LEN_BIN)
return UUID_RC_MEM;
+ *data_len = UUID_LEN_BIN;
+ }
- /* treat output buffer as octet stream */
- out = (uuid_uint8_t *)(*buf);
+ /* treat output data_ptrfer as octet stream */
+ out = (uuid_uint8_t *)(*data_ptr);
/* pack "time_low" field */
tmp32 = uuid->obj.time_low;
@@ -337,19 +408,21 @@
return UUID_TRUE;
}
-/* parse string representation into UUID object */
-uuid_rc_t uuid_parse(uuid_t *uuid, const char *str)
+/* INTERNAL: import UUID object from string representation */
+static uuid_rc_t uuid_import_str(uuid_t *uuid, const void *data_ptr, size_t data_len)
{
uuid_uint16_t tmp16;
const char *cp;
char hexbuf[3];
+ const char *str;
unsigned int i;
/* sanity check argument(s) */
- if (uuid == NULL || str == NULL)
+ if (uuid == NULL || data_ptr == NULL || data_len < UUID_LEN_STR)
return UUID_RC_ARG;
/* check for correct UUID string representation syntax */
+ str = (const char *)data_ptr;
if (!uuid_isstr(str, 0))
return UUID_RC_ARG;
@@ -375,20 +448,30 @@
return UUID_RC_OK;
}
-/* format UUID object into string representation */
-uuid_rc_t uuid_format(uuid_t *uuid, char **str)
+/* INTERNAL: export UUID object to string representation */
+static uuid_rc_t uuid_export_str(uuid_t *uuid, void **data_ptr, size_t *data_len)
{
/* sanity check argument(s) */
- if (uuid == NULL || str == NULL)
+ if (uuid == NULL || data_ptr == NULL)
return UUID_RC_ARG;
- /* optionally allocate string buffer */
- if (*str == NULL)
- if ((*str = (char *)malloc(UUID_LEN_STR+1)) == NULL)
+ /* allocate output buffer */
+ if (*data_ptr == NULL) {
+ if ((*data_ptr = (void *)malloc(UUID_LEN_STR+1)) == NULL)
+ return UUID_RC_MEM;
+ if (data_len != NULL)
+ *data_len = UUID_LEN_STR+1;
+ }
+ else {
+ if (data_len == NULL)
+ return UUID_RC_ARG;
+ if (*data_len < UUID_LEN_STR+1)
return UUID_RC_MEM;
+ *data_len = UUID_LEN_STR+1;
+ }
/* format UUID into string representation */
- str_snprintf(*str, UUID_LEN_STR+1,
+ str_snprintf((char *)(*data_ptr), UUID_LEN_STR+1,
"%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
(unsigned long)uuid->obj.time_low,
(unsigned int)uuid->obj.time_mid,
@@ -405,92 +488,247 @@
return UUID_RC_OK;
}
-/* INTERNAL: brand UUID with version and variant */
-static void uuid_brand(uuid_t *uuid, int version)
+/* decoding tables */
+static struct {
+ uuid_uint8_t num;
+ const char *desc;
+} uuid_dectab_variant[] = {
+ { BM_OCTET(0,0,0,0,0,0,0,0), "reserved (NCS backward compatible)" },
+ { BM_OCTET(1,0,0,0,0,0,0,0), "DCE 1.1, ISO/IEC 11578:1996" },
+ { BM_OCTET(1,1,0,0,0,0,0,0), "reserved (Microsoft GUID)" },
+ { BM_OCTET(1,1,1,0,0,0,0,0), "reserved (future use)" }
+};
+static struct {
+ int num;
+ const char *desc;
+} uuid_dectab_version[] = {
+ { 1, "time and node based" },
+ { 3, "name based" },
+ { 4, "random data based" }
+};
+
+/* INTERNAL: dump UUID object as descriptive text */
+static uuid_rc_t uuid_export_txt(uuid_t *uuid, void **data_ptr, size_t *data_len)
{
- /* set version (as given) */
- uuid->obj.time_hi_and_version &= BM_MASK(11,0);
- uuid->obj.time_hi_and_version |= BM_SHL((uuid_uint16_t)version, 12);
+ uuid_rc_t rc;
+ char **out;
+ char *out_ptr;
+ size_t out_len;
+ const char *version;
+ const char *variant;
+ char *content;
+ int isnil;
+ uuid_uint8_t tmp8;
+ uuid_uint16_t tmp16;
+ uuid_uint32_t tmp32;
+ uuid_uint8_t tmp_bin[UUID_LEN_BIN];
+ char tmp_str[UUID_LEN_STR+1];
+ void *tmp_ptr;
+ size_t tmp_len;
+ ui64_t t;
+ ui64_t t_offset;
+ int t_nsec;
+ int t_usec;
+ time_t t_sec;
+ char t_buf[19+1]; /* YYYY-MM-DD HH:MM:SS */
+ struct tm *tm;
+ unsigned int i;
- /* set variant (always DCE 1.1 only) */
- uuid->obj.clock_seq_hi_and_reserved &= BM_MASK(5,0);
- uuid->obj.clock_seq_hi_and_reserved |= BM_SHL(0x02, 6);
- return;
-}
+ /* sanity check argument(s) */
+ if (uuid == NULL || data_ptr == NULL)
+ return UUID_RC_ARG;
-/* maximum number of 100ns ticks of the actual resolution of system clock
- (which in our case is 1us (= 1000ns) because we use gettimeofday(2) */
-#define UUIDS_PER_TICK 10
+ /* initialize output buffer */
+ out_ptr = NULL;
+ out = &out_ptr;
-/* time offset between UUID and Unix Epoch time according to standards.
- (UUID UTC base time is October 15, 1582
- Unix UTC base time is January 1, 1970) */
-#define UUID_TIMEOFFSET "01B21DD213814000"
+ /* check for special case of "Nil UUID" */
+ if ((rc = uuid_isnil(uuid, &isnil)) != UUID_RC_OK)
+ return rc;
-/* IEEE 802 MAC address encoding/decoding bit fields
+ /* decode into string representation */
+ tmp_ptr = (void *)&tmp_str;
+ tmp_len = sizeof(tmp_str);
+ if ((rc = uuid_export(uuid, UUID_FMT_STR, &tmp_ptr, &tmp_len)) != UUID_RC_OK)
+ return rc;
+ str_rsprintf(out, "UUID: %s\n", tmp_str);
- ATTENTION:
+ /* decode UUID variant */
+ tmp8 = uuid->obj.clock_seq_hi_and_reserved;
+ if (isnil)
+ variant = "n.a.";
+ else {
+ variant = "unknown";
+ for (i = 7; i >= 0; i--) {
+ if ((tmp8 & BM_BIT(i,1)) == 0) {
+ tmp8 &= ~BM_MASK(i,0);
+ break;
+ }
+ }
+ for (i = 0; i < sizeof(uuid_dectab_variant)/sizeof(uuid_dectab_variant[0]); i++) {
+ if (uuid_dectab_variant[i].num == tmp8) {
+ variant = uuid_dectab_variant[i].desc;
+ break;
+ }
+ }
+ }
+ str_rsprintf(out, "variant: %s\n", variant);
- In case no real/physical IEEE 802 address is available, both
- "draft-leach-uuids-guids-01" (section "4. Node IDs when no IEEE 802
- network card is available") and RFC 2518 (section "6.4.1 Node Field
- Generation Without the IEEE 802 Address") recommend (quoted from RFC
- 2518):
+ /* decode UUID version */
+ tmp16 = (BM_SHR(uuid->obj.time_hi_and_version, 12) & BM_MASK(3,0));
+ if (isnil)
+ version = "n.a.";
+ else {
+ version = "unknown";
+ for (i = 0; i < sizeof(uuid_dectab_version)/sizeof(uuid_dectab_version[0]); i++) {
+ if (uuid_dectab_version[i].num == (int)tmp16) {
+ version = uuid_dectab_version[i].desc;
+ break;
+ }
+ }
+ }
+ str_rsprintf(out, "version: %d (%s)\n", (int)tmp16, version);
- "The ideal solution is to obtain a 47 bit cryptographic quality
- random number, and use it as the low 47 bits of the node ID, with
- the most significant bit of the first octet of the node ID set to
- 1. This bit is the unicast/multicast bit, which will never be set
- in IEEE 802 addresses obtained from network cards; hence, there can
- never be a conflict between UUIDs generated by machines with and
- without network cards."
+ /*
+ * decode UUID content
+ */
- This clearly explains that the intention is to use IEEE 802 multicast
- addresses. Unfortunately, it incorrectly explains how to implement
- this! It actually is the "*LEAST* significant bit of the first octet
- of the node ID" in a memory and hexadecimal string representation of
- a 48-bit IEEE 802 MAC address.
+ if (tmp8 == BM_OCTET(1,0,0,0,0,0,0,0) && tmp16 == 1) {
+ /* decode DCE 1.1 version 1 UUID */
- Unfortunately, even the reference implementation included in the
- expired IETF "draft-leach-uuids-guids-01" incorrectly set the
- multicast bit with an OR bit operation and an incorrect mask of
- 0x80. Hence, multiple other UUID implementations can be found on the
- Internet which inherited this bug.
+ /* decode system time */
+ t = ui64_rol(ui64_n2i((unsigned long)(uuid->obj.time_hi_and_version & BM_MASK(11,0))), 48, NULL),
+ t = ui64_or(t, ui64_rol(ui64_n2i((unsigned long)(uuid->obj.time_mid)), 32, NULL));
+ t = ui64_or(t, ui64_n2i((unsigned long)(uuid->obj.time_low)));
+ t_offset = ui64_s2i(UUID_TIMEOFFSET, NULL, 16);
+ t = ui64_sub(t, t_offset, NULL);
+ t = ui64_divn(t, 10, &t_nsec);
+ t = ui64_divn(t, 1000000, &t_usec);
+ t_sec = (time_t)ui64_i2n(t);
+ tm = gmtime(&t_sec);
+ strftime(t_buf, sizeof(t_buf), "%Y-%m-%d %H:%M:%S", tm);
+ str_rsprintf(out, "content: time: %s.%06d.%d UTC\n", t_buf, t_usec, t_nsec);
- Luckily, neither DCE 1.1 nor ISO/IEC 11578:1996 are affected by this
- problem. They disregard the topic of missing IEEE 802 addresses
- entirely, and thus avoid adopting this bug from the original draft
- and code ;-)
+ /* decode clock sequence */
+ tmp32 = ((uuid->obj.clock_seq_hi_and_reserved & BM_MASK(5,0)) << 8)
+ + uuid->obj.clock_seq_low;
+ str_rsprintf(out, " clock: %ld (usually random)\n", (long)tmp32);
- The reason for the bug in the standards seems to be that the
- multicast bit actually is the *MOST* significant bit in IEEE 802.3
- (Ethernet) _transmission order_ of an IEEE 802 MAC address. The
- authors seem to be confused by this and especially were not aware
- that the bitwise order of an octet from a MAC address memory and
- hexadecimal string representation is still always from left (MSB, bit
- 7) to right (LSB, bit 0).
+ /* decode node MAC address */
+ str_rsprintf(out, " node: %02x:%02x:%02x:%02x:%02x:%02x (%s %s)\n",
+ (unsigned int)uuid->obj.node[0],
+ (unsigned int)uuid->obj.node[1],
+ (unsigned int)uuid->obj.node[2],
+ (unsigned int)uuid->obj.node[3],
+ (unsigned int)uuid->obj.node[4],
+ (unsigned int)uuid->obj.node[5],
+ (uuid->obj.node[0] & IEEE_MAC_LOBIT_DEC ? "local" : "global"),
+ (uuid->obj.node[0] & IEEE_MAC_MCBIT_DEC ? "multicast" : "unicast"));
+ }
+ else {
+ /* decode anything else as hexadecimal byte-string only */
- For more information on this, see especially "Understanding
- Physical Addresses" in "Ethernet -- The Definitive Guide",
- p.43, and section "ETHERNET MULTICAST ADDRESSES" in
- http://www.iana.org/assignments/ethernet-numbers.
+ /* determine annotational hint */
+ content = "not decipherable, because unknown UUID version";
+ if (isnil)
+ content = "special case of DCE 1.1 Nil UUID";
+ else if (tmp16 == 3)
+ content = "not decipherable, because message digest only";
+ else if (tmp16 == 4)
+ content = "no semantics, because random data only";
- Hence, we do it the intended/correct way and generate a real IEEE 802
- multicast address, but with a brain-dead compile-time option one can
- nevertheless enforce the broken generation of IEEE 802 MAC addresses.
- For the decoding we always use the correct way, of course. */
+ /* pack UUID into binary representation */
+ tmp_ptr = (void *)&tmp_bin;
+ tmp_len = sizeof(tmp_bin);
+ if ((rc = uuid_export_bin(uuid, &tmp_ptr, &tmp_len)) != UUID_RC_OK)
+ return rc;
-/* encoding */
-#ifdef WITH_RFC2518
-#define IEEE_MAC_MCBIT_ENC BM_OCTET(1,0,0,0,0,0,0,0)
-#else
-#define IEEE_MAC_MCBIT_ENC BM_OCTET(0,0,0,0,0,0,0,1)
-#endif
-#define IEEE_MAC_LOBIT_ENC BM_OCTET(0,0,0,0,0,0,1,0)
+ /* mask out version and variant parts */
+ tmp_bin[6] &= BM_MASK(3,0);
+ tmp_bin[8] &= BM_MASK(5,0);
-/* decoding */
-#define IEEE_MAC_MCBIT_DEC BM_OCTET(0,0,0,0,0,0,0,1)
-#define IEEE_MAC_LOBIT_DEC BM_OCTET(0,0,0,0,0,0,1,0)
+ /* dump as colon-seperated hexadecimal byte-string */
+ str_rsprintf(out,
+ "content: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n"
+ " (%s)\n",
+ (unsigned int)tmp_bin[0], (unsigned int)tmp_bin[1], (unsigned int)tmp_bin[2],
+ (unsigned int)tmp_bin[3], (unsigned int)tmp_bin[4], (unsigned int)tmp_bin[5],
+ (unsigned int)tmp_bin[6], (unsigned int)tmp_bin[7], (unsigned int)tmp_bin[8],
+ (unsigned int)tmp_bin[9], (unsigned int)tmp_bin[10], (unsigned int)tmp_bin[11],
+ (unsigned int)tmp_bin[12], (unsigned int)tmp_bin[13], (unsigned int)tmp_bin[14],
+ (unsigned int)tmp_bin[15], content);
+ }
+
+ /* provide result */
+ out_len = strlen(out_ptr)+1;
+ if (*data_ptr == NULL) {
+ *data_ptr = (void *)out_ptr;
+ if (data_len != NULL)
+ *data_len = out_len;
+ }
+ else {
+ if (data_len == NULL)
+ return UUID_RC_ARG;
+ if (*data_len < out_len)
+ return UUID_RC_MEM;
+ memcpy(*data_ptr, &out_ptr, out_len);
+ }
+
+ return UUID_RC_OK;
+}
+
+/* UUID importing */
+uuid_rc_t uuid_import(uuid_t *uuid, uuid_fmt_t fmt, const void *data_ptr, size_t data_len)
+{
+ uuid_rc_t rc;
+
+ /* sanity check argument(s) */
+ if (uuid == NULL || data_ptr == NULL)
+ return UUID_RC_ARG;
+
+ /* dispatch into format-specific functions */
+ switch (fmt) {
+ case UUID_FMT_BIN: rc = uuid_import_bin(uuid, data_ptr, data_len); break;
+ case UUID_FMT_STR: rc = uuid_import_str(uuid, data_ptr, data_len); break;
+ case UUID_FMT_TXT: rc = UUID_RC_IMP; /* not implemented */ break;
+ default: rc = UUID_RC_ARG;
+ }
+
+ return rc;
+}
+
+/* UUID exporting */
+uuid_rc_t uuid_export(uuid_t *uuid, uuid_fmt_t fmt, void **data_ptr, size_t *data_len)
+{
+ uuid_rc_t rc;
+
+ /* sanity check argument(s) */
+ if (uuid == NULL || data_ptr == NULL)
+ return UUID_RC_ARG;
+
+ /* dispatch into format-specific functions */
+ switch (fmt) {
+ case UUID_FMT_BIN: rc = uuid_export_bin(uuid, data_ptr, data_len); break;
+ case UUID_FMT_STR: rc = uuid_export_str(uuid, data_ptr, data_len); break;
+ case UUID_FMT_TXT: rc = uuid_export_txt(uuid, data_ptr, data_len); break;
+ default: rc = UUID_RC_ARG;
+ }
+
+ return rc;
+}
+
+/* INTERNAL: brand UUID with version and variant */
+static void uuid_brand(uuid_t *uuid, int version)
+{
+ /* set version (as given) */
+ uuid->obj.time_hi_and_version &= BM_MASK(11,0);
+ uuid->obj.time_hi_and_version |= BM_SHL((uuid_uint16_t)version, 12);
+
+ /* set variant (always DCE 1.1 only) */
+ uuid->obj.clock_seq_hi_and_reserved &= BM_MASK(5,0);
+ uuid->obj.clock_seq_hi_and_reserved |= BM_SHL(0x02, 6);
+ return;
+}
/* INTERNAL: generate UUID version 1: time, clock and node based */
static uuid_rc_t uuid_generate_v1(uuid_t *uuid, unsigned int mode, va_list ap)
@@ -625,6 +863,19 @@
return UUID_RC_OK;
}
+/* set UUID object to represents "Nil UUID" */
+uuid_rc_t uuid_nil(uuid_t *uuid)
+{
+ /* argument sanity check */
+ if (uuid == NULL)
+ return UUID_RC_ARG;
+
+ /* clear all octets to create "Nil UUID" */
+ memset((void *)&(uuid->obj), '\0', sizeof(uuid->obj));
+
+ return UUID_RC_OK;
+}
+
/* INTERNAL: UUID Namespace Ids as pre-defined by draft-leach-uuids-guids-01.txt
(defined here as network byte ordered octet stream for direct MD5 feeding) */
static struct {
@@ -666,10 +917,10 @@
/* custom namespace via UUID string representation */
if ((rc = uuid_create(&uuid_object)) != UUID_RC_OK)
return rc;
- if ((rc = uuid_parse(uuid_object, ns)) != UUID_RC_OK)
+ if ((rc = uuid_import_str(uuid_object, ns, strlen(ns))) != UUID_RC_OK)
return rc;
uuid_octets = (void *)&(uuid_object->obj);
- uuid_pack(uuid_object, &uuid_octets);
+ uuid_export_bin(uuid_object, &uuid_octets, NULL);
md5_update(uuid->md5, uuid_octets, UUID_LEN_BIN);
uuid_destroy(uuid_object);
}
@@ -697,9 +948,9 @@
md5_store(uuid->md5, &uuid_octets, NULL);
/* fulfill requirement of standard and convert UUID data into
- local/host byte order (this uses fact that uuid_unpack() is
+ local/host byte order (this uses fact that uuid_import_bin() is
able to operate in-place!) */
- uuid_unpack(uuid, (void *)&(uuid->obj));
+ uuid_import_bin(uuid, (void *)&(uuid->obj), UUID_LEN_BIN);
/* brand UUID with version and variant */
uuid_brand(uuid, 3);
@@ -744,172 +995,6 @@
return rc;
}
-/* decoding tables */
-static struct {
- uuid_uint8_t num;
- const char *desc;
-} uuid_dectab_variant[] = {
- { BM_OCTET(0,0,0,0,0,0,0,0), "reserved (NCS backward compatible)" },
- { BM_OCTET(1,0,0,0,0,0,0,0), "DCE 1.1, ISO/IEC 11578:1996" },
- { BM_OCTET(1,1,0,0,0,0,0,0), "reserved (Microsoft GUID)" },
- { BM_OCTET(1,1,1,0,0,0,0,0), "reserved (future use)" }
-};
-static struct {
- int num;
- const char *desc;
-} uuid_dectab_version[] = {
- { 1, "time and node based" },
- { 3, "name based" },
- { 4, "random data based" }
-};
-
-/* dump UUID object as descriptive text */
-uuid_rc_t uuid_dump(uuid_t *uuid, char **str)
-{
- const char *version;
- const char *variant;
- uuid_rc_t rc;
- uuid_uint8_t tmp8;
- uuid_uint16_t tmp16;
- uuid_uint32_t tmp32;
- char string[UUID_LEN_STR+1];
- char *s;
- unsigned int i;
- ui64_t t;
- ui64_t offset;
- int t_nsec;
- int t_usec;
- time_t t_sec;
- char buf[19+1]; /* YYYY-MM-DD HH:MM:SS */
- char *content;
- struct tm *tm;
- int isnil;
- uuid_uint8_t tmp[UUID_LEN_BIN];
- void *tmp_ptr;
-
- /* sanity check argument(s) */
- if (uuid == NULL || str == NULL)
- return UUID_RC_ARG;
-
- /* initialize output buffer */
- *str = NULL;
-
- /* decode into string representation */
- s = string;
- uuid_format(uuid, &s);
- str_rsprintf(str, "UUID: %s\n", s);
-
- /* check for special case of "Nil UUID" */
- if ((rc = uuid_isnil(uuid, &isnil)) != UUID_RC_OK)
- return rc;
-
- /* decode UUID variant */
- tmp8 = uuid->obj.clock_seq_hi_and_reserved;
- if (isnil)
- variant = "n.a.";
- else {
- variant = "unknown";
- for (i = 7; i >= 0; i--) {
- if ((tmp8 & BM_BIT(i,1)) == 0) {
- tmp8 &= ~BM_MASK(i,0);
- break;
- }
- }
- for (i = 0; i < sizeof(uuid_dectab_variant)/sizeof(uuid_dectab_variant[0]); i++) {
- if (uuid_dectab_variant[i].num == tmp8) {
- variant = uuid_dectab_variant[i].desc;
- break;
- }
- }
- }
- str_rsprintf(str, "variant: %s\n", variant);
-
- /* decode UUID version */
- tmp16 = (BM_SHR(uuid->obj.time_hi_and_version, 12) & BM_MASK(3,0));
- if (isnil)
- version = "n.a.";
- else {
- version = "unknown";
- for (i = 0; i < sizeof(uuid_dectab_version)/sizeof(uuid_dectab_version[0]); i++) {
- if (uuid_dectab_version[i].num == (int)tmp16) {
- version = uuid_dectab_version[i].desc;
- break;
- }
- }
- }
- str_rsprintf(str, "version: %d (%s)\n", (int)tmp16, version);
-
- /*
- * decode UUID content
- */
-
- if (tmp8 == BM_OCTET(1,0,0,0,0,0,0,0) && tmp16 == 1) {
- /* decode DCE 1.1 version 1 UUID */
-
- /* decode system time */
- t = ui64_rol(ui64_n2i((unsigned long)(uuid->obj.time_hi_and_version & BM_MASK(11,0))), 48, NULL),
- t = ui64_or(t, ui64_rol(ui64_n2i((unsigned long)(uuid->obj.time_mid)), 32, NULL));
- t = ui64_or(t, ui64_n2i((unsigned long)(uuid->obj.time_low)));
- offset = ui64_s2i(UUID_TIMEOFFSET, NULL, 16);
- t = ui64_sub(t, offset, NULL);
- t = ui64_divn(t, 10, &t_nsec);
- t = ui64_divn(t, 1000000, &t_usec);
- t_sec = (time_t)ui64_i2n(t);
- tm = gmtime(&t_sec);
- strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", tm);
- str_rsprintf(str, "content: time: %s.%06d.%d UTC\n", buf, t_usec, t_nsec);
-
- /* decode clock sequence */
- tmp32 = ((uuid->obj.clock_seq_hi_and_reserved & BM_MASK(5,0)) << 8)
- + uuid->obj.clock_seq_low;
- str_rsprintf(str, " clock: %ld (usually random)\n", (long)tmp32);
-
- /* decode node MAC address */
- str_rsprintf(str, " node: %02x:%02x:%02x:%02x:%02x:%02x (%s %s)\n",
- (unsigned int)uuid->obj.node[0],
- (unsigned int)uuid->obj.node[1],
- (unsigned int)uuid->obj.node[2],
- (unsigned int)uuid->obj.node[3],
- (unsigned int)uuid->obj.node[4],
- (unsigned int)uuid->obj.node[5],
- (uuid->obj.node[0] & IEEE_MAC_LOBIT_DEC ? "local" : "global"),
- (uuid->obj.node[0] & IEEE_MAC_MCBIT_DEC ? "multicast" : "unicast"));
- }
- else {
- /* decode anything else as hexadecimal byte-string only */
-
- /* determine annotational hint */
- content = "not decipherable, because unknown UUID version";
- if (isnil)
- content = "special case of DCE 1.1 Nil UUID";
- else if (tmp16 == 3)
- content = "not decipherable, because message digest only";
- else if (tmp16 == 4)
- content = "no semantics, because random data only";
-
- /* pack UUID into binary representation */
- tmp_ptr = tmp;
- if ((rc = uuid_pack(uuid, &tmp_ptr)) != UUID_RC_OK)
- return rc;
-
- /* mask out version and variant parts */
- tmp[6] &= BM_MASK(3,0);
- tmp[8] &= BM_MASK(5,0);
-
- /* dump as colon-seperated hexadecimal byte-string */
- str_rsprintf(str,
- "content: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n"
- " (%s)\n",
- (unsigned int)tmp[0], (unsigned int)tmp[1], (unsigned int)tmp[2], (unsigned int)tmp[3],
- (unsigned int)tmp[4], (unsigned int)tmp[5], (unsigned int)tmp[6], (unsigned int)tmp[7],
- (unsigned int)tmp[8], (unsigned int)tmp[9], (unsigned int)tmp[10], (unsigned int)tmp[11],
- (unsigned int)tmp[12], (unsigned int)tmp[13], (unsigned int)tmp[14], (unsigned int)tmp[15],
- content);
- }
-
- return UUID_RC_OK;
-}
-
/* translate UUID API error code into corresponding error string */
char *uuid_error(uuid_rc_t rc)
{
|