OSSP CVS Repository

ossp - Check-in [4371]
Not logged in
[Honeypot]  [Browse]  [Home]  [Login]  [Reports
[Search]  [Ticket]  [Timeline
  [Patchset]  [Tagging/Branching

Check-in Number: 4371
Date: 2004-Jan-18 20:59:12 (local)
2004-Jan-18 19:59:12 (UTC)
User:rse
Branch:
Comment: - Refactor the API by merging uuid_{unpack,pack,parse,format,dump}() functions into unified uuid_{import,export}() functions. This allows us to easily add support for other formats (e.g. XML) in the future without having the change the API in principle. - Document what DCE 1.1 UUID versions exist and what they are intended for.
Tickets:
Inspections:
Files:
ossp-pkg/uuid/ChangeLog      1.26 -> 1.27     10 inserted, 0 deleted
ossp-pkg/uuid/TODO      1.14 -> 1.15     1 inserted, 8 deleted
ossp-pkg/uuid/uuid.c      1.35 -> 1.36     364 inserted, 279 deleted
ossp-pkg/uuid/uuid.h      1.12 -> 1.13     16 inserted, 13 deleted
ossp-pkg/uuid/uuid.pod      added-> 1.11
ossp-pkg/uuid/uuid_cli.c      added-> 1.11

ossp-pkg/uuid/ChangeLog 1.26 -> 1.27

--- ChangeLog    2004/01/18 19:22:54     1.26
+++ ChangeLog    2004/01/18 19:59:12     1.27
@@ -13,6 +13,16 @@
 
   Changes between 0.9.3 and 0.9.4 (16-Jan-2004 to xx-Jan-2004)
 
+   o Refactor the API by merging uuid_{unpack,pack,parse,format,dump}()
+     functions into unified uuid_{import,export}() functions. This
+     allows us to easily add support for other formats (e.g. XML) in the
+     future without having the change the API in principle.
+     [Ralf S. Engelschall]
+
+   o Document what DCE 1.1 UUID versions exist and what they are
+     intended for.
+     [Ralf S. Engelschall]
+
    o Cleanup the C code to also pass warning-free a C++ compiler.
      [Ralf S. Engelschall]
 


ossp-pkg/uuid/TODO 1.14 -> 1.15

--- TODO 2004/01/18 19:23:12     1.14
+++ TODO 2004/01/18 19:59:12     1.15
@@ -1,9 +1,6 @@
 TODO
 - API versioning
-- documentation of Vx and intentions
-  v1: one-time global unique identifier
-  v3: repeatable not-unique message digest
-  v4: one-time local unique identifier
+- why are nanoseconds always "1"?!
 CANDO
 - getopt_long support
 - a more sophisticated test suite
@@ -12,7 +9,3 @@
 - persistent/non-volatile state writing?
 - additional Perl API for covering Perl language
 - additional C API for DCE 1.1 compatibility
-- unify pack/unpack/parse/format/dump into:
-  typedef enum { UUID_FMT_BIN, UUID_FMT_STR, UUID_FMT_TXT, UUID_FMT_XML } uuid_fmt_t;
-  uuid_rc_t uuid_import(uuid_t *_uuid, uuid_fmt_t _fmt, const void  *_buf, size_t _size);
-  uuid_rc_t uuid_export(uuid_t *_uuid, uuid_fmt_t _fmt,       void **_buf, size_t _size);


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


ossp-pkg/uuid/uuid.h 1.12 -> 1.13

--- uuid.h       2004/01/18 19:22:54     1.12
+++ uuid.h       2004/01/18 19:59:12     1.13
@@ -51,7 +51,8 @@
     UUID_RC_ARG = 1,
     UUID_RC_MEM = 2,
     UUID_RC_SYS = 3,
-    UUID_RC_INT = 4
+    UUID_RC_INT = 4,
+    UUID_RC_IMP = 5
 } uuid_rc_t;
 
 /* generation mode flags */
@@ -62,6 +63,13 @@
     UUID_MCASTRND      = (1 << 3)
 };
 
+/* import/export formats */
+typedef enum {
+    UUID_FMT_BIN = 0, /* import/export */
+    UUID_FMT_STR = 1, /* import/export */
+    UUID_FMT_TXT = 2  /* export only */
+} uuid_fmt_t;
+
 /* abstract data type */
 struct uuid_st;
 typedef struct uuid_st uuid_t;
@@ -69,25 +77,20 @@
 /* object handling */
 extern uuid_rc_t  uuid_create   (uuid_t **_uuid);
 extern uuid_rc_t  uuid_destroy  (uuid_t  *_uuid);
+
+/* UUID generation */
 extern uuid_rc_t  uuid_nil      (uuid_t  *_uuid);
+extern uuid_rc_t  uuid_generate (uuid_t  *_uuid, unsigned int _mode, ...);
 
 /* UUID comparison */
 extern uuid_rc_t  uuid_isnil    (uuid_t  *_uuid,                 int *_result);
 extern uuid_rc_t  uuid_compare  (uuid_t  *_uuid, uuid_t *_uuid2, int *_result);
 
-/* UUID binary representation handling */
-extern uuid_rc_t  uuid_unpack   (uuid_t  *_uuid, const void  *_buf);
-extern uuid_rc_t  uuid_pack     (uuid_t  *_uuid,       void **_buf);
-
-/* UUID string representation handling */
-extern uuid_rc_t  uuid_parse    (uuid_t  *_uuid, const char  *_str);
-extern uuid_rc_t  uuid_format   (uuid_t  *_uuid,       char **_str);
-
-/* UUID generation and dumping */
-extern uuid_rc_t  uuid_generate (uuid_t  *_uuid, unsigned int _mode, ...);
-extern uuid_rc_t  uuid_dump     (uuid_t  *_uuid, char **_str);
+/* UUID import/export */
+extern uuid_rc_t  uuid_import   (uuid_t  *_uuid, uuid_fmt_t _fmt, const void  *_data_ptr, size_t  _data_len);
+extern uuid_rc_t  uuid_export   (uuid_t  *_uuid, uuid_fmt_t _fmt,       void **_data_ptr, size_t *_data_len);
 
-/* error handling */
+/* library error handling */
 extern char      *uuid_error    (uuid_rc_t _rc);
 
 DECLARATION_END


ossp-pkg/uuid/uuid.pod -> 1.11

*** /dev/null    Mon Apr 29 20:15:38 2024
--- -    Mon Apr 29 20:17:32 2024
***************
*** 0 ****
--- 1,398 ----
+ ##
+ ##  OSSP uuid - Universally Unique Identifier
+ ##  Copyright (c) 2004 Ralf S. Engelschall <rse@engelschall.com>
+ ##  Copyright (c) 2004 The OSSP Project <http://www.ossp.org/>
+ ##
+ ##  This file is part of OSSP uuid, a library for the generation
+ ##  of UUIDs which can found at http://www.ossp.org/pkg/lib/uuid/
+ ##
+ ##  Permission to use, copy, modify, and distribute this software for
+ ##  any purpose with or without fee is hereby granted, provided that
+ ##  the above copyright notice and this permission notice appear in all
+ ##  copies.
+ ##
+ ##  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ ##  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ ##  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ ##  IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
+ ##  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ ##  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ ##  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ ##  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ ##  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ ##  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ ##  OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ ##  SUCH DAMAGE.
+ ##
+ ##  uuid.pod: manual page
+ ##
+ 
+ =pod
+ 
+ =head1 NAME
+ 
+ B<OSSP uuid> - B<Universally Unique Identifier>
+ 
+ =head1 VERSION
+ 
+ OSSP uuid UUID_VERSION_STR
+ 
+ =head1 DESCRIPTION
+ 
+ B<OSSP uuid> is a ISO-C application programming interface (API) and
+ corresponding command line interface (CLI) for the generation of DCE
+ 1.1 and ISO/IEC 11578:1996 compliant I<Universally Unique Identifier>
+ (UUID). It supports DCE 1.1 variant UUIDs of version 1 (time and node
+ based), version 3 (name based) and version 4 (random number based).
+ 
+ UUIDs are 128 bit numbers which are intended to have a high likelihood
+ of uniqueness over space and time and are computationally difficult
+ to guess. They are globally unique identifiers which can be locally
+ generated without contacting a global registration authority. UUIDs
+ are intended as unique identifiers for both mass tagging objects
+ with an extremely short lifetime and to reliably identifying very
+ persistent objects across a network.
+ 
+ This is the ISO-C application programming interface (API) of B<OSSP uuid>.
+ 
+ =head2 UUID Binary Representation
+ 
+ According to the DCE 1.1 and ISO/IEC 11578:1996 standards, a DCE 1.1
+ variant UUID is a 128 bit number defined out of 7 fields, each field a
+ multiple of an octet in size and stored in network byte order:
+ 
+   0                   1                   2                   3
+    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+  0|                          time_low                             |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+  1|       time_mid                |         time_hi_and_version   |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+  2|clk_seq_hi_res |  clk_seq_low  |         node (0-1)            |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+  3|                         node (2-5)                            |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ 
+ An example of a UUID binary representation is the octet stream "C<0xEC
+ 0xB9 0xF3 0x5F 0x44 0x2A 0x11 0xD8 0x8A 0x24 0x00 0x90 0x27 0x2F 0xF7
+ 0x25>". The binary representation format is exactly what the B<OSSP uuid>
+ API functions B<uuid_pack>() and B<uuid_unpack>() deal with.
+ 
+ =head2 UUID ASCII String Representation
+ 
+ According to the DCE 1.1 and ISO/IEC 11578:1996 standards, a DCE
+ 1.1 variant UUID is represented as an ASCII string consisting
+ of 8 hexadecimal digits followed by a hyphen, then three groups
+ of 4 hexadecimal digits each followed by a hyphen, then 12
+ hexadecimal digits. Formally, the string representation is defined by
+ the following grammar:
+ 
+  uuid                   = <time_low> "-" <time_mid> "-"
+                           <time_high_and_version> "-"
+                           <clock_seq_and_reserved>
+                           <clock_seq_low> "-" <node>
+  time_low               = 4*<hex_octet>
+  time_mid               = 2*<hex_octet>
+  time_high_and_version  = 2*<hex_octet>
+  clock_seq_and_reserved = <hex_octet>
+  clock_seq_low          = <hex_octet>
+  node                   = 6*<hex_octet>
+  hex_octet              = <hex_digit> <hex_digit>
+  hex_digit              = "0"|"1"|"2"|"3"|"4"|"5"|"6"|"7"|"8"|"9"
+                          |"a"|"b"|"c"|"d"|"e"|"f"
+                          |"A"|"B"|"C"|"D"|"E"|"F"
+ 
+ An example of a UUID string representation is the ASCII string
+ "C<54531d28-402b-11d8-af12-0002a5094c23>". The string representation
+ format is exactly what the B<OSSP uuid> API functions B<uuid_parse>() and
+ B<uuid_format>() deal with.
+ 
+ =head2 UUID Variants and Versions
+ 
+ A UUID has a variant and version. The variant defines the layout of the
+ UUID. The version defines the content of the UUID. The UUID variant
+ supported in B<OSSP uuid> is the DCE 1.1 variant only. The DCE 1.1 UUID
+ variant versions supported in B<OSSP uuid> are:
+ 
+ =over 4
+ 
+ =item B<Version 1> (time and node based)
+ 
+ These are the classical UUIDs, created out of a 60-bit system time,
+ a 14-bit local clock sequence and 48-bit system MAC address. The MAC
+ address can be either the real one of a physical network interface card
+ (NIC) or a random multi-cast MAC address. Version 1 UUIDs are usually
+ used as one-time global unique identifiers.
+ 
+ =item B<Version 3> (name based)
+ 
+ These are UUIDs which are based on the 128-bit MD5 message digest of the
+ concatenation of a 128-bit namespace UUID and a name string of arbitrary
+ length. Version 3 UUIDs are usually used for non-unique but repeatable
+ message digest identifiers.
+ 
+ =item B<Version 4> (random data based)
+ 
+ These are UUIDs which are based on just 128-bit of random data. Version
+ 4 UUIDs are usually used as one-time local unique identifiers.
+ 
+ =back
+ 
+ =head2 UUID Uniqueness
+ 
+ Version 1 UUIDs are guaranteed to be unique through combinations of
+ hardware addresses, time stamps and random seeds. There is a reference
+ in the UUID to the hardware (MAC) address of the first network interface
+ card (NIC) on the host which generated the UUID -- this reference
+ is intended to ensure the UUID will be unique in space as the MAC
+ address of every network card is assigned by a single global authority
+ (IEEE) and is guaranteed to be unique. The next component in a UUID
+ is a timestamp which, as clock always (should) move forward, will
+ be unique in time. Just in case some part of the above goes wrong
+ (the hardware address cannot be determined or the clock moved steps
+ backward), there is a random clock sequence component placed into the
+ UUID as a "catch-all" for uniqueness.
+ 
+ Version 3 UUIDs are guaranteed to be inherently globally unique if the
+ combination of namespace and name used to generate them is unique.
+ 
+ Version 4 UUIDs are not guaranteed to be globally unique, because they
+ are generated out of locally gathered pseudo-random numbers only.
+ Nevertheless there is still a high likelihood of uniqueness over space
+ and time and that they are computationally difficult to guess.
+ 
+ =head2 Nil UUID
+ 
+ There is a special I<Nil> UUID consisting of all octets set to zero in
+ the binary representation. It can be used as a special UUID value which does
+ not conflict with real UUIDs.
+ 
+ =head1 APPLICATION PROGRAMMING INTERFACE
+ 
+ The ISO-C Application Programming Interface (API) of B<OSSP uuid>
+ consists of the following components.
+ 
+ =head2 CONSTANTS
+ 
+ The following constants are provided:
+ 
+ =over 4
+ 
+ =item B<UUID_LEN_BIN>, B<UUID_LEN_STR>
+ 
+ The number of octets of the UUID binary and string representations.
+ Notice that the lengths of the string representation does I<not> include
+ the necessary C<NUL> termination character.
+ 
+ =item B<UUID_VERSION1>, B<UUID_VERSION3>, B<UUID_VERSION4>, B<UUID_MCASTRND>
+ 
+ The I<mode> bits for use with B<uuid_generate>(). The
+ B<UUID_VERSION>I<N> specify which UUID version to generate. The
+ B<UUID_MCASTRND> forces the use of a random multi-cast MAC address
+ instead of the real physical MAC address in version 1 UUIDs.
+ 
+ =item B<UUID_RC_OK>, B<UUID_RC_ARG>, B<UUID_RC_MEM>, B<UUID_RC_SYS>, B<UUID_RC_INT>
+ 
+ The possible numerical return-codes of API functions.
+ Use B<uuid_error>() to translate them into string versions.
+ 
+ =item B<UUID_FMT_BIN>, B<UUID_FMT_STR>, B<UUID_FMT_TXT>
+ 
+ The I<fmt> formats for use with B<uuid_import>() and B<uuid_export>().
+ The B<UUID_FMT_BIN> indicates the UUID binary representation (of
+ length B<UUID_LEN_BIN>), the B<UUID_FMT_STR> indicates the UUID string
+ representation (of length B<UUID_LEN_STR>) and the B<UUID_FMT_TXT>
+ indicates the textual description (of arbitrary length) of a UUID.
+ 
+ =back
+ 
+ =head2 FUNCTIONS
+ 
+ The following functions are provided:
+ 
+ =over 4
+ 
+ =item uuid_rc_t B<uuid_create>(uuid_t **I<uuid>);
+ 
+ Create a new UUID object and store a pointer to it in C<*>I<uuid>.
+ A UUID object consists of an internal representation of a UUID, the
+ internal PRNG and MD5 generator contexts, and cached MAC address and
+ timestamp information. The initial UUID is the I<Nil> UUID.
+ 
+ =item uuid_rc_t B<uuid_destroy>(uuid_t *I<uuid>);
+ 
+ Destroy UUID object I<uuid>.
+ 
+ =item uuid_rc_t B<uuid_nil>(uuid_t *I<uuid>);
+ 
+ Sets or resets the UUID in I<uuid> to the I<Nil> UUID.
+ 
+ =item uuid_rc_t B<uuid_isnil>(uuid_t *I<uuid>, int *I<result>);
+ 
+ Checks whether the UUID in I<uuid> is the I<Nil> UUID.
+ If this is the case, it returns I<true> in C<*>I<result>.
+ Else it returns I<false> in C<*>I<result>.
+ 
+ =item uuid_rc_t B<uuid_compare>(uuid_t *I<uuid>, uuid_t *I<uuid2>, int *I<result>);
+ 
+ Compares the order of the two UUIDs in I<uuid1> and I<uuid2>
+ and returns the result in C<*>I<result>: C<-1> if I<uuid1> is
+ smaller than I<uuid2>, C<0> if I<uuid1> is equal to I<uuid2>
+ and C<+1> if I<uuid1> is greater than I<uuid2>.
+ 
+ 
+ =item uuid_rc_t B<uuid_import>(uuid_t *I<uuid>, uuid_fmt_t I<fmt>, const void *I<data_ptr>, size_t I<data_len>);
+ 
+ Imports a UUID I<uuid> from an external representation of format I<fmt>.
+ The data is read from the buffer at I<data_ptr> which contains at least
+ I<data_len> bytes.
+ 
+ The format of the external representation is specified by I<fmt> and the
+ minimum expected length in I<data_len> depends on it. Valid values for
+ I<fmt> are B<UUID_FMT_BIN> and B<UUID_FMT_STR>.
+ 
+ =item uuid_rc_t B<uuid_export>(uuid_t *I<uuid>, uuid_fmt_t I<fmt>, void **I<data_ptr>, size_t *I<data_len>);
+ 
+ Exports a UUID I<uuid> into an external representation of format I<fmt>.
+ The data is written to the buffer at C<*>I<data_ptr> which has room
+ for at least C<*>I<data_len> bytes. If C<*>I<data_ptr> is C<NULL>,
+ a new buffer is allocated (and I<data_len> ignored as input). If
+ I<data_len> is not C<NULL>, the number of written bytes are stored into
+ C<*>I<data_len>.
+ 
+ The format of the external representation is specified by I<fmt> and the
+ minimum required length in C<*>I<data_len> depends on it. Valid values
+ for I<fmt> are B<UUID_FMT_BIN>, B<UUID_FMT_STR> and B<UUID_FMT_TXT>.
+ 
+ =item uuid_rc_t B<uuid_generate>(uuid_t *I<uuid>, unsigned int I<mode>, ...);
+ 
+ Generates a new UUID in I<uuid> according to I<mode> and optional
+ arguments (dependent on I<mode>).
+ 
+ If I<mode> contains the C<UUID_VERSION1> bit, a DCE 1.1 variant UUID of
+ version 1 is generated. Then optionally the bit C<UUID_MCASTRND> forces
+ the use of random multi-cast MAC address instead of the real physical
+ MAC address (the default). The UUID is generated out of the 60-bit current
+ system time, a 12-bit clock sequence and the 48-bit MAC address.
+ 
+ If I<mode> contains the C<UUID_VERSION3> bit, a DCE 1.1 variant UUID
+ of version 3 is generated and two additional C<NUL>-terminated string
+ arguments of type "C<const char *>" are expected: first a namespace,
+ given as an internally pre-defined id (currently known are ids "C<DNS>",
+ "C<URL>", "C<OID>", and "C<X500>") or a UUID in string representation.
+ Second, a name string of arbitrary length. The UUID is generated out of
+ the 128-bit MD5 from the concatenated octet stream of namespace UUID and name
+ string.
+ 
+ If I<mode> contains the C<UUID_VERSION4> bit, a DCE 1.1 variant UUID
+ of version 4 is generated. The UUID is generated out of 128-bit random
+ data.
+ 
+ =item char *B<uuid_error>(uuid_rc_t I<rc>);
+ 
+ Returns a constant string representation corresponding to the
+ return-code I<rc> for use in displaying B<OSSP uuid> errors.
+ 
+ =back
+ 
+ =head1 EXAMPLE
+ 
+ The following shows an example usage of the API. Error handling is
+ omitted for code simplification and has to be re-added for production
+ code.
+ 
+  /* generate a DCE 1.1 v1 UUID from system environment */
+  char *uuid_v1(void) 
+  {
+      uuid_t *uuid;
+      char *str = NULL;
+ 
+      uuid_create(&uuid);
+      uuid_generate(uuid, UUID_VERSION1);
+      uuid_export(uuid, UUID_FMT_STR, &str, NULL);
+      uuid_destroy(uuid);
+      return str;
+  }
+ 
+  /* generate a DCE 1.1 v3 UUID from an URL */
+  char *uuid_v3(const char *url) 
+  {
+      uuid_t *uuid;
+      char *str = NULL;
+ 
+      uuid_create(&uuid);
+      uuid_generate(uuid, UUID_VERSION3, "URL", url);
+      uuid_export(uuid, UUID_FMT_STR, &str, NULL);
+      uuid_destroy(uuid);
+      return str;
+  }
+ 
+ =head1 SEE ALSO
+ 
+ See the following are references to more B<UUID> documentation and specifications:
+ 
+ =over 4
+ 
+ =item 
+ 
+ B<UUIDs and GUIDs>,
+ IETF Internet Draft (expired),
+ Paul J. Leach, Rich Salz,
+ February 1998, 27 pages,
+ http://www.opengroup.org/dce/info/draft-leach-uuids-guids-01.txt
+ 
+ =item 
+ 
+ B<DCE 1.1: Remote Procedure Call>,
+ appendix B<Universally Unique Identifier>,
+ Open Group Technical Standard
+ Document Number C706, August 1997, 737 pages,
+ (supersedes C309 DCE: Remote Procedure Call 8/1994,
+ which was basis for ISO/IEC 11578:1996 specification),
+ http://www.opengroup.org/publications/catalog/c706.htm 
+ 
+ =item 
+ 
+ B<Information technology -- Open Systems Interconnection (OSI) -- Remote Procedure Call (RPC)>,
+ ISO/IEC 11578:1996,
+ August 2001, 570 pages, (CHF 340,00),
+ http://www.iso.ch/cate/d2229.html
+ 
+ =item 
+ 
+ B<HTTP Extensions for Distributed Authoring (WebDAV)>,
+ section B<6.4.1 Node Field Generation Without the IEEE 802 Address>,
+ IETF RFC 2518,
+ February 1999, 94 pages,
+ http://www.ietf.org/rfc/rfc2518.txt
+ 
+ =item
+ 
+ B<A UUID URN Namespace>,
+ P. Leach, M. Mealling, R. Salz,
+ IETF Internet Draft draft-mealling-uuid-urn-01,
+ October 2003, 31 pages,
+ http://www.ietf.org/internet-drafts/draft-mealling-uuid-urn-01.txt
+ 
+ =item
+ 
+ B<DCE 1.1 compliant UUID functions>,
+ FreeBSD manual pages uuid(3) and uuidgen(2),
+ http://www.freebsd.org/cgi/man.cgi?query=uuid&manpath=FreeBSD+5.2-RELEASE
+ 
+ =back
+ 
+ =head1 HISTORY
+ 
+ B<OSSP uuid> was implemented in January 2004 by Ralf S. Engelschall
+ E<lt>rse@engelschall.comE<gt>. It was prompted by the use of UUIDs
+ in the B<OSSP as> and B<OpenPKG> projects. It is a clean room
+ implementation intended to be strictly standards compliant and maximum
+ portable.
+ 
+ =head1 SEE ALSO
+ 
+ uuid(1), uuid-config(1).
+ 
+ =cut
+ 


ossp-pkg/uuid/uuid_cli.c -> 1.11

*** /dev/null    Mon Apr 29 20:15:38 2024
--- -    Mon Apr 29 20:17:32 2024
***************
*** 0 ****
--- 1,213 ----
+ /*
+ **  OSSP uuid - Universally Unique Identifier
+ **  Copyright (c) 2004 Ralf S. Engelschall <rse@engelschall.com>
+ **  Copyright (c) 2004 The OSSP Project <http://www.ossp.org/>
+ **
+ **  This file is part of OSSP uuid, a library for the generation
+ **  of UUIDs which can found at http://www.ossp.org/pkg/lib/uuid/
+ **
+ **  Permission to use, copy, modify, and distribute this software for
+ **  any purpose with or without fee is hereby granted, provided that
+ **  the above copyright notice and this permission notice appear in all
+ **  copies.
+ **
+ **  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ **  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ **  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ **  IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
+ **  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ **  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ **  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ **  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ **  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ **  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ **  OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ **  SUCH DAMAGE.
+ **
+ **  uuid_cli.c: command line tool
+ */
+ 
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <stdarg.h>
+ #include <unistd.h>
+ #include <string.h>
+ #include <errno.h>
+ 
+ #include "uuid.h"
+ 
+ /* error handler */
+ static void
+ error(int ec, const char *str, ...)
+ {
+     va_list ap;
+ 
+     va_start(ap, str);
+     fprintf(stderr, "uuid:ERROR: ");
+     vfprintf(stderr, str, ap);
+     fprintf(stderr, "\n");
+     va_end(ap);
+     exit(ec);
+ }
+ 
+ /* usage handler */
+ static void
+ usage(const char *str, ...)
+ {
+     va_list ap;
+ 
+     va_start(ap, str);
+     if (str != NULL) {
+         fprintf(stderr, "uuid:ERROR: ");
+         vfprintf(stderr, str, ap);
+         fprintf(stderr, "\n");
+     }
+     fprintf(stderr, "usage: uuid [-1] [-n count] [-a] [-d] [-o filename] [UUID]\n");
+     va_end(ap);
+     exit(1);
+ }
+ 
+ /* main procedure */
+ int main(int argc, char *argv[])
+ {
+     uuid_t *uuid;
+     uuid_rc_t rc;
+     FILE *fp;
+     char *p;
+     int ch;
+     int count;
+     int i;
+     int iterate;
+     int raw;
+     int decode;
+     char *cp;
+     void *vp;
+     size_t n;
+     unsigned int version;
+ 
+     /* command line parsing */
+     count = -1;     /* no count yet */
+     fp = stdout;    /* default output file */
+     iterate = 0;    /* not one at a time */
+     raw = 0;        /* default is ASCII output */
+     decode = 0;     /* default is to encode */
+     version = UUID_VERSION1;
+     while ((ch = getopt(argc, argv, "1n:rdmo:v:")) != -1) {
+         switch (ch) {
+             case '1':
+                 iterate = 1;
+                 break;
+             case 'n':
+                 if (count > 0)
+                     usage("option 'n' specified multiple times");
+                 count = strtol(optarg, &p, 10);
+                 if (*p != '\0' || count < 1)
+                     usage("invalid argument to option 'n'");
+                 break;
+             case 'r':
+                 raw = 1;
+                 break;
+             case 'd':
+                 decode = 1;
+                 break;
+             case 'o':
+                 if (fp != stdout)
+                     error(1, "multiple output files are not allowed");
+                 if ((fp = fopen(optarg, "w")) == NULL)
+                     error(1, "fopen: %s", strerror(errno));
+                 break;
+             case 'm':
+                 version |= UUID_MCASTRND;
+                 break;
+             case 'v':
+                 i = strtol(optarg, &p, 10);
+                 if (*p != '\0')
+                     usage("invalid argument to option 'v'");
+                 switch (i) {
+                     case 1: version = UUID_VERSION1; break;;
+                     case 3: version = UUID_VERSION3; break;;
+                     case 4: version = UUID_VERSION4; break;;
+                     default:
+                         usage("invalid version on option 'v'");
+                         break;
+                 }
+                 break;
+             default:
+                 usage("invalid option '%c'", optopt);
+         }
+     }
+     argv += optind;
+     argc -= optind;
+     if (count == -1)
+         count = 1;
+ 
+     if (decode) {
+         /* decoding */
+         if (argc != 1)
+             usage("invalid number of arguments");
+         if ((rc = uuid_create(&uuid)) != UUID_RC_OK)
+             error(1, "uuid_create: %s", uuid_error(rc));
+         if (strlen(argv[0]) != UUID_LEN_STR)
+             error(1, "invalid length of UUID string representation");
+         if ((rc = uuid_import(uuid, UUID_FMT_STR, argv[0], strlen(argv[0]))) != UUID_RC_OK)
+             error(1, "uuid_parse: %s", uuid_error(rc));
+         cp = NULL;
+         if ((rc = uuid_export(uuid, UUID_FMT_TXT, (void **)&cp, NULL)) != UUID_RC_OK)
+             error(1, "uuid_dump: %s", uuid_error(rc));
+         fprintf(stdout, "%s", cp);
+         free(cp);
+         if ((rc = uuid_destroy(uuid)) != UUID_RC_OK)
+             error(1, "uuid_destroy: %s", uuid_error(rc));
+     }
+     else {
+         /* encoding */
+         if (   (version == UUID_VERSION1 && argc != 0)
+             || (version == UUID_VERSION3 && argc != 2)
+             || (version == UUID_VERSION4 && argc != 0))
+             usage("invalid number of arguments");
+         if ((rc = uuid_create(&uuid)) != UUID_RC_OK)
+             error(1, "uuid_create: %s", uuid_error(rc));
+         if (argc == 1) {
+             /* load initial UUID for setting old generator state */
+             if (strlen(argv[0]) != UUID_LEN_STR)
+                 error(1, "invalid length of UUID string representation");
+             if ((rc = uuid_import(uuid, UUID_FMT_STR, argv[0], strlen(argv[0]))) != UUID_RC_OK)
+                 error(1, "uuid_parse: %s", uuid_error(rc));
+         }
+         for (i = 0; i < count; i++) {
+             if (iterate) {
+                 if ((rc = uuid_nil(uuid)) != UUID_RC_OK)
+                     error(1, "uuid_nil: %s", uuid_error(rc));
+             }
+             if (version == UUID_VERSION3)
+                 rc = uuid_generate(uuid, version, argv[0], argv[1]);
+             else
+                 rc = uuid_generate(uuid, version);
+             if (rc != UUID_RC_OK)
+                 error(1, "uuid_generate: %s", uuid_error(rc));
+             if (raw) {
+                 vp = NULL;
+                 if ((rc = uuid_export(uuid, UUID_FMT_BIN, &vp, &n)) != UUID_RC_OK)
+                     error(1, "uuid_export: %s", uuid_error(rc));
+                 fwrite(vp, n, 1, fp);
+                 free(vp);
+             }
+             else {
+                 cp = NULL;
+                 if ((rc = uuid_export(uuid, UUID_FMT_STR, (void **)&cp, &n)) != UUID_RC_OK)
+                     error(1, "uuid_format: %s", uuid_error(rc));
+                 fprintf(fp, "%s\n", cp);
+                 free(cp);
+             }
+         }
+         if ((rc = uuid_destroy(uuid)) != UUID_RC_OK)
+             error(1, "uuid_destroy: %s", uuid_error(rc));
+     }
+ 
+     /* close output channel */
+     if (fp != stdout)
+         fclose(fp);
+ 
+     return 0;
+ }
+ 

CVSTrac 2.0.1