[Insight-developers] DICOM UID generation

Mathieu Malaterre mathieu.malaterre at kitware.com
Thu Jan 6 09:51:01 EST 2005


David Clunie wrote:
> Hi Jim
> 
> Sending money to ANSI is a complete waste of money, since there are
> free UID roots available, and nobody cares where your root comes from
> as long as it is unique.
> 
> For other alternatives, see:
> 
> "http://www.dclunie.com/medical-image-faq/html/part8.html#UIDRegistration"
> 
> Your biggest problem though is not getting a root, it is making sure
> that every file generated by ITK anywhere no matter where and by whom
> it is installed is globally unique.
> 
> Typically this is done with something unique to the device on which it
> is installed, e.g. serial number, hostid, MAC address or similar, as
> well as any process or thread running on that device (e.g. process
> number). It is very hard to get this right in a multi-platform toolkit.
> The MAC address, process number, a date time stamp with high precision
> and a random number might be necessary. If it won't all fit into 64
> bytes, considering feeding everything (after the root) into some sort
> of cryptographic hash function.

David,

	Could you please comment on the code bellow. This is extracted from 
GDCM CVS tree.

	The code works as follow:
echo "gdcm" | od -b
0000000 147 144 143 155 012

	Then we build the UID with:

  radical (if passed in) + 147.144.143.155 + IP + time()

	Therefore even organization without radical can create unique DICOM 
images internal within their organization.

Mathieu

/**
  * \ingroup Util
  * \brief   Return the IP adress of the machine writting the DICOM image
  */
std::string Util::GetIPAddress()
{
   // This is a rip from 
http://www.codeguru.com/Cpp/I-N/internet/network/article.php/c3445/
#ifndef HOST_NAME_MAX
   // SUSv2 guarantees that `Host names are limited to 255 bytes'.
   // POSIX 1003.1-2001 guarantees that `Host names (not including the
   // terminating NUL) are limited to HOST_NAME_MAX bytes'.
#  define HOST_NAME_MAX 255
   // In this case we should maybe check the string was not truncated.
   // But I don't known how to check that...
#if defined(_MSC_VER) || defined(__BORLANDC__)
   // with WinSock DLL we need to initialise the WinSock before using 
gethostname
   WORD wVersionRequested = MAKEWORD(1,0);
   WSADATA WSAData;
   int err = WSAStartup(wVersionRequested,&WSAData);
   if (err != 0) {
       /* Tell the user that we could not find a usable */
       /* WinSock DLL.                                  */
       WSACleanup();
       return "127.0.0.1";
   }
#endif

#endif //HOST_NAME_MAX

   std::string str;
   char szHostName[HOST_NAME_MAX+1];
   int r = gethostname(szHostName, HOST_NAME_MAX);

   if( r == 0 )
   {
     // Get host adresses
     struct hostent * pHost = gethostbyname(szHostName);

     for( int i = 0; pHost!= NULL && pHost->h_addr_list[i]!= NULL; i++ )
     {
       for( int j = 0; j<pHost->h_length; j++ )
       {
         if( j > 0 ) str += ".";

         str += Util::Format("%u",
             (unsigned int)((unsigned char*)pHost->h_addr_list[i])[j]);
       }
       // str now contains one local IP address

#if defined(_MSC_VER) || defined(__BORLANDC__)
   WSACleanup();
#endif

     }
   }
   // If an error occur r == -1
   // Most of the time it will return 127.0.0.1...
   return str;
}

/**
  * \ingroup Util
  * \brief Creates a new UID. As stipulate in the DICOM ref
  *        each time a DICOM image is create it should have
  *        a unique identifier (URI)
  */
std::string Util::CreateUniqueUID(const std::string& root)
{
   // The code works as follow:
   // echo "gdcm" | od -b
   // 0000000 147 144 143 155 012
   // Therefore we return
   // radical + 147.144.143.155 + IP + time()
   std::string radical = root;
   if( !root.size() ) //anything better ?
   {
     radical = "0.0."; // Is this really usefull ?
   }
   // else
   // A root was specified use it to forge our new UID:
   radical += "147.144.143.155"; // gdcm
   radical += ".";
   radical += Util::GetIPAddress();
   radical += ".";
   radical += Util::GetCurrentDate();
   radical += ".";
   radical += Util::GetCurrentTime();

   return radical;
}





More information about the Insight-developers mailing list