天天看點

一個UUID生成算法的C語言實作 --- WIN32版本 .

一個UUID生成算法的C語言實作——WIN32版本

cheungmine

2007-9-16

根據定義,UUID(Universally Unique IDentifier,也稱GUID)在時間和空間都是唯一的。為保證空間的唯一性,每個UUID使用了一個48位的值來記錄,一般是計算機的網卡位址。為保證時間上的唯一性,每個UUID具有一個60位的時間戳(timestamp)。這個時間戳表示自公元1582年(絕對不是1852,這是《COM技術内幕》,1999年3月第1版第89頁中的一個錯誤)10月15号00:00:00:00以來的時間,是以100納秒為機關的時間間隔。1納秒(ns)=10-9秒(s)。UUID算法可以保證至大約公元3400年仍然唯一。UUID的C語言結構定義如下:

typedef struct _uuid_t

{

     unsigned long      data1;       

     unsigned short     data2;

     unsigned short     data3;

     unsigned char      data4[8];

} uuid_t;

它的結構大小為16個位元組。即sizeof(uuid_t)==16為TRUE。寫成16進制字元串的格式,一般為:

"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"

上面的字元串形式,占用36個字元,不包括結尾空字元’/0’。是以,要想容納一個UUID字元串,必須聲明為一個char[36+1]的字元數組。

以軟體算法實作UUID非常有現實意義。參考RFC4122文檔和其他一些開源代碼,我寫了一個WIN32下的UUID實作C語言程式——UUID32.c。程式符合RFC4122标準。程式不但實作建立UUID和UUID String,還可以對UUID進行字元和時間上的比較。還可以從UUID從提取時間戳(精度到秒)。頭檔案uuid32.h定義如下:

/* uuid32.h 

   2007-09-15 Last created by cheungmine.

   Partly rights reserved by cheungmine.

*/

#ifndef UUID32_H_INCLUDED

#define UUID32_H_INCLUDED

#include <stdlib.h>

#include <assert.h>

#include <string.h>

#include <memory.h>

#include "cdatatype.h"

typedef struct _timestamp_t

    BYTE    tm_sec;                /* Seconds after minute (0 – 59). */

    BYTE    tm_min;                /* Minutes after hour (0 – 59). */

    BYTE    tm_hour;            /* Hours after midnight (0 – 23). */

    BYTE    tm_mday;            /* Day of month (1 – 31). */

    BYTE    tm_mon;                /* Month (0 – 11; January = 0). */

    BYTE    tm_wday;            /* Day of week (0 – 6; Sunday = 0). */

    short    tm_year;            /* Year (current year minus 1900). */

    short    tm_yday;            /* Day of year (0 – 365; January 1 = 0). */

    long    tm_fraction;        /* Fraction little than 1 second */

} timestamp_t;

typedef struct _uuid_t

    unsigned long    data1;

    unsigned short    data2;

    unsigned short    data3;

    unsigned char    data4[8];

} uuid_t;

/**

 * Checks whether the given string matches the UUID format.

 *    params:

 *     [in] uuid - the potential UUID string

 *    return 

 *     TRUE if the given string is a UUID, FALSE otherwise

 **/

BOOL is_uuid_string(const char *uuid);

 * Generates a new UUID. The UUID is a time-based time 1 UUID.

 * A random per-process node identifier is used to avoid keeping global

 * state and maintaining inter-process synchronization.

void uuid_create(uuid_t* uuid);

 * Generates a new UUID string. The returned UUID is a time-based time 1 UUID.

 *  return UUID string (newly allocated)

char *uuid_create_string(void);

 * Generates a name-based (type 3) UUID string from the given external

 * identifier. The special namespace UUID is used as the namespace of

 * the generated UUID.

 *  params

 *     [in] external - the external identifier

 *  return 

 *     UUID string (newly allocated)

void uuid_create_external(const char *external, uuid_t* uuid);

 * Translate a uuid_t to a uuid string

 *  return UUID string

char *uuid_to_string(const uuid_t* uuid);

 * Get timestamp from a UUID

void uuid_to_timestamp(const uuid_t* uuid, timestamp_t* time);

 * Resurn a description of timestamp NOT including fraction

char* timestamp_to_string(const timestamp_t* time);

 * Compare two UUID's lexically

 *    return

 *      -1   u1 is lexically before u2

 *     0   u1 is equal to u2

 *     1   u1 is lexically after u2

int uuid_compare(const uuid_t *u1, const uuid_t *u2);

 * Compare two UUID's temporally

 *      -1   u1 is temporally before u2

 *     1   u1 is temporally after u2

int uuid_compare_time(const uuid_t *u1, const uuid_t *u2);

#endif        /* UUID32_H_INCLUDED */

       其中,頭檔案"cdatatype.h"如下:

/* cdatatype.h 

   2008-09-15 Last created by cheungmine.

   All rights reserved by cheungmine.

#ifndef CDATATYPE_H__

#define CDATATYPE_H__

/*============================================================================*/

typedef unsigned char uchar, byte, BYTE;

typedef unsigned short uint16, word_t, ushort;

typedef unsigned int uint, uint32, dword_t, size_t;

typedef unsigned long ulong;

typedef __int64 int64;

typedef unsigned __int64 uint64, qword_t;

#ifndef BOOL

    #define BOOL  int

    #define TRUE  1

    #define FALSE 0

#endif

#ifndef RESULT

    #define RESULT  long

    #define SUCCESS        0

    #define ERROR        -1

#define SIZE_BYTE    1

#define SIZE_SHORT    2

#define SIZE_INT    4

#define SIZE_FLT    4

#define SIZE_DBL    8

#define SIZE_WORD    2

#define SIZE_DWORD    4

#define SIZE_QWORD    8

#define SIZE_LINT    8

#define SIZE_INT64    8

#define SIZE_UUID    16

#endif    /*CDATATYPE_H__*/

           MD5算法生成的檔案有:md5.h和md5.c,分别羅列如下:

#ifndef _MD5_H__

#define _MD5_H__

/* MD5.H - header file for MD5C.C */

/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All

   rights reserved.

   License to copy and use this software is granted provided that it

   is identified as the "RSA Data Security, Inc. MD5 Message-Digest

   Algorithm" in all material mentioning or referencing this software

   or this function.

   License is also granted to make and use derivative works provided

   that such works are identified as "derived from the RSA Data

   Security, Inc. MD5 Message-Digest Algorithm" in all material

   mentioning or referencing the derived work.

   RSA Data Security, Inc. makes no representations concerning either

   the merchantability of this software or the suitability of this

   software for any particular purpose. It is provided "as is"

   without express or implied warranty of any kind.

   These notices must be retained in any copies of any part of this

   documentation and/or software.

   2007-09-15 Last modified by cheungmine.

 */

/* MD5 context. */

typedef struct {

    unsigned int state[4];                /* state (ABCD) */

    unsigned int count[2];                /* number of bits, modulo 2^64 (lsb first) */

    unsigned char buffer[64];    /* input buffer */

} MD5_CTX;

void  MD5_init (MD5_CTX *);

void  MD5_update (MD5_CTX *, const unsigned char *str, unsigned int len);

void  MD5_fini (unsigned char[16], MD5_CTX *);

char* MD5_sign (const unsigned char *str, unsigned int len);

#endif    /* _MD5_H__ */

/* 

 * md5.c - Copyright 1997 Lachlan Roche 

 *       - Modified by cheungmine, 2007-9-15

#include <stdio.h>

#include "md5.h"

#define MD5STR_LEN        32    

/*=====================================================================

   The remaining code is the reference MD5 code (md5c.c) from rfc1321

   MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm

   Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All

=====================================================================*/

/* Constants for _MD5Transform routine. */

#define S11 7

#define S12 12

#define S13 17

#define S14 22

#define S21 5

#define S22 9

#define S23 14

#define S24 20

#define S31 4

#define S32 11

#define S33 16

#define S34 23

#define S41 6

#define S42 10

#define S43 15

#define S44 21

static void _MD5Transform(unsigned int[4], const unsigned char[64]);

static void _Encode(unsigned char *, unsigned int *, unsigned int);

static void _Decode(unsigned int *, const unsigned char *, unsigned int);

static unsigned char PADDING[64] = {

    0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,

    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,

    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0

};

/* F, G, H and I are basic MD5 functions. */

#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))

#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))

#define H(x, y, z) ((x) ^ (y) ^ (z))

#define I(x, y, z) ((y) ^ ((x) | (~z)))

/* ROTATE_LEFT rotates x left n bits. */

#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))

/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.

   Rotation is separate from addition to prevent recomputation. */

#define FF(a, b, c, d, x, s, ac) { 

 (a) += F ((b), (c), (d)) + (x) + (unsigned int)(ac); 

 (a) = ROTATE_LEFT ((a), (s)); 

 (a) += (b); 

  }

#define GG(a, b, c, d, x, s, ac) { 

 (a) += G ((b), (c), (d)) + (x) + (unsigned int)(ac); 

#define HH(a, b, c, d, x, s, ac) { 

 (a) += H ((b), (c), (d)) + (x) + (unsigned int)(ac); 

#define II(a, b, c, d, x, s, ac) { 

 (a) += I ((b), (c), (d)) + (x) + (unsigned int)(ac); 

/* MD5 initialization. Begins an MD5 operation, writing a new context. */

void MD5_init(MD5_CTX * context)

    context->count[0] = context->count[1] = 0;

    /* Load magic initialization constants. */

    context->state[0] = 0x67452301;

    context->state[1] = 0xefcdab89;

    context->state[2] = 0x98badcfe;

    context->state[3] = 0x10325476;

}

/* MD5 block update operation. Continues an MD5 message-digest operation, 

   processing another message block, and updating the context. */

void MD5_update(MD5_CTX * context, const unsigned char *input, unsigned int inputLen)

    unsigned int i, index, partLen;

    /* Compute number of bytes mod 64 */

    index = (unsigned int) ((context->count[0] >> 3) & 0x3F);

    /* Update number of bits */

    if ((context->count[0] += ((unsigned int) inputLen << 3)) < ((unsigned int) inputLen << 3))

        context->count[1]++;

    context->count[1] += ((unsigned int) inputLen >> 29);

    partLen = 64 - index;

    /* Transform as many times as possible. */

    if (inputLen >= partLen) {

        memcpy((void *) &context->buffer[index], (void *) input, partLen);

        _MD5Transform(context->state, context->buffer);

        for (i = partLen; i + 63 < inputLen; i += 64)

            _MD5Transform(context->state, &input[i]);

        index = 0;

    }

    else

        i = 0;

    /* Buffer remaining input */

    memcpy((void *) &context->buffer[index], (void *) &input[i], inputLen - i);

/* MD5 finalization. Ends an MD5 message-digest operation, writing the message digest and zeroizing the context. */

void MD5_fini(unsigned char digest[16], MD5_CTX * context)

    unsigned char bits[8];

    unsigned int index, padLen;

    /* Save number of bits */

    _Encode(bits, context->count, 8);

    /* Pad out to 56 mod 64. */

    index = (unsigned int) ((context->count[0] >> 3) & 0x3f);

    padLen = (index < 56) ? (56 - index) : (120 - index);

    MD5_update(context, PADDING, padLen);

    /* Append length (before padding) */

    MD5_update(context, bits, 8);

    /* Store state in digest */

    _Encode(digest, context->state, 16);

    /* Zeroize sensitive information.*/

    memset((void *) context, 0, sizeof (*context));

#pragma warning(push)    /* C4996 */

#pragma warning( disable : 4996 )

char* MD5_sign (const unsigned char *str, unsigned int len)

    int i;

    MD5_CTX     md5;

    static char md5_str[MD5STR_LEN+1];

    char hash[16], tmp[3];

    md5_str[0] = 0;

    MD5_init(&md5);

    MD5_update (&md5, str, len);

    MD5_fini (hash, &md5);

    for ( i = 0 ; i < 16 ; i++ )

    {

        _itoa((unsigned char)hash[i], tmp , 16);

        if (tmp[1] == 0){

            tmp[2]=0;    tmp[1]=tmp[0]; tmp[0]='0';

        }

        strcat(md5_str, tmp);

    return md5_str;

#pragma warning(pop)    /* C4996 */

/* MD5 basic transformation. Transforms state based on block. */

static void _MD5Transform(unsigned int state[4], const unsigned char block[64])

    unsigned int a = state[0], 

                 b = state[1], 

                 c = state[2], 

                 d = state[3], 

                 x[16];

    _Decode(x, block, 64);

    /* Round 1 */

    FF(a, b, c, d, x[0], S11, 0xd76aa478);    /* 1 */

    FF(d, a, b, c, x[1], S12, 0xe8c7b756);    /* 2 */

    FF(c, d, a, b, x[2], S13, 0x242070db);    /* 3 */

    FF(b, c, d, a, x[3], S14, 0xc1bdceee);    /* 4 */

    FF(a, b, c, d, x[4], S11, 0xf57c0faf);    /* 5 */

    FF(d, a, b, c, x[5], S12, 0x4787c62a);    /* 6 */

    FF(c, d, a, b, x[6], S13, 0xa8304613);    /* 7 */

    FF(b, c, d, a, x[7], S14, 0xfd469501);    /* 8 */

    FF(a, b, c, d, x[8], S11, 0x698098d8);    /* 9 */

    FF(d, a, b, c, x[9], S12, 0x8b44f7af);    /* 10 */

    FF(c, d, a, b, x[10], S13, 0xffff5bb1);    /* 11 */

    FF(b, c, d, a, x[11], S14, 0x895cd7be);    /* 12 */

    FF(a, b, c, d, x[12], S11, 0x6b901122);    /* 13 */

    FF(d, a, b, c, x[13], S12, 0xfd987193);    /* 14 */

    FF(c, d, a, b, x[14], S13, 0xa679438e);    /* 15 */

    FF(b, c, d, a, x[15], S14, 0x49b40821);    /* 16 */

    /* Round 2 */

    GG(a, b, c, d, x[1], S21, 0xf61e2562);    /* 17 */

    GG(d, a, b, c, x[6], S22, 0xc040b340);    /* 18 */

    GG(c, d, a, b, x[11], S23, 0x265e5a51);    /* 19 */

    GG(b, c, d, a, x[0], S24, 0xe9b6c7aa);    /* 20 */

    GG(a, b, c, d, x[5], S21, 0xd62f105d);    /* 21 */

    GG(d, a, b, c, x[10], S22, 0x2441453);    /* 22 */

    GG(c, d, a, b, x[15], S23, 0xd8a1e681);    /* 23 */

    GG(b, c, d, a, x[4], S24, 0xe7d3fbc8);    /* 24 */

    GG(a, b, c, d, x[9], S21, 0x21e1cde6);    /* 25 */

    GG(d, a, b, c, x[14], S22, 0xc33707d6);    /* 26 */

    GG(c, d, a, b, x[3], S23, 0xf4d50d87);    /* 27 */

    GG(b, c, d, a, x[8], S24, 0x455a14ed);    /* 28 */

    GG(a, b, c, d, x[13], S21, 0xa9e3e905);    /* 29 */

    GG(d, a, b, c, x[2], S22, 0xfcefa3f8);    /* 30 */

    GG(c, d, a, b, x[7], S23, 0x676f02d9);    /* 31 */

    GG(b, c, d, a, x[12], S24, 0x8d2a4c8a);    /* 32 */

    /* Round 3 */

    HH(a, b, c, d, x[5], S31, 0xfffa3942);    /* 33 */

    HH(d, a, b, c, x[8], S32, 0x8771f681);    /* 34 */

    HH(c, d, a, b, x[11], S33, 0x6d9d6122);    /* 35 */

    HH(b, c, d, a, x[14], S34, 0xfde5380c);    /* 36 */

    HH(a, b, c, d, x[1], S31, 0xa4beea44);    /* 37 */

    HH(d, a, b, c, x[4], S32, 0x4bdecfa9);    /* 38 */

    HH(c, d, a, b, x[7], S33, 0xf6bb4b60);    /* 39 */

    HH(b, c, d, a, x[10], S34, 0xbebfbc70);    /* 40 */

    HH(a, b, c, d, x[13], S31, 0x289b7ec6);    /* 41 */

    HH(d, a, b, c, x[0], S32, 0xeaa127fa);    /* 42 */

    HH(c, d, a, b, x[3], S33, 0xd4ef3085);    /* 43 */

    HH(b, c, d, a, x[6], S34, 0x4881d05);    /* 44 */

    HH(a, b, c, d, x[9], S31, 0xd9d4d039);    /* 45 */

    HH(d, a, b, c, x[12], S32, 0xe6db99e5);    /* 46 */

    HH(c, d, a, b, x[15], S33, 0x1fa27cf8);    /* 47 */

    HH(b, c, d, a, x[2], S34, 0xc4ac5665);    /* 48 */

    /* Round 4 */

    II(a, b, c, d, x[0], S41, 0xf4292244);    /* 49 */

    II(d, a, b, c, x[7], S42, 0x432aff97);    /* 50 */

    II(c, d, a, b, x[14], S43, 0xab9423a7);    /* 51 */

    II(b, c, d, a, x[5], S44, 0xfc93a039);    /* 52 */

    II(a, b, c, d, x[12], S41, 0x655b59c3);    /* 53 */

    II(d, a, b, c, x[3], S42, 0x8f0ccc92);    /* 54 */

    II(c, d, a, b, x[10], S43, 0xffeff47d);    /* 55 */

    II(b, c, d, a, x[1], S44, 0x85845dd1);    /* 56 */

    II(a, b, c, d, x[8], S41, 0x6fa87e4f);    /* 57 */

    II(d, a, b, c, x[15], S42, 0xfe2ce6e0);    /* 58 */

    II(c, d, a, b, x[6], S43, 0xa3014314);    /* 59 */

    II(b, c, d, a, x[13], S44, 0x4e0811a1);    /* 60 */

    II(a, b, c, d, x[4], S41, 0xf7537e82);    /* 61 */

    II(d, a, b, c, x[11], S42, 0xbd3af235);    /* 62 */

    II(c, d, a, b, x[2], S43, 0x2ad7d2bb);    /* 63 */

    II(b, c, d, a, x[9], S44, 0xeb86d391);    /* 64 */

    state[0] += a;

    state[1] += b;

    state[2] += c;

    state[3] += d;

    /* Zeroize sensitive information. */

    memset((void *) x, 0, sizeof (x));

/* Encodes input (unsigned int) into output (unsigned char). Assumes len is a multiple of 4. */

static void _Encode(unsigned char *output, unsigned int *input, unsigned int len)

    unsigned int i, j;

    for (i = 0, j = 0; j < len; i++, j += 4) {

        output[j] = (unsigned char) (input[i] & 0xff);

        output[j + 1] = (unsigned char) ((input[i] >> 8) & 0xff);

        output[j + 2] = (unsigned char) ((input[i] >> 16) & 0xff);

        output[j + 3] = (unsigned char) ((input[i] >> 24) & 0xff);

/* Decodes input (unsigned char) into output (unsigned int). Assumes len is a multiple of 4.*/

static void _Decode(unsigned int *output, const unsigned char *input, unsigned int len)

        output[i] = ((unsigned int) input[j]) | (((unsigned int) input[j + 1]) << 8) |

                    (((unsigned int) input[j + 2]) << 16) | (((unsigned int) input[j + 3]) << 24);

        uuid32.c檔案如下:

/* uuid32.c 

#include <time.h>

#include <sys/types.h>

#include <sys/timeb.h>

#include "uuid32.h"

#define MD5_LEN            16

#define UUID_LEN        36

/* microsecond per second. 1s=1000000us=1000000000ns*/

#define NSec100_Per_Sec        10000000

#define USec_Per_Sec        1000000

#define USec_Per_MSec        1000

#define NSec_Since_1582        ((uint64)(0x01B21DD213814000))

/*========================================================================================

                            Private Functions

========================================================================================*/

static BOOL isbigendian()

    int c = 1;

    return ( *((unsigned char *) &c) == 1 )? FALSE: TRUE;

static void swap_word( int size_bytes, void * ptr_word )

    int        i;

    unsigned char       temp;

    for( i=0; i < size_bytes/2; i++ )

        temp = ((unsigned char *) ptr_word)[i];

        ((unsigned char *) ptr_word)[i] = ((unsigned char *) ptr_word)[size_bytes-i-1];

        ((unsigned char *) ptr_word)[size_bytes-i-1] = temp;

static void write_word( unsigned char* stream, word_t val )

    memcpy(stream, &val, 2);

    if( isbigendian() ) swap_word( 2, stream );

static void write_dword( unsigned char* stream, dword_t val )

    memcpy(stream, &val, 4);

    if( isbigendian() ) swap_word( 4, stream );

static void  read_word( const unsigned char* stream, word_t* val )

    memcpy( val, stream, 2 );

    if( isbigendian() )    swap_word( 2, val );

static void  read_dword( const unsigned char* stream, dword_t* val )

    memcpy( val, stream, 4 );

    if( isbigendian() )    swap_word( 4, val );

static BOOL is_xdigit(char c)

    /* isxdigit returns a non-zero value if c is a hexadecimal digit (A – F, a – f, or 0 – 9). */

    return ((c>='A'&&c<='F')||(c>='a'&&c<='f')||(c>='0'&&c<='9'))? TRUE : FALSE;

/* make a pseudorandom numbel based on current time*/

static int pseudo_rand()

#ifdef _USE_32BIT_TIME_T

    assert(0);

    struct _timeb  timebuf;

    _ftime64(&timebuf);

    srand((uint32) ((((uint32)timebuf.time&0xFFFF)+(uint32)timebuf.millitm)^(uint32)timebuf.millitm));

    return rand();

                            Public Functions

BOOL is_uuid_string(const char *uuid) 

{    

    static const char fmt[] = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";

    assert(uuid != NULL);

    for (i = 0; i < sizeof(fmt); i++)

        if (fmt[i] == 'x')

            if (!is_xdigit(uuid[i]))

                return FALSE;

        else if (uuid[i] != fmt[i])

            return FALSE;

    return TRUE;

 * internal

 * ingroup uuid

 * The thread synchronization lock used to guarantee UUID uniqueness

 * for all the threads running within a process.

void uuid_create(uuid_t* u) 

    static BOOL        initialized = FALSE;

    static int64    timestamp;

    static uint32    advance;

    static uint16    clockseq;

    static uint16    node_high;

    static uint32    node_low;

    int64            time;    /* unit of 100ns */

    uint16            nowseq;

    int                r;

    #ifdef _USE_32BIT_TIME_T

        assert(0);

    #endif

    struct _timeb  tv;

    assert(u);

    _ftime64(&tv);

    /* time is counter of 100ns time interval since Oct.15, 1582 (NOT 1852) */

    time = ((uint64) tv.time) * USec_Per_Sec + ((uint64) tv.millitm*USec_Per_MSec);

    time = time * 10 + NSec_Since_1582;

    if (!initialized) 

        timestamp = time;

        advance = 0;

        r = pseudo_rand();

        clockseq = r >> 16;

        node_high = r | 0x0100;

        node_low = pseudo_rand();

        initialized = TRUE;

    } 

    else if (time < timestamp) 

        clockseq++;

    else if (time == timestamp) 

        advance++;

        time += advance;

    else 

    nowseq = clockseq;

    u->data1 = (dword_t) time;

    u->data2 = (word_t) ((time >> 32) & 0xffff);

    u->data3 = (word_t) (((time >> 48) & 0x0ffff) | 0x1000);

    write_word(&(u->data4[6]), (word_t) ((nowseq & 0x3fff) | 0x8000));    

    write_word(&(u->data4[4]), (word_t) (node_high));                    

    write_dword(&(u->data4[0]), (dword_t) (node_low));            

char *uuid_create_string(void) 

    uuid_t  u;

    uuid_create(&u);

    return uuid_to_string(&u);

char *uuid_to_string(const uuid_t*  u)

    static char uuid_str[UUID_LEN+1];

    ushort a,b;

    uint32  c;

    read_word(&(u->data4[6]), &a);

    read_word(&(u->data4[4]), &b);

    read_dword(&(u->data4[0]), &c);

    sprintf(uuid_str, "%08lx-%04x-%04x-%04x-%04x%08lx", 

                u->data1,

                u->data2,

                u->data3,

                a, b, c);

    return uuid_str;

 * The predefined namespace UUID. Expressed in binary format

 * to avoid unnecessary conversion when generating name based UUIDs.

static const unsigned char namespace_uuid[] = {

        0x9c, 0xfb, 0xd9, 0x1f, 0x11, 0x72, 0x4a, 0xf6,

        0xbd, 0xcb, 0x9f, 0x34, 0xe4, 0x6f, 0xa0, 0xfb

void  uuid_create_external(const char *external, uuid_t* u) 

    MD5_CTX md5;

    unsigned char uuid[16];    

    assert(external != NULL);

    MD5_update(&md5, namespace_uuid, sizeof(namespace_uuid));

    MD5_update(&md5, (unsigned char *) external, (unsigned int) strlen(external));

    MD5_fini(uuid, &md5);

    u->data1 = (dword_t) (uuid[0] << 24 | uuid[1] << 16 | uuid[2] << 8 | uuid[3]);

    u->data2 = (word_t)  (uuid[4] << 8 | uuid[5]);

    u->data3 = (word_t)  (((uuid[6] & 0x0f) | 0x30) << 8 | uuid[7]);    

    /* BYTE 6-7 */

    write_word(&(u->data4[6]), (word_t) (((uuid[8] & 0x3f) | 0x80) << 8 | uuid[9]));        

    /* BYTE 4-5 */

    write_word(&(u->data4[4]), (word_t) (uuid[10] << 8 | uuid[11]));                        

    /* BYTE 0-3 */

    write_dword(&(u->data4[0]), (dword_t) (uuid[12] << 24 | uuid[13] << 16 | uuid[14] << 8 | uuid[15]));

void uuid_to_timestamp(const uuid_t* u, timestamp_t* t)

    int64   time, t2, t3;

    struct  tm*  p;

    t2 = u->data2;

    t3 = u->data3;

    time = u->data1 + (t2<<32) + ((t3&0x0fff)<<48);        /* 100ns */

    time -= NSec_Since_1582;

    t->tm_fraction = (long)(time%NSec100_Per_Sec);

    time /= 10;

    time /= USec_Per_Sec; 

    p = _localtime64(&time);

    t->tm_hour = p->tm_hour;

    t->tm_mday = p->tm_mday;

    t->tm_min = p->tm_min;

    t->tm_mon = p->tm_mon;

    t->tm_sec = p->tm_sec;

    t->tm_wday = p->tm_wday;

    t->tm_yday = p->tm_yday;

    t->tm_year = p->tm_year;

char* timestamp_to_string(const timestamp_t* time)

    struct tm t;

    t.tm_hour = time->tm_hour;

    t.tm_mday = time->tm_mday;

    t.tm_min = time->tm_min;

    t.tm_mon = time->tm_mon;

    t.tm_sec = time->tm_sec;

    t.tm_wday = time->tm_wday;

    t.tm_yday = time->tm_yday;

    t.tm_year = time->tm_year;

    return asctime(&t);

int uuid_compare(const uuid_t *u1, const uuid_t *u2)

#define CHECK_COMP(f1, f2)  if ((f1) != (f2)) return ((f1) < (f2) ? -1 : 1);

    CHECK_COMP(u1->data1, u2->data1);

    CHECK_COMP(u1->data2, u2->data2);

    CHECK_COMP(u1->data3, u2->data3);

    for(i=0; i<8; i++)

        CHECK_COMP(u1->data4[i], u1->data4[i]);

#undef CHECK_COMP

    return 0;

int uuid_compare_time(const uuid_t *u1, const uuid_t *u2)

      好了,到此,所有檔案都列出來了,它們是:cdatatype.h、md5.h、uuid32.h、md5.c和uuid32.c。

最後是測試代碼:

/* uuidgen.c 

   C application

int main()

    char *sign, *uid;

    uuid_t u, v, x;

    timestamp_t  t;

    sign = MD5_sign("hello world", (unsigned int)strlen("hello world"));

    printf("md5 string digit:%s ", sign);

    uid = uuid_to_string(&u);

    printf("uuid U to string:{%s} ", uid);

    uuid_create(&v);

    uid = uuid_to_string(&v);

    printf("uuid V to string:{%s} ", uid);

    printf("uuid compare U with V lexically:%d ", uuid_compare(&u, &v));

    printf("uuid compare V with U temporally:%d ", uuid_compare_time(&v, &u));

    uid = uuid_create_string();

    printf("new uuid string:{%s} ", uid);

    uuid_create_external("cheungmine", &x);

    uid = uuid_to_string(&x);

    printf("new external uuid to string:{%s} ", uid);

    uuid_to_timestamp(&u, &t);

    printf("%s ", timestamp_to_string(&t));

          以上代碼保證正确。請放心使用!

繼續閱讀