📄 gdcmutil.cxx
字号:
perror("in Get MAC Adress (internal) : sock");
return -1;
}
memset(&parpreq, 0, sizeof(struct arpreq));
psa = (struct sockaddr_in *) &parpreq.arp_pa;
memset(psa, 0, sizeof(struct sockaddr_in));
psa->sin_family = AF_INET;
memcpy(&psa->sin_addr, *paddrs, sizeof(struct in_addr));
status = ioctl(sock, SIOCGARP, &parpreq);
if (status == -1 )
{
perror("in Get MAC Adress (internal) : SIOCGARP");
return -1;
}
memcpy(addr, parpreq.arp_ha.sa_data, 6);
return 0;
#else
#ifdef CMAKE_HAVE_NET_IF_H
int sd;
struct ifreq ifr, *ifrp;
struct ifconf ifc;
char buf[1024];
int n, i;
unsigned char *a;
#if defined(AF_LINK) && (!defined(SIOCGIFHWADDR) && !defined(SIOCGENADDR))
struct sockaddr_dl *sdlp;
#endif
//
// BSD 4.4 defines the size of an ifreq to be
// max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len
// However, under earlier systems, sa_len isn't present, so the size is
// just sizeof(struct ifreq)
// We should investigate the use of SIZEOF_ADDR_IFREQ
//
#ifdef HAVE_SA_LEN
#ifndef max
#define max(a,b) ((a) > (b) ? (a) : (b))
#endif
#define ifreq_size(i) max(sizeof(struct ifreq),\
sizeof((i).ifr_name)+(i).ifr_addr.sa_len)
#else
#define ifreq_size(i) sizeof(struct ifreq)
#endif // HAVE_SA_LEN
if ( (sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0 )
{
return -1;
}
memset(buf, 0, sizeof(buf));
ifc.ifc_len = sizeof(buf);
ifc.ifc_buf = buf;
if (ioctl (sd, SIOCGIFCONF, (char *)&ifc) < 0)
{
close(sd);
return -1;
}
n = ifc.ifc_len;
for (i = 0; i < n; i+= ifreq_size(*ifrp) )
{
ifrp = (struct ifreq *)((char *) ifc.ifc_buf+i);
strncpy(ifr.ifr_name, ifrp->ifr_name, IFNAMSIZ);
#ifdef SIOCGIFHWADDR
if (ioctl(sd, SIOCGIFHWADDR, &ifr) < 0)
continue;
a = (unsigned char *) &ifr.ifr_hwaddr.sa_data;
#else
#ifdef SIOCGENADDR
// In theory this call should also work on Sun Solaris, but apparently
// SIOCGENADDR is not implemented properly thus the call
// ioctl(sd, SIOCGENADDR, &ifr) always returns errno=2
// (No such file or directory)
// Furthermore the DLAPI seems to require full root access
if (ioctl(sd, SIOCGENADDR, &ifr) < 0)
continue;
a = (unsigned char *) ifr.ifr_enaddr;
#else
#ifdef AF_LINK
sdlp = (struct sockaddr_dl *) &ifrp->ifr_addr;
if ((sdlp->sdl_family != AF_LINK) || (sdlp->sdl_alen != 6))
continue;
a = (unsigned char *) &sdlp->sdl_data[sdlp->sdl_nlen];
#else
perror("in Get MAC Adress (internal) : No way to access hardware");
close(sd);
return -1;
#endif // AF_LINK
#endif // SIOCGENADDR
#endif // SIOCGIFHWADDR
if (!a[0] && !a[1] && !a[2] && !a[3] && !a[4] && !a[5]) continue;
if (addr)
{
memcpy(addr, a, 6);
close(sd);
return 0;
}
}
close(sd);
#endif
// Not implemented platforms (or no cable !)
perror("in Get MAC Adress (internal) : There was a configuration problem (or no cable !) on your platform");
memset(addr,0,6);
return -1;
#endif //__sun
}
/**
* \brief Mini function to return the last digit from a number express in base 256
* pre condition data contain an array of 6 unsigned char
* post condition carry contain the last digit
*/
inline int getlastdigit(unsigned char *data, unsigned int size = 6)
{
int extended, carry = 0;
for(unsigned int i=0;i<size;i++)
{
extended = (carry << 8) + data[i];
data[i] = extended / 10;
carry = extended % 10;
}
return carry;
}
size_t Util::EncodeBytes(char *out, const unsigned char *data, int size)
{
bool zero = false;
int res;
std::string sres;
unsigned char buffer[32];
unsigned char *addr = buffer;
memcpy(addr, data, size);
while(!zero)
{
res = getlastdigit(addr, size);
sres.insert(sres.begin(), '0' + res);
zero = true;
for(int i = 0; i < size; ++i)
{
zero = zero && (addr[i] == 0);
}
}
//return sres;
strcpy(out, sres.c_str()); //, sres.size() );
return sres.size();
}
/**
* \brief Encode the mac address on a fixed length string of 15 characters.
* we save space this way.
*/
std::string Util::GetMACAddress()
{
// This code is the result of a long internet search to find something
// as compact as possible (not OS independant). We only have to separate
// 3 OS: Win32, SunOS and 'real' POSIX
// http://groups-beta.google.com/group/comp.unix.solaris/msg/ad36929d783d63be
// http://bdn.borland.com/article/0,1410,26040,00.html
unsigned char addr[6];
int stat = GetMacAddrSys(addr);
if (stat == 0)
{
// We need to convert a 6 digit number from base 256 to base 10, using integer
// would requires a 48bits one. To avoid this we have to reimplement the div + modulo
// with string only
bool zero = false;
int res;
std::string sres;
while(!zero)
{
res = getlastdigit(addr);
sres.insert(sres.begin(), '0' + res);
zero = (addr[0] == 0) && (addr[1] == 0) && (addr[2] == 0)
&& (addr[3] == 0) && (addr[4] == 0) && (addr[5] == 0);
}
return sres;
}
else
{
gdcmWarningMacro("Problem in finding the MAC Address");
return "";
}
}
/**
* \brief Creates a new UID. As stipulated in the DICOM ref
* each time a DICOM image is created it should have
* a unique identifier (URI)
* @param root is the DICOM prefix assigned by IOS group
*/
std::string Util::CreateUniqueUID(const std::string &root)
{
#if defined(HAVE_UUIDCREATE) || defined(HAVE_UUID_GENERATE) || defined(HAVE_UUID_CREATE)
const char * s = Util::CreateUniqueUID2(root);
return s;
#else
std::string prefix;
std::string append;
if ( root.empty() )
{
// gdcm UID prefix, as supplied by http://www.medicalconnections.co.uk
assert( !RootUID.empty() );
prefix = RootUID;
}
else
{
prefix = root;
}
// A root was specified use it to forge our new UID:
append += ".";
//append += Util::GetMACAddress(); // to save CPU time
if( !Util::GDCM_MAC_ADDRESS.empty() )
{
append += Util::GDCM_MAC_ADDRESS;
append += ".";
}
append += Util::GetCurrentDateTime();
//Also add a mini random number just in case:
char tmp[10];
int r = (int) (100.0*rand()/RAND_MAX);
// Don't use Util::Format to accelerate the execution
sprintf(tmp,"%02d", r);
append += tmp;
// If append is too long we need to rehash it
if ( (prefix + append).size() > 64 )
{
gdcmErrorMacro( "Size of UID is too long." );
// we need a hash function to truncate this number
// if only md5 was cross platform
// MD5(append);
}
return prefix + append;
#endif
}
/* return true on success */
bool Util::GenerateUUID(unsigned char *uuid_data)
{
#if defined(HAVE_UUID_GENERATE)
uuid_t g;
uuid_generate(g);
memcpy(uuid_data, g, sizeof(uuid_t));
return true;
#elif defined(HAVE_UUID_CREATE)
uint32_t rv;
uuid_t g;
uuid_create(&g, &rv);
if (rv != uuid_s_ok)
return false;
memcpy(uuid_data, &g, sizeof(uuid_t));
return true;
#elif defined(HAVE_UUIDCREATE)
if (FAILED(UuidCreate((UUID *)uuid_data)))
{
return false;
}
return true;
#else
uuid_data = 0;
return false;
#endif
}
const char * Util::CreateUniqueUID2(const std::string &root)
{
static std::string Unique;
std::string prefix;
//std::string append;
if ( root.empty() )
{
// gdcm UID prefix, as supplied by http://www.medicalconnections.co.uk
assert( !RootUID.empty() );
prefix = RootUID;
}
else
{
prefix = root;
}
//Unique = GetRoot();
Unique = prefix;
// We choose here a value of 26 so that we can still have 37 bytes free to
// set the suffix part which is sufficient to store a 2^(128-8+1)-1 number
if( Unique.empty() || Unique.size() > 62 ) // 62 is simply the highest possible limit
{
// I cannot go any further...
return NULL;
}
unsigned char uuid[16];
bool r = GenerateUUID(uuid);
// This should only happen in some obscure cases. Since the creation of UUID failed
// I should try to go any further and make sure the user's computer crash and burn
// right away
if( !r ) return 0;
char randbytesbuf[64];
size_t len = Util::EncodeBytes(randbytesbuf, uuid, sizeof(uuid));
assert( len < 64 ); // programmer error
Unique += "."; // This dot is compulsary to separate root from suffix
if( Unique.size() + len > 64 )
{
int idx = 0;
bool found = false;
std::bitset<8> x;
while( !found && idx < 16 ) /* 16 is insane ... oh well */
{
// too bad ! randbytesbuf is too long, let's try to truncate the high bits a little
x = uuid[idx];
unsigned int i = 0;
while( ( Unique.size() + len > 64 ) && i < 8 )
{
x[7-i] = 0;
uuid[idx] = x.to_ulong();
len = Util::EncodeBytes(randbytesbuf, uuid, sizeof(uuid));
++i;
}
if( ( Unique.size() + len > 64 ) && i == 8 )
{
// too bad only reducing the 8 bits from uuid[idx] was not enought,
// let's set to zero the following bits...
idx++;
}
else
{
// cool we found enough to stop
found = true;
}
}
if( !found )
{
// Technically this could only happen when root has a length >= 64 ... is it
// even remotely possible ?
gdcmWarningMacro( "Root is too long for current implementation" );
return NULL;
}
}
// can now safely use randbytesbuf as is, no need to truncate any more:
Unique += randbytesbuf;
assert( Util::IsValid( Unique.c_str() ) );
return Unique.c_str();
}
void Util::SetRootUID(const std::string &root)
{
if ( root.empty() )
RootUID = GDCM_UID;
else
RootUID = root;
}
const std::string &Util::GetRootUID()
{
return RootUID;
}
bool Util::IsValid(const char *uid_)
{
/*
9.1 UID ENCODING RULES
The DICOM UID encoding rules are defined as follows:
- Each component of a UID is a number and shall consist of one or more digits. The first digit of
each component shall not be zero unless the component is a single digit.
Note: Registration authorities may distribute components with non-significant leading zeroes. The leading
zeroes should be ignored when being encoded (ie.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -