[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