/* ** OSSP uuid - Universally Unique Identifier ** Copyright (c) 2004 Ralf S. Engelschall ** Copyright (c) 2004 The OSSP Project ** ** 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.c: library API implementation */ #include #include #include #include #include #include #include "config.h" #include "uuid.h" #include "uuid_ui64.h" /* determine types of 8-bit size */ #if SIZEOF_CHAR == 1 typedef char uuid_int8_t; #else #error uexpected: sizeof(char) != 1 !? #endif #if SIZEOF_UNSIGNED_CHAR == 1 typedef unsigned char uuid_uint8_t; #else #error uexpected: sizeof(unsigned char) != 1 !? #endif /* determine types of 16-bit size */ #if SIZEOF_SHORT == 2 typedef short uuid_int16_t; #elif SIZEOF_INT == 2 typedef int uuid_int16_t; #elif SIZEOF_LONG == 2 typedef long uuid_int16_t; #else #error unexpected: no type found for uuid_int16_t #endif #if SIZEOF_UNSIGNED_SHORT == 2 typedef unsigned short uuid_uint16_t; #elif SIZEOF_UNSIGNED_INT == 2 typedef unsigned int uuid_uint16_t; #elif SIZEOF_UNSIGNED_LONG == 2 typedef unsigned long uuid_uint16_t; #else #error unexpected: no type found for uuid_uint16_t #endif /* determine types of 32-bit size */ #if SIZEOF_SHORT == 4 typedef short uuid_int32_t; #elif SIZEOF_INT == 4 typedef int uuid_int32_t; #elif SIZEOF_LONG == 4 typedef long uuid_int32_t; #elif SIZEOF_LONG_LONG == 4 typedef long long uuid_int32_t; #else #error unexpected: no type found for uuid_int32_t #endif #if SIZEOF_UNSIGNED_SHORT == 4 typedef unsigned short uuid_uint32_t; #elif SIZEOF_UNSIGNED_INT == 4 typedef unsigned int uuid_uint32_t; #elif SIZEOF_UNSIGNED_LONG == 4 typedef unsigned long uuid_uint32_t; #elif SIZEOF_UNSIGNED_LONG_LONG == 4 typedef unsigned long long uuid_uint32_t; #else #error unexpected: no type found for uuid_uint32_t #endif #ifndef FALSE #define FALSE 0 #endif #ifndef TRUE #define TRUE !FALSE #endif /* UUID binary representation according to UUID standards */ struct uuid_st { uuid_uint32_t time_low; uuid_uint16_t time_mid; uuid_uint16_t time_hi_and_version; uuid_uint8_t clock_seq_hi_and_reserved; uuid_uint8_t clock_seq_low; uuid_uint8_t node[6]; }; uuid_rc_t uuid_create(uuid_t **uuid) { /* argument sanity check */ if (uuid == NULL) return UUID_RC_ARG; /* allocate UUID binary representation buffer */ if ((*uuid = (uuid_t *)malloc(sizeof(uuid_t))) == NULL) return UUID_RC_MEM; /* set initially to "nil UUID" */ uuid_nil(*uuid); return UUID_RC_OK; } uuid_rc_t uuid_destroy(uuid_t *uuid) { /* argument sanity check */ if (uuid == NULL) return UUID_RC_ARG; /* free UUID binary representation buffer */ free(uuid); return UUID_RC_OK; } 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(uuid, '\0', sizeof(uuid_t)); return UUID_RC_OK; } uuid_rc_t uuid_compare(uuid_t *a, uuid_t *b, int *result) { int r; /* argument sanity check */ if (result == NULL) return UUID_RC_ARG; /* convinience macro for setting result */ # define RESULT(r) \ do { \ *result = (r); \ goto result_exit; \ } while (0) /* special cases: NULL or equal UUIDs */ if (a == b) RESULT(0); if (a == NULL && b == NULL) RESULT(0); if (a == NULL) RESULT((uuid_isnil(b, &r), r) ? 0 : -1); if (b == NULL) RESULT((uuid_isnil(a, &r), r) ? 0 : 1); /* standard cases: regular different UUIDs */ if (a->time_low != b->time_low) RESULT((a->time_low < b->time_low) ? -1 : 1); if ((r = (int)a->time_mid - (int)b->time_mid) != 0) RESULT((r < 0) ? -1 : 1); if ((r = (int)a->time_hi_and_version - (int)b->time_hi_and_version) != 0) RESULT((r < 0) ? -1 : 1); if ((r = (int)a->clock_seq_hi_and_reserved - (int)b->clock_seq_hi_and_reserved) != 0) RESULT((r < 0) ? -1 : 1); if ((r = (int)a->clock_seq_low - (int)b->clock_seq_low) != 0) RESULT((r < 0) ? -1 : 1); if ((r = memcmp(a->node, b->node, sizeof(a->node))) != 0) RESULT((r < 0) ? -1 : 1); /* default case: the keys are equal */ *result = 0; result_exit: return UUID_RC_OK; } uuid_rc_t uuid_isnil(uuid_t *uuid, int *result) { const unsigned char *ucp; int i; /* sanity check argument(s) */ if (uuid == NULL || result == NULL) return UUID_RC_ARG; /* a "nil UUID" is defined as all octets zero, so check for this case */ *result = TRUE; for (i = 0, ucp = (unsigned char *)uuid; i < UUID_LEN_BIN; i++) { if (*ucp++ != '\0') { *result = FALSE; break; } } return UUID_RC_OK; } uuid_rc_t uuid_unpack(uuid_t *uuid, const void *buf) { const uuid_uint8_t *in; uuid_uint32_t tmp32; uuid_uint16_t tmp16; int i; /* sanity check argument(s) */ if (uuid == NULL || buf == NULL) return UUID_RC_ARG; /* treat input buffer as octet stream */ in = (const uuid_uint8_t *)buf; /* unpack "time_low" field */ tmp32 = *in++; tmp32 = (tmp32 << 8) | *in++; tmp32 = (tmp32 << 8) | *in++; tmp32 = (tmp32 << 8) | *in++; uuid->time_low = tmp32; /* unpack "time_mid" field */ tmp16 = *in++; tmp16 = (tmp16 << 8) | *in++; uuid->time_mid = tmp16; /* unpack "time_hi_and_version" field */ tmp16 = *in++; tmp16 = (tmp16 << 8) | *in++; uuid->time_hi_and_version = tmp16; /* unpack "clock_seq_hi_and_reserved" field */ uuid->clock_seq_hi_and_reserved = *in++; /* unpack "clock_seq_low" field */ uuid->clock_seq_low = *in++; /* unpack "node" field */ for (i = 0; i < sizeof(uuid->node); i++) uuid->node[i] = *in++; return UUID_RC_OK; } uuid_rc_t uuid_pack(uuid_t *uuid, void **buf) { uuid_uint8_t *out; uuid_uint32_t tmp32; uuid_uint16_t tmp16; int i; /* sanity check argument(s) */ if (uuid == NULL || buf == NULL) return UUID_RC_ARG; /* optionally allocate octet buffer */ if (*buf == NULL) if ((*buf = malloc(sizeof(uuid_t))) == NULL) return UUID_RC_MEM; /* treat output buffer as octet stream */ out = (uuid_uint8_t *)(*buf); /* pack "time_low" field */ tmp32 = uuid->time_low; out[3] = (uuid_uint8_t)(tmp32 & 0xff); tmp32 >>= 8; out[2] = (uuid_uint8_t)(tmp32 & 0xff); tmp32 >>= 8; out[1] = (uuid_uint8_t)(tmp32 & 0xff); tmp32 >>= 8; out[0] = (uuid_uint8_t)(tmp32 & 0xff); /* pack "time_mid" field */ tmp16 = uuid->time_mid; out[5] = (uuid_uint8_t)(tmp16 & 0xff); tmp16 >>= 8; out[4] = (uuid_uint8_t)(tmp16 & 0xff); /* pack "time_hi_and_version" field */ tmp16 = uuid->time_hi_and_version; out[7] = (uuid_uint8_t)(tmp16 & 0xff); tmp16 >>= 8; out[6] = (uuid_uint8_t)(tmp16 & 0xff); /* pack "clock_seq_hi_and_reserved" field */ out[8] = uuid->clock_seq_hi_and_reserved; /* pack "clock_seq_low" field */ out[9] = uuid->clock_seq_low; /* pack "node" field */ for (i = 0; i < sizeof(uuid->node); i++) out[10+i] = uuid->node[i]; return UUID_RC_OK; } uuid_rc_t uuid_parse(uuid_t *uuid, const char *str) { uuid_t uuid_tmp; uuid_uint16_t tmp16; const char *cp; char hexbuf[3]; int i; /* sanity check argument(s) */ if (uuid == NULL || str == NULL) return UUID_RC_ARG; /* * pass 1: check UUID string representation syntax * example reference: * f81d4fae-7dec-11d0-a765-00a0c91e6bf6 * 012345678901234567890123456789012345 * 0 1 2 3 */ if (strlen(str) != UUID_LEN_STR) return UUID_RC_ARG; for (i = 0, cp = str; i <= UUID_LEN_STR; i++, cp++) { if ((i == 8) || (i == 13) || (i == 18) || (i == 23)) { if (*cp == '-') continue; else return -1; } if (i == UUID_LEN_STR) if (*cp == '\0') continue; if (!isxdigit(*cp)) return UUID_RC_ARG; } /* * pass 2: parse hex values of string representation syntax */ uuid_tmp.time_low = (uuid_uint32_t)strtoul(str, NULL, 16); uuid_tmp.time_mid = (uuid_uint16_t)strtoul(str+9, NULL, 16); uuid_tmp.time_hi_and_version = (uuid_uint16_t)strtoul(str+14, NULL, 16); tmp16 = (uuid_uint16_t)strtoul(str+19, NULL, 16); uuid_tmp.clock_seq_low = (uuid_uint8_t)(tmp16 & 0xff); tmp16 >>= 8; uuid_tmp.clock_seq_hi_and_reserved = (uuid_uint8_t)(tmp16 & 0xff); cp = str+24; hexbuf[2] = '\0'; for (i = 0; i < sizeof(uuid_tmp.node); i++) { hexbuf[0] = *cp++; hexbuf[1] = *cp++; uuid_tmp.node[i] = strtoul(hexbuf, NULL, 16); } return UUID_RC_OK; } uuid_rc_t uuid_format(uuid_t *uuid, char **str) { uuid_t uuid_tmp; /* sanity check argument(s) */ if (uuid == NULL || str == NULL) return UUID_RC_ARG; /* optionally allocate string buffer */ if (*str == NULL) if ((*str = (char *)malloc(UUID_LEN_STR+1)) == NULL) return UUID_RC_MEM; /* format UUID into string representation */ sprintf(*str, "%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", (unsigned long)uuid_tmp.time_low, (unsigned int)uuid_tmp.time_mid, (unsigned int)uuid_tmp.time_hi_and_version, (unsigned int)uuid_tmp.clock_seq_hi_and_reserved, (unsigned int)uuid_tmp.clock_seq_low, (unsigned int)uuid_tmp.node[0], (unsigned int)uuid_tmp.node[1], (unsigned int)uuid_tmp.node[2], (unsigned int)uuid_tmp.node[3], (unsigned int)uuid_tmp.node[4], (unsigned int)uuid_tmp.node[5]); return UUID_RC_OK; } uuid_rc_t uuid_generate(uuid_t *uuid, unsigned int mode, ...) { va_list ap; /* sanity check argument(s) */ if (uuid == NULL) return UUID_RC_ARG; va_start(ap, mode); /* FIXME */ va_end(ap); return UUID_RC_OK; } uuid_rc_t uuid_dump(uuid_t *uuid, char **str) { /* sanity check argument(s) */ if (uuid == NULL || str == NULL) return UUID_RC_ARG; /* FIXME */ return UUID_RC_OK; } char *uuid_error(uuid_rc_t rc) { char *str; switch (rc) { case UUID_RC_OK: str = "everything ok"; break; case UUID_RC_ARG: str = "invalid argument"; break; case UUID_RC_MEM: str = "out of memory"; break; case UUID_RC_SYS: str = "system error"; break; default: str = NULL; break; } return str; }