Blame UUID.xs

Packit Service 7500fa
#include "EXTERN.h"
Packit Service 7500fa
#include "perl.h"
Packit Service 7500fa
#include "XSUB.h"
Packit Service 7500fa
#include "UUID.h"
Packit Service 7500fa
Packit Service 7500fa
#if defined __BEOS__ || defined __HAIKU__
Packit Service 7500fa
#  undef bool
Packit Service 7500fa
#  include <OS.h>
Packit Service 7500fa
#endif
Packit Service 7500fa
Packit Service 7500fa
#ifdef USE_ITHREADS
Packit Service 7500fa
# define DU_THREADSAFE 1
Packit Service 7500fa
#else
Packit Service 7500fa
# define DU_THREADSAFE 0
Packit Service 7500fa
#endif
Packit Service 7500fa
Packit Service 7500fa
#if DU_THREADSAFE
Packit Service 7500fa
Packit Service 7500fa
# define pPTBL   pTHX
Packit Service 7500fa
# define pPTBL_  pTHX_
Packit Service 7500fa
# define aPTBL   aTHX
Packit Service 7500fa
# define aPTBL_  aTHX_
Packit Service 7500fa
Packit Service 7500fa
# define PTABLE_VAL_FREE(V) ((void) (V))
Packit Service 7500fa
Packit Service 7500fa
# include "ptable.h"
Packit Service 7500fa
Packit Service 7500fa
# define ptable_store(T, K, V)  ptable_store(aTHX_ (T), (K), (V))
Packit Service 7500fa
Packit Service 7500fa
static ptable *instances;
Packit Service 7500fa
static perl_mutex instances_mutex;
Packit Service 7500fa
Packit Service 7500fa
static void inc(pTHX_ ptable_ent *ent, void *ud) {
Packit Service 7500fa
    UV count = PTR2UV(ent->val);
Packit Service 7500fa
    PERL_UNUSED_VAR(ud);
Packit Service 7500fa
    ptable_store(instances, ent->key, (void *)++count);
Packit Service 7500fa
}
Packit Service 7500fa
Packit Service 7500fa
#endif
Packit Service 7500fa
Packit Service 7500fa
static  perl_uuid_t NameSpace_DNS = { /* 6ba7b810-9dad-11d1-80b4-00c04fd430c8 */
Packit Service 7500fa
   0x6ba7b810,
Packit Service 7500fa
   0x9dad,
Packit Service 7500fa
   0x11d1,
Packit Service 7500fa
   0x80, 0xb4, { 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8 }
Packit Service 7500fa
};
Packit Service 7500fa
Packit Service 7500fa
static  perl_uuid_t NameSpace_URL = { /* 6ba7b811-9dad-11d1-80b4-00c04fd430c8 */
Packit Service 7500fa
   0x6ba7b811,
Packit Service 7500fa
   0x9dad,
Packit Service 7500fa
   0x11d1,
Packit Service 7500fa
   0x80, 0xb4, { 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8 }
Packit Service 7500fa
};
Packit Service 7500fa
Packit Service 7500fa
static  perl_uuid_t NameSpace_OID = { /* 6ba7b812-9dad-11d1-80b4-00c04fd430c8 */
Packit Service 7500fa
   0x6ba7b812,
Packit Service 7500fa
   0x9dad,
Packit Service 7500fa
   0x11d1,
Packit Service 7500fa
   0x80, 0xb4, { 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8 }
Packit Service 7500fa
};
Packit Service 7500fa
Packit Service 7500fa
static  perl_uuid_t NameSpace_X500 = { /* 6ba7b814-9dad-11d1-80b4-00c04fd430c8 */
Packit Service 7500fa
   0x6ba7b814,
Packit Service 7500fa
   0x9dad,
Packit Service 7500fa
   0x11d1,
Packit Service 7500fa
   0x80, 0xb4, { 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8 }
Packit Service 7500fa
};
Packit Service 7500fa
Packit Service 7500fa
static void format_uuid_v1(
Packit Service 7500fa
   perl_uuid_t     *uuid, 
Packit Service 7500fa
   unsigned16  clock_seq, 
Packit Service 7500fa
   perl_uuid_time_t timestamp, 
Packit Service 7500fa
   uuid_node_t node
Packit Service 7500fa
) {
Packit Service 7500fa
   uuid->time_low = (unsigned long)(timestamp & 0xFFFFFFFF);
Packit Service 7500fa
   uuid->time_mid = (unsigned short)((timestamp >> 32) & 0xFFFF);
Packit Service 7500fa
   uuid->time_hi_and_version = (unsigned short)((timestamp >> 48) &
Packit Service 7500fa
      0x0FFF);
Packit Service 7500fa
Packit Service 7500fa
   uuid->time_hi_and_version |= (1 << 12);
Packit Service 7500fa
   uuid->clock_seq_low = clock_seq & 0xFF;
Packit Service 7500fa
   uuid->clock_seq_hi_and_reserved = (clock_seq & 0x3F00) >> 8;
Packit Service 7500fa
   uuid->clock_seq_hi_and_reserved |= 0x80;
Packit Service 7500fa
   memcpy(&uuid->node, &node, sizeof uuid->node);
Packit Service 7500fa
}
Packit Service 7500fa
Packit Service 7500fa
static void get_current_time(perl_uuid_time_t * timestamp) {
Packit Service 7500fa
   perl_uuid_time_t        time_now;
Packit Service 7500fa
   static perl_uuid_time_t time_last;
Packit Service 7500fa
   static unsigned16  uuids_this_tick;
Packit Service 7500fa
   static int         inited = 0;
Packit Service 7500fa
Packit Service 7500fa
   if (!inited) {
Packit Service 7500fa
      get_system_time(&time_last);
Packit Service 7500fa
      uuids_this_tick = UUIDS_PER_TICK;
Packit Service 7500fa
      inited = 1;
Packit Service 7500fa
   };
Packit Service 7500fa
   while (1) {
Packit Service 7500fa
      get_system_time(&time_now);
Packit Service 7500fa
Packit Service 7500fa
      if (time_last != time_now) {
Packit Service 7500fa
         uuids_this_tick = 0;
Packit Service 7500fa
         time_last = time_now;
Packit Service 7500fa
         break;
Packit Service 7500fa
      };
Packit Service 7500fa
      if (uuids_this_tick < UUIDS_PER_TICK) {
Packit Service 7500fa
         uuids_this_tick++;
Packit Service 7500fa
         break;
Packit Service 7500fa
      };
Packit Service 7500fa
   };
Packit Service 7500fa
   *timestamp = time_now + uuids_this_tick;
Packit Service 7500fa
}
Packit Service 7500fa
Packit Service 7500fa
static unsigned16 true_random(void) {
Packit Service 7500fa
   static int  inited = 0;
Packit Service 7500fa
   perl_uuid_time_t time_now;
Packit Service 7500fa
Packit Service 7500fa
   if (!inited) {
Packit Service 7500fa
      get_system_time(&time_now);
Packit Service 7500fa
      time_now = time_now/UUIDS_PER_TICK;
Packit Service 7500fa
      srand((unsigned int)(((time_now >> 32) ^ time_now)&0xffffffff));
Packit Service 7500fa
      inited = 1;
Packit Service 7500fa
    };
Packit Service 7500fa
    return (rand());
Packit Service 7500fa
}
Packit Service 7500fa
Packit Service 7500fa
static void format_uuid_v3(
Packit Service 7500fa
   perl_uuid_t        *uuid, 
Packit Service 7500fa
   unsigned char  hash[16]
Packit Service 7500fa
) {
Packit Service 7500fa
   memcpy(uuid, hash, sizeof(perl_uuid_t));
Packit Service 7500fa
Packit Service 7500fa
   uuid->time_low            = ntohl(uuid->time_low);
Packit Service 7500fa
   uuid->time_mid            = ntohs(uuid->time_mid);
Packit Service 7500fa
   uuid->time_hi_and_version = ntohs(uuid->time_hi_and_version);
Packit Service 7500fa
Packit Service 7500fa
   uuid->time_hi_and_version &= 0x0FFF;
Packit Service 7500fa
   uuid->time_hi_and_version |= (3 << 12);
Packit Service 7500fa
   uuid->clock_seq_hi_and_reserved &= 0x3F;
Packit Service 7500fa
   uuid->clock_seq_hi_and_reserved |= 0x80;
Packit Service 7500fa
}
Packit Service 7500fa
Packit Service 7500fa
static void get_system_time(perl_uuid_time_t *perl_uuid_time) {
Packit Service 7500fa
#if defined __cygwin__ || defined __MINGW32__ || defined WIN32
Packit Service 7500fa
   /* ULARGE_INTEGER time; */
Packit Service 7500fa
   LARGE_INTEGER time;
Packit Service 7500fa
Packit Service 7500fa
   /* use QeryPerformanceCounter for +ms resolution - as per Paul Stodghill 
Packit Service 7500fa
   GetSystemTimeAsFileTime((FILETIME *)&time); */
Packit Service 7500fa
   QueryPerformanceCounter(&time);
Packit Service 7500fa
   time.QuadPart +=
Packit Service 7500fa
      (unsigned __int64) (1000*1000*10) * 
Packit Service 7500fa
      (unsigned __int64) (60 * 60 * 24) * 
Packit Service 7500fa
      (unsigned __int64) (17+30+31+365*18+5);
Packit Service 7500fa
Packit Service 7500fa
   *perl_uuid_time = time.QuadPart;
Packit Service 7500fa
#else
Packit Service 7500fa
   struct timeval tp;
Packit Service 7500fa
Packit Service 7500fa
   gettimeofday(&tp, (struct timezone *)0);
Packit Service 7500fa
   *perl_uuid_time = (tp.tv_sec * I64(10000000)) + (tp.tv_usec * I64(10)) +
Packit Service 7500fa
      I64(0x01B21DD213814000);
Packit Service 7500fa
#endif
Packit Service 7500fa
}
Packit Service 7500fa
Packit Service 7500fa
static void get_random_info(unsigned char seed[16]) {
Packit Service 7500fa
   SV* ctx;
Packit Service 7500fa
#if defined __cygwin__ || defined __MINGW32__ || defined __MSWin32__
Packit Service 7500fa
   typedef struct {
Packit Service 7500fa
      MEMORYSTATUS  m;
Packit Service 7500fa
      SYSTEM_INFO   s;
Packit Service 7500fa
      FILETIME      t;
Packit Service 7500fa
      LARGE_INTEGER pc;
Packit Service 7500fa
      DWORD         tc;
Packit Service 7500fa
      DWORD         l;
Packit Service 7500fa
      char          hostname[MAX_COMPUTERNAME_LENGTH + 1];
Packit Service 7500fa
   } randomness;
Packit Service 7500fa
#else
Packit Service 7500fa
   typedef struct {
Packit Service 7500fa
#if defined __BEOS__ || defined __HAIKU__
Packit Service 7500fa
      system_info    sys_info;
Packit Service 7500fa
#else
Packit Service 7500fa
      long           hostid;
Packit Service 7500fa
#endif
Packit Service 7500fa
      struct timeval t;
Packit Service 7500fa
      char           hostname[257];
Packit Service 7500fa
   } randomness;
Packit Service 7500fa
#endif
Packit Service 7500fa
   randomness r;
Packit Service 7500fa
Packit Service 7500fa
#if defined __cygwin__ || defined __MINGW32__ || defined __MSWin32__
Packit Service 7500fa
   GlobalMemoryStatus(&r.m);
Packit Service 7500fa
   GetSystemInfo(&r.s);
Packit Service 7500fa
   GetSystemTimeAsFileTime(&r.t);
Packit Service 7500fa
   QueryPerformanceCounter(&r.pc);
Packit Service 7500fa
   r.tc = GetTickCount();
Packit Service 7500fa
   r.l = MAX_COMPUTERNAME_LENGTH + 1;
Packit Service 7500fa
   GetComputerName(r.hostname, &r.l );
Packit Service 7500fa
#else
Packit Service 7500fa
#  if defined __BEOS__ || defined __HAIKU__
Packit Service 7500fa
   get_system_info(&r.sys_info);
Packit Service 7500fa
#  elif !defined(__ANDROID__)
Packit Service 7500fa
   r.hostid = gethostid();
Packit Service 7500fa
#  endif
Packit Service 7500fa
   gettimeofday(&r.t, (struct timezone *)0);
Packit Service 7500fa
   gethostname(r.hostname, 256);
Packit Service 7500fa
#endif
Packit Service 7500fa
Packit Service 7500fa
   ctx = MD5Init();
Packit Service 7500fa
   MD5Update(ctx, sv_2mortal(newSVpv((char*)&r, sizeof(randomness))));
Packit Service 7500fa
   MD5Final(seed, ctx);
Packit Service 7500fa
}
Packit Service 7500fa
Packit Service 7500fa
static SV* make_ret(const perl_uuid_t u, int type) {
Packit Service 7500fa
   char                 buf[BUFSIZ];
Packit Service 7500fa
   const unsigned char *from;
Packit Service 7500fa
   unsigned char       *to;
Packit Service 7500fa
   STRLEN               len;
Packit Service 7500fa
   int                  i;
Packit Service 7500fa
Packit Service 7500fa
   memset(buf, 0x00, BUFSIZ);
Packit Service 7500fa
   switch(type) {
Packit Service 7500fa
   case F_BIN:
Packit Service 7500fa
      memcpy(buf, &u, sizeof(perl_uuid_t));
Packit Service 7500fa
      len = sizeof(perl_uuid_t);
Packit Service 7500fa
      break;
Packit Service 7500fa
   case F_STR:
Packit Service 7500fa
      sprintf(buf, "%8.8X-%4.4X-%4.4X-%2.2X%2.2X-", (unsigned int)u.time_low, u.time_mid,
Packit Service 7500fa
	 u.time_hi_and_version, u.clock_seq_hi_and_reserved, u.clock_seq_low);
Packit Service 7500fa
      for(i = 0; i < 6; i++ ) 
Packit Service 7500fa
	 sprintf(buf+strlen(buf), "%2.2X", u.node[i]);
Packit Service 7500fa
      len = strlen(buf);
Packit Service 7500fa
      break;
Packit Service 7500fa
   case F_HEX:
Packit Service 7500fa
      sprintf(buf, "0x%8.8X%4.4X%4.4X%2.2X%2.2X", (unsigned int)u.time_low, u.time_mid,
Packit Service 7500fa
	 u.time_hi_and_version, u.clock_seq_hi_and_reserved, u.clock_seq_low);
Packit Service 7500fa
      for(i = 0; i < 6; i++ ) 
Packit Service 7500fa
	 sprintf(buf+strlen(buf), "%2.2X", u.node[i]);
Packit Service 7500fa
      len = strlen(buf);
Packit Service 7500fa
      break;
Packit Service 7500fa
   case F_B64:
Packit Service 7500fa
      for(from = (const unsigned char*)&u, to = (unsigned char*)buf, i = sizeof(u); i > 0; i -= 3, from += 3) {
Packit Service 7500fa
         *to++ = base64[from[0]>>2];
Packit Service 7500fa
         switch(i) {
Packit Service 7500fa
	 case 1:
Packit Service 7500fa
	    *to++ = base64[(from[0]&0x03)<<4];
Packit Service 7500fa
	    *to++ = '=';
Packit Service 7500fa
	    *to++ = '=';
Packit Service 7500fa
	     break;
Packit Service 7500fa
         case 2:
Packit Service 7500fa
	    *to++ = base64[((from[0]&0x03)<<4) | ((from[1]&0xF0)>>4)];
Packit Service 7500fa
	    *to++ = base64[(from[1]&0x0F)<<2];
Packit Service 7500fa
	    *to++ = '=';
Packit Service 7500fa
	     break;
Packit Service 7500fa
         default:
Packit Service 7500fa
	    *to++ = base64[((from[0]&0x03)<<4) | ((from[1]&0xF0)>>4)];
Packit Service 7500fa
	    *to++ = base64[((from[1]&0x0F)<<2) | ((from[2]&0xC0)>>6)];
Packit Service 7500fa
	    *to++ = base64[(from[2]&0x3F)];
Packit Service 7500fa
         }
Packit Service 7500fa
      }	    
Packit Service 7500fa
      len = strlen(buf);
Packit Service 7500fa
      break;
Packit Service 7500fa
   default:
Packit Service 7500fa
      croak("invalid type: %d\n", type);
Packit Service 7500fa
      break;
Packit Service 7500fa
   }
Packit Service 7500fa
   return sv_2mortal(newSVpv(buf,len));
Packit Service 7500fa
}
Packit Service 7500fa
Packit Service 7500fa
static SV* MD5Init() {
Packit Service 7500fa
   SV* res;
Packit Service 7500fa
   int rcount;
Packit Service 7500fa
Packit Service 7500fa
   dSP;
Packit Service 7500fa
Packit Service 7500fa
   ENTER; SAVETMPS;
Packit Service 7500fa
Packit Service 7500fa
   PUSHMARK(SP);
Packit Service 7500fa
   XPUSHs(sv_2mortal(newSVpv("Digest::MD5", 0)));
Packit Service 7500fa
   PUTBACK;
Packit Service 7500fa
Packit Service 7500fa
   rcount = call_method("new", G_SCALAR);
Packit Service 7500fa
   SPAGAIN;
Packit Service 7500fa
Packit Service 7500fa
   if ( rcount != 1 )
Packit Service 7500fa
       croak("couldn't construct new Digest::MD5 object");
Packit Service 7500fa
Packit Service 7500fa
   res = newSVsv(POPs);
Packit Service 7500fa
Packit Service 7500fa
   PUTBACK;
Packit Service 7500fa
   FREETMPS;
Packit Service 7500fa
   LEAVE;
Packit Service 7500fa
Packit Service 7500fa
   return res;
Packit Service 7500fa
};
Packit Service 7500fa
Packit Service 7500fa
static void MD5Update( SV* ctx, SV* data ) {
Packit Service 7500fa
   dSP;
Packit Service 7500fa
   ENTER; SAVETMPS;
Packit Service 7500fa
Packit Service 7500fa
   PUSHMARK(SP);
Packit Service 7500fa
   XPUSHs(ctx);
Packit Service 7500fa
   XPUSHs(data);
Packit Service 7500fa
   PUTBACK;
Packit Service 7500fa
Packit Service 7500fa
   call_method("add", G_DISCARD);
Packit Service 7500fa
   SPAGAIN;
Packit Service 7500fa
Packit Service 7500fa
   PUTBACK;
Packit Service 7500fa
   FREETMPS;
Packit Service 7500fa
   LEAVE;
Packit Service 7500fa
};
Packit Service 7500fa
Packit Service 7500fa
static void MD5Final( unsigned char hash[16], SV* ctx ) {
Packit Service 7500fa
   int rcount;
Packit Service 7500fa
   char* tmp;
Packit Service 7500fa
   STRLEN len;
Packit Service 7500fa
   SV* retval;
Packit Service 7500fa
   dSP;
Packit Service 7500fa
Packit Service 7500fa
   ENTER; SAVETMPS;
Packit Service 7500fa
Packit Service 7500fa
   PUSHMARK(SP);
Packit Service 7500fa
   XPUSHs(sv_2mortal(ctx));
Packit Service 7500fa
   PUTBACK;
Packit Service 7500fa
Packit Service 7500fa
   rcount = call_method("digest", G_SCALAR);
Packit Service 7500fa
   SPAGAIN;
Packit Service 7500fa
Packit Service 7500fa
   if ( rcount != 1 )
Packit Service 7500fa
       croak("Digest::MD5->digest hasn't returned a scalar");
Packit Service 7500fa
Packit Service 7500fa
   retval = POPs;
Packit Service 7500fa
   tmp = SvPV(retval, len);
Packit Service 7500fa
   if ( len != 16 )
Packit Service 7500fa
       croak("Digest::MD5->digest returned not 16 bytes");
Packit Service 7500fa
Packit Service 7500fa
   memcpy(hash, tmp, len);
Packit Service 7500fa
Packit Service 7500fa
   PUTBACK;
Packit Service 7500fa
   FREETMPS;
Packit Service 7500fa
   LEAVE;
Packit Service 7500fa
};
Packit Service 7500fa
Packit Service 7500fa
MODULE = Data::UUID		PACKAGE = Data::UUID		
Packit Service 7500fa
Packit Service 7500fa
PROTOTYPES: DISABLE
Packit Service 7500fa
Packit Service 7500fa
uuid_context_t*
Packit Service 7500fa
new(class)
Packit Service 7500fa
PREINIT:
Packit Service 7500fa
   FILE          *fd;
Packit Service 7500fa
   unsigned char  seed[16];
Packit Service 7500fa
   perl_uuid_time_t    timestamp;
Packit Service 7500fa
   mode_t         mask;
Packit Service 7500fa
   UV             one = 1;
Packit Service 7500fa
CODE:
Packit Service 7500fa
   RETVAL = (uuid_context_t *)PerlMemShared_malloc(sizeof(uuid_context_t));
Packit Service 7500fa
   if ((fd = fopen(UUID_STATE_NV_STORE, "rb"))) {
Packit Service 7500fa
      fread(&(RETVAL->state), sizeof(uuid_state_t), 1, fd);
Packit Service 7500fa
      fclose(fd);
Packit Service 7500fa
      get_current_time(&timestamp);
Packit Service 7500fa
      RETVAL->next_save = timestamp;
Packit Service 7500fa
   }
Packit Service 7500fa
   if ((fd = fopen(UUID_NODEID_NV_STORE, "rb"))) {
Packit Service 7500fa
      pid_t *hate = (pid_t *) &(RETVAL->nodeid); 
Packit Service 7500fa
      fread(&(RETVAL->nodeid), sizeof(uuid_node_t), 1, fd );
Packit Service 7500fa
      fclose(fd);
Packit Service 7500fa
      
Packit Service 7500fa
      *hate += getpid();
Packit Service 7500fa
   } else {
Packit Service 7500fa
      get_random_info(seed);
Packit Service 7500fa
      seed[0] |= 0x80;
Packit Service 7500fa
      memcpy(&(RETVAL->nodeid), seed, sizeof(uuid_node_t));
Packit Service 7500fa
      mask = umask(_DEFAULT_UMASK);
Packit Service 7500fa
      if ((fd = fopen(UUID_NODEID_NV_STORE, "wb"))) {
Packit Service 7500fa
         fwrite(&(RETVAL->nodeid), sizeof(uuid_node_t), 1, fd);
Packit Service 7500fa
         fclose(fd);
Packit Service 7500fa
      };
Packit Service 7500fa
      umask(mask);
Packit Service 7500fa
   }
Packit Service 7500fa
   errno = 0;
Packit Service 7500fa
#if DU_THREADSAFE
Packit Service 7500fa
   MUTEX_LOCK(&instances_mutex);
Packit Service 7500fa
   ptable_store(instances, RETVAL, INT2PTR(void *, one));
Packit Service 7500fa
   MUTEX_UNLOCK(&instances_mutex);
Packit Service 7500fa
#endif
Packit Service 7500fa
OUTPUT:
Packit Service 7500fa
   RETVAL
Packit Service 7500fa
Packit Service 7500fa
void
Packit Service 7500fa
create(self)
Packit Service 7500fa
   uuid_context_t *self;
Packit Service 7500fa
ALIAS:
Packit Service 7500fa
   Data::UUID::create_bin = F_BIN
Packit Service 7500fa
   Data::UUID::create_str = F_STR
Packit Service 7500fa
   Data::UUID::create_hex = F_HEX
Packit Service 7500fa
   Data::UUID::create_b64 = F_B64
Packit Service 7500fa
PREINIT:
Packit Service 7500fa
   perl_uuid_time_t  timestamp;
Packit Service 7500fa
   unsigned16   clockseq;
Packit Service 7500fa
   perl_uuid_t       uuid;
Packit Service 7500fa
   FILE        *fd;
Packit Service 7500fa
   mode_t       mask;
Packit Service 7500fa
PPCODE:
Packit Service 7500fa
   clockseq = self->state.cs;
Packit Service 7500fa
   get_current_time(&timestamp);
Packit Service 7500fa
   if ( self->state.ts == I64(0) ||
Packit Service 7500fa
      memcmp(&(self->nodeid), &(self->state.node), sizeof(uuid_node_t)))
Packit Service 7500fa
      clockseq = true_random();
Packit Service 7500fa
   else if (timestamp <= self->state.ts)
Packit Service 7500fa
      clockseq++;
Packit Service 7500fa
Packit Service 7500fa
   format_uuid_v1(&uuid, clockseq, timestamp, self->nodeid);
Packit Service 7500fa
   self->state.node = self->nodeid;
Packit Service 7500fa
   self->state.ts   = timestamp;
Packit Service 7500fa
   self->state.cs   = clockseq;
Packit Service 7500fa
   if (timestamp > self->next_save ) {
Packit Service 7500fa
      mask = umask(_DEFAULT_UMASK);
Packit Service 7500fa
      if((fd = fopen(UUID_STATE_NV_STORE, "wb"))) {
Packit Service 7500fa
	 LOCK(fd);
Packit Service 7500fa
         fwrite(&(self->state), sizeof(uuid_state_t), 1, fd);
Packit Service 7500fa
	 UNLOCK(fd);
Packit Service 7500fa
         fclose(fd);
Packit Service 7500fa
      }
Packit Service 7500fa
      umask(mask);
Packit Service 7500fa
      self->next_save = timestamp + (10 * 10 * 1000 * 1000);
Packit Service 7500fa
   }
Packit Service 7500fa
   ST(0) = make_ret(uuid, ix);
Packit Service 7500fa
   XSRETURN(1);
Packit Service 7500fa
Packit Service 7500fa
void
Packit Service 7500fa
create_from_name(self,nsid,name)
Packit Service 7500fa
   uuid_context_t *self;
Packit Service 7500fa
   perl_uuid_t    *nsid;
Packit Service 7500fa
   SV             *name;
Packit Service 7500fa
ALIAS:
Packit Service 7500fa
   Data::UUID::create_from_name_bin = F_BIN
Packit Service 7500fa
   Data::UUID::create_from_name_str = F_STR
Packit Service 7500fa
   Data::UUID::create_from_name_hex = F_HEX
Packit Service 7500fa
   Data::UUID::create_from_name_b64 = F_B64
Packit Service 7500fa
PREINIT:
Packit Service 7500fa
   SV *ctx;
Packit Service 7500fa
   unsigned char hash[16];
Packit Service 7500fa
   perl_uuid_t        net_nsid; 
Packit Service 7500fa
   perl_uuid_t        uuid;
Packit Service 7500fa
PPCODE:
Packit Service 7500fa
   net_nsid = *nsid;
Packit Service 7500fa
   net_nsid.time_low            = htonl(net_nsid.time_low);
Packit Service 7500fa
   net_nsid.time_mid            = htons(net_nsid.time_mid);
Packit Service 7500fa
   net_nsid.time_hi_and_version = htons(net_nsid.time_hi_and_version);
Packit Service 7500fa
Packit Service 7500fa
   ctx = MD5Init();
Packit Service 7500fa
   MD5Update(ctx, newSVpv((char*)&net_nsid, sizeof(perl_uuid_t)));
Packit Service 7500fa
   MD5Update(ctx, name);
Packit Service 7500fa
   MD5Final(hash, ctx);
Packit Service 7500fa
Packit Service 7500fa
   format_uuid_v3(&uuid, hash);
Packit Service 7500fa
   ST(0) = make_ret(uuid, ix);
Packit Service 7500fa
   XSRETURN(1);
Packit Service 7500fa
Packit Service 7500fa
int 
Packit Service 7500fa
compare(self,u1,u2)
Packit Service 7500fa
   uuid_context_t *self;
Packit Service 7500fa
   perl_uuid_t         *u1; 
Packit Service 7500fa
   perl_uuid_t         *u2;
Packit Service 7500fa
PREINIT:
Packit Service 7500fa
   int i;
Packit Service 7500fa
CODE:
Packit Service 7500fa
   RETVAL = 0;
Packit Service 7500fa
   CHECK(u1->time_low, u2->time_low);
Packit Service 7500fa
   CHECK(u1->time_mid, u2->time_mid);
Packit Service 7500fa
   CHECK(u1->time_hi_and_version, u2->time_hi_and_version);
Packit Service 7500fa
   CHECK(u1->clock_seq_hi_and_reserved, u2->clock_seq_hi_and_reserved);
Packit Service 7500fa
   CHECK(u1->clock_seq_low, u2->clock_seq_low);
Packit Service 7500fa
   for (i = 0; i < 6; i++) {
Packit Service 7500fa
      if (u1->node[i] < u2->node[i])
Packit Service 7500fa
         RETVAL = -1;
Packit Service 7500fa
      if (u1->node[i] > u2->node[i])
Packit Service 7500fa
         RETVAL =  1;
Packit Service 7500fa
   }
Packit Service 7500fa
OUTPUT:
Packit Service 7500fa
   RETVAL
Packit Service 7500fa
Packit Service 7500fa
void
Packit Service 7500fa
to_string(self,uuid)
Packit Service 7500fa
   uuid_context_t *self;
Packit Service 7500fa
   perl_uuid_t         *uuid;
Packit Service 7500fa
ALIAS:
Packit Service 7500fa
   Data::UUID::to_hexstring = F_HEX
Packit Service 7500fa
   Data::UUID::to_b64string = F_B64
Packit Service 7500fa
PPCODE:
Packit Service 7500fa
   ST(0) = make_ret(*uuid, ix ? ix : F_STR);
Packit Service 7500fa
   XSRETURN(1);
Packit Service 7500fa
Packit Service 7500fa
void
Packit Service 7500fa
from_string(self,str) 
Packit Service 7500fa
   uuid_context_t *self;
Packit Service 7500fa
   char           *str;
Packit Service 7500fa
ALIAS:
Packit Service 7500fa
   Data::UUID::from_hexstring = F_HEX
Packit Service 7500fa
   Data::UUID::from_b64string = F_B64
Packit Service 7500fa
PREINIT:
Packit Service 7500fa
   perl_uuid_t         uuid;
Packit Service 7500fa
   char          *from, *to;
Packit Service 7500fa
   int            c;
Packit Service 7500fa
   unsigned int   i;
Packit Service 7500fa
   unsigned char  buf[4];
Packit Service 7500fa
PPCODE:
Packit Service 7500fa
   switch(ix) {
Packit Service 7500fa
   case F_BIN:
Packit Service 7500fa
   case F_STR:
Packit Service 7500fa
   case F_HEX:
Packit Service 7500fa
      from = str;
Packit Service 7500fa
      memset(&uuid, 0x00, sizeof(perl_uuid_t));
Packit Service 7500fa
      if ( from[0] == '0' && from[1] == 'x' )
Packit Service 7500fa
         from += 2;
Packit Service 7500fa
      for (i = 0; i < sizeof(perl_uuid_t); i++) {
Packit Service 7500fa
         if (*from == '-')
Packit Service 7500fa
	    from++; 
Packit Service 7500fa
         if (sscanf(from, "%2x", &c) != 1) 
Packit Service 7500fa
	    croak("from_string(%s) failed...\n", str);
Packit Service 7500fa
         ((unsigned char*)&uuid)[i] = (unsigned char)c;
Packit Service 7500fa
         from += 2;
Packit Service 7500fa
      }
Packit Service 7500fa
      uuid.time_low            = ntohl(uuid.time_low);
Packit Service 7500fa
      uuid.time_mid            = ntohs(uuid.time_mid);
Packit Service 7500fa
      uuid.time_hi_and_version = ntohs(uuid.time_hi_and_version);
Packit Service 7500fa
      break;
Packit Service 7500fa
   case F_B64:
Packit Service 7500fa
      from = str; to = (char*)&uui;;
Packit Service 7500fa
      while(from < (str + strlen(str))) {
Packit Service 7500fa
	 i = 0; memset(buf, 254, 4);
Packit Service 7500fa
	 do {
Packit Service 7500fa
	    c = index64[(int)*from++];
Packit Service 7500fa
	    if (c != 255) buf[i++] = (unsigned char)c;
Packit Service 7500fa
	    if (from == (str + strlen(str))) 
Packit Service 7500fa
	       break;
Packit Service 7500fa
         } while (i < 4);
Packit Service 7500fa
Packit Service 7500fa
	 if (buf[0] == 254 || buf[1] == 254) 
Packit Service 7500fa
	    break;
Packit Service 7500fa
         *to++ = (buf[0] << 2) | ((buf[1] & 0x30) >> 4);
Packit Service 7500fa
Packit Service 7500fa
	 if (buf[2] == 254) break;
Packit Service 7500fa
	 *to++ = ((buf[1] & 0x0F) << 4) | ((buf[2] & 0x3C) >> 2);
Packit Service 7500fa
Packit Service 7500fa
	 if (buf[3] == 254) break;
Packit Service 7500fa
	 *to++ = ((buf[2] & 0x03) << 6) | buf[3];
Packit Service 7500fa
      }
Packit Service 7500fa
      break;
Packit Service 7500fa
   default:
Packit Service 7500fa
      croak("invalid type %d\n", ix);
Packit Service 7500fa
      break;
Packit Service 7500fa
   }
Packit Service 7500fa
   ST(0) = make_ret(uuid, F_BIN);
Packit Service 7500fa
   XSRETURN(1);
Packit Service 7500fa
Packit Service 7500fa
#if DU_THREADSAFE
Packit Service 7500fa
Packit Service 7500fa
void
Packit Service 7500fa
CLONE(klass)
Packit Service 7500fa
CODE:
Packit Service 7500fa
   MUTEX_LOCK(&instances_mutex);
Packit Service 7500fa
   ptable_walk(instances, inc, instances);
Packit Service 7500fa
   MUTEX_UNLOCK(&instances_mutex);
Packit Service 7500fa
Packit Service 7500fa
#endif
Packit Service 7500fa
Packit Service 7500fa
void
Packit Service 7500fa
DESTROY(self)
Packit Service 7500fa
   uuid_context_t *self;
Packit Service 7500fa
PREINIT:
Packit Service 7500fa
#if DU_THREADSAFE
Packit Service 7500fa
   UV            count;
Packit Service 7500fa
#endif
Packit Service 7500fa
   FILE           *fd;
Packit Service 7500fa
CODE:
Packit Service 7500fa
#if DU_THREADSAFE
Packit Service 7500fa
   MUTEX_LOCK(&instances_mutex);
Packit Service 7500fa
   count = PTR2UV(ptable_fetch(instances, self));
Packit Service 7500fa
   count--;
Packit Service 7500fa
   ptable_store(instances, self, (void *)count);
Packit Service 7500fa
   MUTEX_UNLOCK(&instances_mutex);
Packit Service 7500fa
   if (count == 0) {
Packit Service 7500fa
#endif
Packit Service 7500fa
      if ((fd = fopen(UUID_STATE_NV_STORE, "wb"))) {
Packit Service 7500fa
         LOCK(fd);
Packit Service 7500fa
         fwrite(&(self->state), sizeof(uuid_state_t), 1, fd);
Packit Service 7500fa
         UNLOCK(fd);
Packit Service 7500fa
         fclose(fd);
Packit Service 7500fa
      };
Packit Service 7500fa
      PerlMemShared_free(self);
Packit Service 7500fa
#if DU_THREADSAFE
Packit Service 7500fa
   }
Packit Service 7500fa
#endif
Packit Service 7500fa
Packit Service 7500fa
BOOT:
Packit Service 7500fa
{
Packit Service 7500fa
  HV *stash = gv_stashpv("Data::UUID", 0);
Packit Service 7500fa
  STRLEN len = sizeof(perl_uuid_t);
Packit Service 7500fa
#if DU_THREADSAFE
Packit Service 7500fa
  instances = ptable_new();
Packit Service 7500fa
  MUTEX_INIT(&instances_mutex);
Packit Service 7500fa
#endif
Packit Service 7500fa
  newCONSTSUB(stash, "NameSpace_DNS", newSVpv((char *)&NameSpace_DNS, len));
Packit Service 7500fa
  newCONSTSUB(stash, "NameSpace_URL", newSVpv((char *)&NameSpace_URL, len));
Packit Service 7500fa
  newCONSTSUB(stash, "NameSpace_OID", newSVpv((char *)&NameSpace_OID, len));
Packit Service 7500fa
  newCONSTSUB(stash, "NameSpace_X500", newSVpv((char *)&NameSpace_X500, len));
Packit Service 7500fa
}