/*
 * $Header: /san01/cvs/ashpool/csrc/continuity/mecha/Attic/uid.c,v 1.9 2004/04/30 13:41:56 aleigh Exp $ 
 */

/*
 * Copyright (c) 1994, 2004 Alex Leigh, All Rights Reserved
 * 
 * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright
 * notice above does not evidence any actual or intended publication of such
 * source code.
 * 
 * Use, disclosure, copying, distribution, or transmission of of this code without
 * express permission is prohibited.
 */

typedef unsigned char uuidTpack[16];

#include <string.h>

#include "mecha.h"

struct uuidSid {
    uint32_t time_low;
    uint16_t time_mid;
    uint16_t time_hi_and_version;
    uint16_t clock_seq;
    uint8_t node[6];
};
typedef struct uuidSid uuidTid;

static void uuidFpack(uuidTid * uu, uuidTpack * ptr);
static void uuidFgenerate(uuidTpack * out);
static void uuidFunpack(uuidTpack * in, uuidTid * uu);
static void uuidFunparse(uuidTpack * uu, char *out);

static void uuidFunpack(uuidTpack * in, uuidTid * uu)
{
    uint8_t *ptr = (uint8_t *) in;
    uint32_t tmp;

    tmp = *ptr++;
    tmp = (tmp << 8) | *ptr++;
    tmp = (tmp << 8) | *ptr++;
    tmp = (tmp << 8) | *ptr++;
    uu->time_low = tmp;

    tmp = *ptr++;
    tmp = (tmp << 8) | *ptr++;
    uu->time_mid = tmp;

    tmp = *ptr++;
    tmp = (tmp << 8) | *ptr++;
    uu->time_hi_and_version = tmp;

    tmp = *ptr++;
    tmp = (tmp << 8) | *ptr++;
    uu->clock_seq = tmp;

    memcpy(uu->node, ptr, 6);
}

static void uuidFunparse(uuidTpack * uu, char *out)
{
    uuidTid uuid;

    uuidFunpack(uu, &uuid);
    sprintf(out,
            "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
            uuid.time_low, uuid.time_mid, uuid.time_hi_and_version,
            uuid.clock_seq >> 8, uuid.clock_seq & 0xFF,
            uuid.node[0], uuid.node[1], uuid.node[2],
            uuid.node[3], uuid.node[4], uuid.node[5]);
}

static void uuidFpack(uuidTid * uu, uuidTpack * ptr)
{
    uint32_t tmp;
    unsigned char *out = (unsigned char *) ptr;

    tmp = uu->time_low;
    out[3] = (unsigned char) tmp;
    tmp >>= 8;
    out[2] = (unsigned char) tmp;
    tmp >>= 8;
    out[1] = (unsigned char) tmp;
    tmp >>= 8;
    out[0] = (unsigned char) tmp;

    tmp = uu->time_mid;
    out[5] = (unsigned char) tmp;
    tmp >>= 8;
    out[4] = (unsigned char) tmp;

    tmp = uu->time_hi_and_version;
    out[7] = (unsigned char) tmp;
    tmp >>= 8;
    out[6] = (unsigned char) tmp;

    tmp = uu->clock_seq;
    out[9] = (unsigned char) tmp;
    tmp >>= 8;
    out[8] = (unsigned char) tmp;

    memcpy(out + 10, uu->node, 6);
}

/*
 * generates a UUID based on the current time on the platform.
 */
static void uuidFgenerate(uuidTpack * out)
{
    static unsigned char node_id[6];
    uuidTid uu;
    uint32_t clock_mid;
    uint32_t node_number;

    if ((node_number = utlFgethostid()) == 0) {
        rndFrandom_bytes(node_id, 6);
        /*
         * Set multicast bit, to prevent conflicts with IEEE 802 addresses
         * obtained from network cards
         */
        node_id[0] |= 0x80;
    } else {
        memcpy(node_id, (char *) &node_number, 4);
    }

    utlFclock_get(&clock_mid, &uu.time_low, &uu.clock_seq);
    uu.clock_seq |= 0x8000;
    uu.time_mid = (uint16_t) clock_mid;
    uu.time_hi_and_version = (clock_mid >> 16) | 0x1000;
    memcpy(uu.node, node_id, 6);
    uuidFpack(&uu, out);
}

/* Generate a uuid, and write it into the provided buffer. */

int uidFgenerate_str(char *id, size_t len)
{
    uuidTpack uuid;

    if (len < 37)
        return -1;

    memFclear(&uuid, sizeof(uuidTpack));
    uuidFgenerate(&uuid);
    uuidFunparse(&uuid, id);

    return 0;
}
