ossp-pkg/uuid/uuid.c
1.6
/*
** 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.c: library API implementation
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>
#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_unparse(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;
}