//  ----------------------------------------------------------------------------
//  MODULE    : Gen_guid 
//  LANGUAGE  : C++ 
//  CREATOR   : Philippe BOSSUT 
//  CREAT. DATE : Thursday, May 2, 1996 
//  DESCRIPTION : Guid generation compatible Mac and Windows.
//  SCCSID      : @(#)gen_guid.cpp  1.1 11:53:26 18 Dec 1996
//  ----------------------------------------------------------------------------
//  Copyright (c) 1999 Digital Imaging Group, Inc.
//  For conditions of distribution and use, see copyright notice
//  in Flashpix.h
//  ----------------------------------------------------------------------------
  #ifdef macintosh
    #pragma segment Gen_guid
  #endif
//  ----------------------------------------------------------------------------

//  Includes
//  --------

#ifndef OLECommun_h
  #include "olecomm.h"
#endif
#ifndef OLECore_h
  #include "olecore.h"
#endif
#ifndef Debug_h
  #include "debug.h"
#endif

#ifdef _WINDOWS 
  #include "b_error.h"
#endif

#include "fpxlib-config.h"

#if defined(HAVE_SYS_TIME_H)
  #include <sys/time.h>
#endif

//  ----------------------------------------------------------------------------
  #include "gen_guid.h"
//  ----------------------------------------------------------------------------

//  Constants
//  ---------

#define UUID_LEN        128                 /* In bits */
#define UUID_VERSION    0x1000              /* DCE variant */
#define UUID_RESERVED   0x10
#define DEFAULT_ETHER_ADDR  "8:0:20:20:32:d0"   /* Historically significant... :-) */

//  Variables
//  ---------

#if   !defined(__unix) && !defined(HAVE_SYS_TIME_H)
typedef struct _timespec
{
  unsigned long tv_nsec;
  unsigned long tv_sec;
} timespec;
#endif

//  ----------------------------------------------------------------------------
//  Internal Functions
//  ----------------------------------------------------------------------------

#if defined(macintosh) || defined(__unix)
static void GetENETAddress(unsigned char *ENETaddress)
{
  // MPPParamBlock thePB;
  short i;
  char linkAddr[7];
  // char zoneName[34];
  // OSErr err;
  
  linkAddr[0] = 0x08;
  linkAddr[1] = 0x00;
  linkAddr[2] = 0x20;
  linkAddr[3] = 0x20;
  linkAddr[4] = 0x32;
  linkAddr[5] = 0xd0;
  // thePB.GAIINFO.version = 1;
  // thePB.GAIINFO.LAlength = 6;
  // thePB.GAIINFO.linkAddr = linkAddr;
  // thePB.GAIINFO.zoneName = zoneName;
  // err = PGetAppleTalkInfo(&thePB, 0);
  for(i=0;i<6;i++)
    *(ENETaddress+i) = linkAddr[i];
}
#endif

//  ----------------------------------------------------------------------------
//  Member Functions
//  ----------------------------------------------------------------------------

//  ----------------------------------------------------------------------------
//  External Functions
//  ----------------------------------------------------------------------------

#if defined(macintosh) || defined(_UNIX)
HRESULT GenGuid(CLSID *clsid)
{
  timespec ts;
  unsigned char ether_address[20];
  uint32_t loop, time_low, offset;
  uint16_t clock_sequence, time_mid, time_hi_and_version;
  unsigned char *uuid, clock_seq_hi, clock_seq_low; 

  offset = 0;

  uuid = (unsigned char *)clsid;

#if defined(macintosh)
  ts.tv_sec  = TickCount() * 60;
  ts.tv_nsec = ts.tv_sec   * 100000; 
#else
# ifdef _UNIX // FIXME: Should be based on HAVE_GETTIMEOFDAY
  {
    struct timeval tv;
    gettimeofday(&tv,NULL);
    ts.tv_sec = tv.tv_sec;
    ts.tv_nsec = tv.tv_usec * 1000;
  }
# endif
#endif

//  clock_gettime(CLOCK_REALTIME, &ts);

  /* Copy in TIME_LOW to uuid from nano seconds */
  time_low = ts.tv_nsec;
  BlockMove((unsigned char *)&time_low, (unsigned char *)(uuid + offset), 4);
  offset += 4;

  /* Copy in TIME_MID to uuid from seconds */
  time_mid = (unsigned short)(ts.tv_sec & 0x0000ffff);
  BlockMove((unsigned char *)&time_mid, (unsigned char *)(uuid + offset), 2);
  offset += 2;

  /* Copy in TIME_HI_AND_VERSION to uuid from seconds and version id */
  time_hi_and_version = (unsigned short)(ts.tv_sec >> 8);
  time_hi_and_version &= 0x0fff;
  time_hi_and_version |= UUID_VERSION;
  BlockMove((unsigned char *)&time_hi_and_version, (unsigned char *)(uuid + offset), 2);
  offset += 2;

  /* Copy in CLOCK_SEQUENCE to uuid from seconds and version id */
  /* Always assume we have to reinit the clock sequence.
   * It's just easier this way... :-)
   */
  srand(ts.tv_nsec);    /* Seed random number generator with nanoseconds */
  clock_sequence = ((unsigned short)rand() % 16384);

  clock_seq_low = (unsigned char)(clock_sequence);

  clock_seq_hi = (unsigned char)(clock_sequence >> 8);
  clock_seq_hi &= 0x3f;
  clock_seq_hi |= UUID_RESERVED;
  BlockMove((unsigned char *)&clock_seq_hi, (unsigned char *)(uuid + offset), sizeof(unsigned char));
  offset+=sizeof(unsigned char);
  BlockMove((unsigned char *)&clock_seq_low, (unsigned char *)(uuid + offset), sizeof(unsigned char));
  offset+=sizeof(unsigned char);

  GetENETAddress(ether_address);

  for (loop = 0; loop < 6; loop++)
    *(uuid + offset + loop) = (unsigned char)ether_address[loop];
    
 return(S_OK);

}
#else
// The Windows version is of course better integrated...
HRESULT GenGuid(CLSID *clsid)
{
  return CoCreateGuid(clsid);
}
#endif // macintosh


//  - EOF ----------------------------------------------------------------------
