OSSP CVS Repository

ossp - Difference in ossp-pkg/uuid/uuid.c versions 1.35 and 1.36
Not logged in
[Honeypot]  [Browse]  [Home]  [Login]  [Reports
[Search]  [Ticket]  [Timeline
  [History

ossp-pkg/uuid/uuid.c 1.35 -> 1.36

--- 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)
 {

CVSTrac 2.0.1