X-Git-Url: https://git.creatis.insa-lyon.fr/pubgit/?a=blobdiff_plain;f=src%2FgdcmUtil.cxx;h=6d474c2e5c83b3584c00db80685ea166956e8f87;hb=906464b1c71b1b623f8202a693e75a358a5bd965;hp=1bcba04c10bf728abd2856c211fe1bf2912d6b57;hpb=8a9ab161e2643bf1406660e2fbbf5caf8f915137;p=gdcm.git diff --git a/src/gdcmUtil.cxx b/src/gdcmUtil.cxx index 1bcba04c..6d474c2e 100644 --- a/src/gdcmUtil.cxx +++ b/src/gdcmUtil.cxx @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmUtil.cxx,v $ Language: C++ - Date: $Date: 2005/01/15 21:36:01 $ - Version: $Revision: 1.93 $ + Date: $Date: 2006/02/16 20:06:15 $ + Version: $Revision: 1.183 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -18,81 +18,102 @@ #include "gdcmUtil.h" #include "gdcmDebug.h" + #include +#include // for va_list // For GetCurrentDate, GetCurrentTime #include #include #include +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__) +#include +#else +#include +#endif + #include //only included in implementation file #include //only included in implementation file -#if defined(_MSC_VER) - #include // for gethostname & gethostbyname +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__) + #include // for gethostname and gethostbyname and GetTickCount... +// I haven't find a way to determine wether we need to under GetCurrentTime or not... +// I think the best solution would simply to get rid of this problematic function +// and use a 'less' common name... +#if !defined(__BORLANDC__) || (__BORLANDC__ >= 0x0560) #undef GetCurrentTime +#endif #else -#ifndef __BORLANDC__ #include // for gethostname #include // for gethostbyname #endif -#endif // For GetMACAddress #ifdef _WIN32 -#include -#include + #include + #include #else -#include -#include -#include -#include + #include + #include + #include + #include #endif -#ifdef __sun -//#include -#include -#include -#include -#else -//#include -//#include -//#include -#include -#include -#endif //__sun - #ifdef CMAKE_HAVE_SYS_IOCTL_H -#include // For SIOCGIFCONF on Linux + #include // For SIOCGIFCONF on Linux #endif #ifdef CMAKE_HAVE_SYS_SOCKET_H -#include + #include #endif #ifdef CMAKE_HAVE_SYS_SOCKIO_H -#include // For SIOCGIFCONF on SunOS + #include // For SIOCGIFCONF on SunOS #endif #ifdef CMAKE_HAVE_NET_IF_H -#include + #include #endif #ifdef CMAKE_HAVE_NETINET_IN_H -#include //For IPPROTO_IP + #include //For IPPROTO_IP #endif #ifdef CMAKE_HAVE_NET_IF_DL_H -#include + #include +#endif +#if defined(CMAKE_HAVE_NET_IF_ARP_H) && defined(__sun) + // This is absolutely necessary on SunOS + #include #endif -// How do I do that in CMake ? -#ifdef __APPLE__ -#define HAVE_SA_LEN -#endif //APPLE +// For GetCurrentThreadID() +#ifdef __linux__ + #include + #include +#endif +#ifdef __sun + #include +#endif namespace gdcm { +//------------------------------------------------------------------------- +const std::string Util::GDCM_UID = "1.2.826.0.1.3680043.2.1143"; +std::string Util::RootUID = GDCM_UID; +/* + * File Meta Information Version (0002,0001) shall contain a two byte OB + * value consisting of a 0x00 byte, followed by 0x01 byte, and not the + * value 0x0001 encoded as a little endian 16 bit short value, + * which would be the other way around... + */ +const uint16_t Util::FMIV = 0x0100; +uint8_t *Util::FileMetaInformationVersion = (uint8_t *)&FMIV; +std::string Util::GDCM_MAC_ADRESS = GetMACAddress(); + +//------------------------------------------------------------------------- +// Public /** - * \ingroup Globals * \brief Provide a better 'c++' approach for sprintf * For example c code is: - * sprintf(trash, "%04x|%04x", group , elem); + * char result[2048]; // hope 2048 is enough + * sprintf(result, "%04x|%04x", group , elem); * * c++ code is * std::ostringstream buf; @@ -102,12 +123,12 @@ namespace gdcm * buf.str(); * * gdcm style code is - * Format("%04x|%04x", group , elem); + * string result; + * result = gdcm::Util::Format("%04x|%04x", group , elem); */ - std::string Util::Format(const char *format, ...) { - char buffer[2048]; + char buffer[2048]; // hope 2048 is enough va_list args; va_start(args, format); vsprintf(buffer, format, args); //might be a security flaw @@ -119,12 +140,15 @@ std::string Util::Format(const char *format, ...) /** - * \ingroup Globals * \brief Because not available in C++ (?) + * @param str string to check + * @param tokens std::vector to receive the tokenized substrings + * @param delimiters string containing the character delimitors + */ void Util::Tokenize (const std::string &str, std::vector &tokens, - const std::string& delimiters) + const std::string &delimiters) { std::string::size_type lastPos = str.find_first_not_of(delimiters,0); std::string::size_type pos = str.find_first_of (delimiters,lastPos); @@ -137,36 +161,70 @@ void Util::Tokenize (const std::string &str, } /** - * \ingroup Globals * \brief Because not available in C++ (?) * Counts the number of occurences of a substring within a string + * @param str string to check + * @param subStr substring to count */ int Util::CountSubstring (const std::string &str, const std::string &subStr) { - int count = 0; // counts how many times it appears - std::string::size_type x = 0; // The index position in the string + int count = 0; // counts how many times it appears + std::string::size_type x = 0; // The index position in the string do { - x = str.find(subStr,x); // Find the substring - if (x != std::string::npos) // If present + x = str.find(subStr,x); // Find the substring + if (x != std::string::npos) // If present { - count++; // increase the count - x += subStr.length(); // Skip this word + count++; // increase the count + x += subStr.length(); // Skip this word } } - while (x != std::string::npos); // Carry on until not present + while (x != std::string::npos);// Carry on until not present return count; } /** - * \ingroup Globals + * \brief Checks whether a 'string' is printable or not (in order + * to avoid corrupting the terminal of invocation when printing) + * @param s string to check + */ +bool Util::IsCleanString(std::string const &s) +{ + for(unsigned int i=0; i 0) + if (str.size() > 0 ) { - if(!isprint((unsigned char)s[str.size()-1])) + if (!isprint((unsigned char)s[str.size()-1]) ) { - if(s[str.size()-1] == 0) + if (s[str.size()-1] == 0 ) { str[str.size()-1] = ' '; } @@ -195,36 +253,67 @@ std::string Util::CreateCleanString(std::string const &s) } /** - * \ingroup Globals - * \brief Add a SEPARATOR to the end of the name is necessary + * \brief Weed out a string from the non-printable characters (in order + * to avoid corrupting the terminal of invocation when printing) + * @param s area to process (uint8_t is just for prototyping. feel free to cast) + * @param l area length to check + */ +std::string Util::CreateCleanString(uint8_t *s, int l) +{ + std::string str; + + for( int i=0; i pos2) + if ( pos1 > pos2 ) { res.resize(pos1); } @@ -232,23 +321,28 @@ std::string Util::GetPath(std::string const &fullName) { res.resize(pos2); } - +*/ + int pos = res.rfind(GDCM_FILESEPARATOR); + res.resize(pos); return res; } /** - * \ingroup Util * \brief Get the (last) name of a full path file name * @param fullName file/directory name to extract end name from */ std::string Util::GetName(std::string const &fullName) { std::string filename = fullName; - +/* std::string::size_type slash_pos = filename.rfind("/"); std::string::size_type backslash_pos = filename.rfind("\\"); - slash_pos = slash_pos > backslash_pos ? slash_pos : backslash_pos; - if(slash_pos != std::string::npos) + // At least with my gcc4.0.1, unfound char results in pos =4294967295 ... + //slash_pos = slash_pos > backslash_pos ? slash_pos : backslash_pos; + slash_pos = slash_pos < backslash_pos ? slash_pos : backslash_pos; +*/ + std::string::size_type slash_pos = filename.rfind(GDCM_FILESEPARATOR); + if (slash_pos != std::string::npos ) { return filename.substr(slash_pos + 1); } @@ -259,7 +353,6 @@ std::string Util::GetName(std::string const &fullName) } /** - * \ingroup Util * \brief Get the current date of the system in a dicom string */ std::string Util::GetCurrentDate() @@ -272,7 +365,6 @@ std::string Util::GetCurrentDate() } /** - * \ingroup Util * \brief Get the current time of the system in a dicom string */ std::string Util::GetCurrentTime() @@ -284,11 +376,91 @@ std::string Util::GetCurrentTime() return tmp; } +/** + * \brief Get both the date and time at the same time to avoid problem + * around midnight where the two calls could be before and after midnight + */ +std::string Util::GetCurrentDateTime() +{ + char tmp[40]; + long milliseconds; + time_t timep; + + // We need implementation specific functions to obtain millisecond precision +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__) + struct timeb tb; + ::ftime(&tb); + timep = tb.time; + milliseconds = tb.millitm; +#else + struct timeval tv; + gettimeofday (&tv, NULL); + timep = tv.tv_sec; + // Compute milliseconds from microseconds. + milliseconds = tv.tv_usec / 1000; +#endif + // Obtain the time of day, and convert it to a tm struct. + struct tm *ptm = localtime (&timep); + // Format the date and time, down to a single second. + strftime (tmp, sizeof (tmp), "%Y%m%d%H%M%S", ptm); + + // Add milliseconds + // Don't use Util::Format to accelerate execution of code + char tmpAll[80]; + sprintf(tmpAll,"%s%03ld",tmp,milliseconds); + + return tmpAll; +} + +unsigned int Util::GetCurrentThreadID() +{ +// FIXME the implementation is far from complete +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__) + return (unsigned int)GetCurrentThreadId(); +#else +#ifdef __linux__ + return 0; + // Doesn't work on fedora, but is in the man page... + //return (unsigned int)gettid(); +#else +#ifdef __sun + return (unsigned int)thr_self(); +#else + //default implementation + return 0; +#endif // __sun +#endif // __linux__ +#endif // Win32 +} + +unsigned int Util::GetCurrentProcessID() +{ +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__) + // NOTE: There is also a _getpid()... + return (unsigned int)GetCurrentProcessId(); +#else + // get process identification, POSIX + return (unsigned int)getpid(); +#endif +} + +/** + * \brief tells us whether the processor we are working with is BigEndian or not + */ +bool Util::IsCurrentProcessorBigEndian() +{ +#if defined(GDCM_WORDS_BIGENDIAN) + return true; +#else + return false; +#endif +} + /** * \brief Create a /DICOM/ string: * It should a of even length (no odd length ever) * It can contain as many (if you are reading this from your - * editor the following character is is backslash followed by zero + * editor the following character is backslash followed by zero * that needed to be escaped with an extra backslash for doxygen) \\0 * as you want. */ @@ -300,21 +472,20 @@ std::string Util::DicomString(const char *s, size_t l) } /** - * \ingroup Util * \brief Create a /DICOM/ string: - * It should a of even lenght (no odd length ever) + * It should a of even length (no odd length ever) * It can contain as many (if you are reading this from your - * editor the following character is is backslash followed by zero + * editor the following character is backslash followed by zero * that needed to be escaped with an extra backslash for doxygen) \\0 * as you want. * This function is similar to DicomString(const char*), - * except it doesn't take a lenght. + * except it doesn't take a length. * It only pad with a null character if length is odd */ std::string Util::DicomString(const char *s) { size_t l = strlen(s); - if( l%2 ) + if ( l%2 ) { l++; } @@ -324,79 +495,121 @@ std::string Util::DicomString(const char *s) } /** - * \ingroup Util - * \brief Safely compare two Dicom String: - * - Both string should be of even lenght - * - We allow padding of even lenght string by either a null - * character of a space + * \brief Safely check the equality of two Dicom String: + * - Both strings should be of even length + * - We allow padding of even length string by either + * a null character of a space */ bool Util::DicomStringEqual(const std::string &s1, const char *s2) { - // s2 is the string from the DICOM reference: 'MONOCHROME1' + // s2 is the string from the DICOM reference e.g. : 'MONOCHROME1' std::string s1_even = s1; //Never change input parameter std::string s2_even = DicomString( s2 ); - if( s1_even[s1_even.size()-1] == ' ') + if ( s1_even[s1_even.size()-1] == ' ' ) { s1_even[s1_even.size()-1] = '\0'; //replace space character by null } return s1_even == s2_even; } - - /** - * \ingroup Util - * \brief tells us if the processor we are working with is BigEndian or not + * \brief Safely compare two Dicom String: + * - Both strings should be of even length + * - We allow padding of even length string by either + * a null character of a space */ -bool Util::IsCurrentProcessorBigEndian() +bool Util::CompareDicomString(const std::string &s1, const char *s2, int op) { -#ifdef GDCM_WORDS_BIGENDIAN - return true; -#else - return false; -#endif + // s2 is the string from the DICOM reference e.g. : 'MONOCHROME1' + std::string s1_even = s1; //Never change input parameter + std::string s2_even = DicomString( s2 ); + if ( s1_even[s1_even.size()-1] == ' ' ) + { + s1_even[s1_even.size()-1] = '\0'; //replace space character by null + } + switch (op) + { + case GDCM_EQUAL : + return s1_even == s2_even; + case GDCM_DIFFERENT : + return s1_even != s2_even; + case GDCM_GREATER : + return s1_even > s2_even; + case GDCM_GREATEROREQUAL : + return s1_even >= s2_even; + case GDCM_LESS : + return s1_even < s2_even; + case GDCM_LESSOREQUAL : + return s1_even <= s2_even; + default : + gdcmDebugMacro(" Wrong operator : " << op); + return false; + } } - - #ifdef _WIN32 -typedef BOOL(WINAPI * pSnmpExtensionInit) ( - IN DWORD dwTimeZeroReference, - OUT HANDLE * hPollForTrapEvent, - OUT AsnObjectIdentifier * supportedView); - -typedef BOOL(WINAPI * pSnmpExtensionTrap) ( - OUT AsnObjectIdentifier * enterprise, - OUT AsnInteger * genericTrap, - OUT AsnInteger * specificTrap, - OUT AsnTimeticks * timeStamp, - OUT RFC1157VarBindList * variableBindings); - -typedef BOOL(WINAPI * pSnmpExtensionQuery) ( - IN BYTE requestType, - IN OUT RFC1157VarBindList * variableBindings, - OUT AsnInteger * errorStatus, - OUT AsnInteger * errorIndex); - -typedef BOOL(WINAPI * pSnmpExtensionInitEx) ( - OUT AsnObjectIdentifier * supportedView); + typedef BOOL(WINAPI * pSnmpExtensionInit) ( + IN DWORD dwTimeZeroReference, + OUT HANDLE * hPollForTrapEvent, + OUT AsnObjectIdentifier * supportedView); + + typedef BOOL(WINAPI * pSnmpExtensionTrap) ( + OUT AsnObjectIdentifier * enterprise, + OUT AsnInteger * genericTrap, + OUT AsnInteger * specificTrap, + OUT AsnTimeticks * timeStamp, + OUT RFC1157VarBindList * variableBindings); + + typedef BOOL(WINAPI * pSnmpExtensionQuery) ( + IN BYTE requestType, + IN OUT RFC1157VarBindList * variableBindings, + OUT AsnInteger * errorStatus, + OUT AsnInteger * errorIndex); + + typedef BOOL(WINAPI * pSnmpExtensionInitEx) ( + OUT AsnObjectIdentifier * supportedView); #endif //_WIN32 +#ifdef __sgi +static int SGIGetMacAddress(unsigned char *addr) +{ + FILE *f = popen("/etc/nvram eaddr","r"); + if(f == 0) + { + return -1; + } + unsigned int x[6]; + if(fscanf(f,"%02x:%02x:%02x:%02x:%02x:%02x", + x,x+1,x+2,x+3,x+4,x+5) != 6) + { + pclose(f); + return -1; + } + for(unsigned int i = 0; i < 6; i++) + { + addr[i] = static_cast(x[i]); + } + return 0; +} +#endif -long GetMacAddrSys ( unsigned char *addr) +/// \brief gets current M.A.C adress (for internal use only) +int GetMacAddrSys ( unsigned char *addr ); +int GetMacAddrSys ( unsigned char *addr ) { #ifdef _WIN32 WSADATA WinsockData; - if (WSAStartup(MAKEWORD(2, 0), &WinsockData) != 0) + if ( (WSAStartup(MAKEWORD(2, 0), &WinsockData)) != 0 ) { - std::cerr << "This program requires Winsock 2.x!" << std::endl; + std::cerr << "in Get MAC Adress (internal) : This program requires Winsock 2.x!" + << std::endl; return -1; } HANDLE PollForTrapEvent; AsnObjectIdentifier SupportedView; - UINT OID_ifEntryType[] = { 1, 3, 6, 1, 2, 1, 2, 2, 1, 3 }; - UINT OID_ifEntryNum[] = { 1, 3, 6, 1, 2, 1, 2, 1 }; + UINT OID_ifEntryType[] = { 1, 3, 6, 1, 2, 1, 2, 2, 1, 3 }; + UINT OID_ifEntryNum[] = { 1, 3, 6, 1, 2, 1, 2, 1 }; UINT OID_ipMACEntAddr[] = { 1, 3, 6, 1, 2, 1, 2, 2, 1, 6 }; AsnObjectIdentifier MIB_ifMACEntAddr = { sizeof(OID_ipMACEntAddr) / sizeof(UINT), OID_ipMACEntAddr }; @@ -411,24 +624,18 @@ long GetMacAddrSys ( unsigned char *addr) AsnObjectIdentifier MIB_NULL = { 0, 0 }; int ret; int dtmp; - int i = 0, j = 0; - BOOL found = FALSE; + int j = 0; // Load the SNMP dll and get the addresses of the functions necessary HINSTANCE m_hInst = LoadLibrary("inetmib1.dll"); if (m_hInst < (HINSTANCE) HINSTANCE_ERROR) { - m_hInst = NULL; return -1; } pSnmpExtensionInit m_Init = (pSnmpExtensionInit) GetProcAddress(m_hInst, "SnmpExtensionInit"); - pSnmpExtensionInitEx m_InitEx = - (pSnmpExtensionInitEx) GetProcAddress(m_hInst, "SnmpExtensionInitEx"); pSnmpExtensionQuery m_Query = (pSnmpExtensionQuery) GetProcAddress(m_hInst, "SnmpExtensionQuery"); - pSnmpExtensionTrap m_Trap = - (pSnmpExtensionTrap) GetProcAddress(m_hInst, "SnmpExtensionTrap"); m_Init(GetTickCount(), &PollForTrapEvent, &SupportedView); /* Initialize the variable list to be retrieved by m_Query */ @@ -440,10 +647,11 @@ long GetMacAddrSys ( unsigned char *addr) // Inteface table varBindList.len = 1; // Only retrieving one item SNMP_oidcpy(&varBind[0].name, &MIB_ifEntryNum); - ret = m_Query(ASN_RFC1157_GETNEXTREQUEST, &varBindList, &errorStatus, + m_Query(ASN_RFC1157_GETNEXTREQUEST, &varBindList, &errorStatus, &errorIndex); // printf("# of adapters in this system : %i\n", -// varBind[0].value.asnValue.number); varBindList.len = 2; +// varBind[0].value.asnValue.number); + varBindList.len = 2; // Copy in the OID of ifType, the type of interface SNMP_oidcpy(&varBind[0].name, &MIB_ifEntryType); @@ -472,7 +680,6 @@ long GetMacAddrSys ( unsigned char *addr) { j++; dtmp = varBind[0].value.asnValue.number; - printf("Interface #%i type : %i\n", j, dtmp); // Type 6 describes ethernet interfaces if (dtmp == 6) @@ -489,7 +696,8 @@ long GetMacAddrSys ( unsigned char *addr) && (varBind[1].value.asnValue.address.stream[4] == 0x00) ) { // Ignore all dial-up networking adapters - printf("Interface #%i is a DUN adapter\n", j); + std::cerr << "in Get MAC Adress (internal) : Interface #" + << j << " is a DUN adapter\n"; continue; } if ( (varBind[1].value.asnValue.address.stream[0] == 0x00) @@ -501,7 +709,8 @@ long GetMacAddrSys ( unsigned char *addr) { // Ignore NULL addresses returned by other network // interfaces - printf("Interface #%i is a NULL address\n", j); + std::cerr << "in Get MAC Adress (internal) : Interface #" + << j << " is a NULL address\n"; continue; } memcpy( addr, varBind[1].value.asnValue.address.stream, 6); @@ -516,58 +725,52 @@ long GetMacAddrSys ( unsigned char *addr) return 0; #endif //Win32 version +#if defined(__sgi) + return SGIGetMacAddress(addr); +#endif // __sgi + // implementation for POSIX system -#ifdef __sun +#if defined(CMAKE_HAVE_NET_IF_ARP_H) && defined(__sun) //The POSIX version is broken anyway on Solaris, plus would require full //root power - int i; struct arpreq parpreq; - struct sockaddr_in sa, *psa; - struct in_addr inaddr; + struct sockaddr_in *psa; struct hostent *phost; char hostname[MAXHOSTNAMELEN]; - unsigned char *ptr; char **paddrs; int sock, status=0; - gethostname(hostname, MAXHOSTNAMELEN); + if (gethostname(hostname, MAXHOSTNAMELEN) != 0 ) + { + perror("in Get MAC Adress (internal) : gethostname"); + return -1; + } phost = gethostbyname(hostname); paddrs = phost->h_addr_list; - //memcpy(&inaddr.s_addr, *paddrs, sizeof(inaddr.s_addr)); sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - - if(sock == -1) + if (sock == -1 ) { - perror("sock"); + 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) + if (status == -1 ) { - perror("SIOCGARP"); - exit(-1); + perror("in Get MAC Adress (internal) : SIOCGARP"); + return -1; } + memcpy(addr, parpreq.arp_ha.sa_data, 6); - memcpy(addr, parpreq.arp_ha.sa_data, 6); -// printf("MAC Address: %x:%x:%x:%x:%x:%x\n", -// -// parpreq.arp_ha.sa_data[0], -// parpreq.arp_ha.sa_data[1], -// parpreq.arp_ha.sa_data[2], -// parpreq.arp_ha.sa_data[3], -// parpreq.arp_ha.sa_data[4], -// -// parpreq.arp_ha.sa_data[5]); - + return 0; #else #ifdef CMAKE_HAVE_NET_IF_H int sd; @@ -576,7 +779,7 @@ long GetMacAddrSys ( unsigned char *addr) char buf[1024]; int n, i; unsigned char *a; -#ifdef AF_LINK +#if defined(AF_LINK) && (!defined(SIOCGIFHWADDR) && !defined(SIOCGENADDR)) struct sockaddr_dl *sdlp; #endif @@ -585,19 +788,19 @@ long GetMacAddrSys ( unsigned char *addr) // 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 investiage the use of SIZEOF_ADDR_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) + #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) + #define ifreq_size(i) sizeof(struct ifreq) #endif // HAVE_SA_LEN - if( (sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0 ) + if ( (sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0 ) { return -1; } @@ -620,6 +823,11 @@ long GetMacAddrSys ( unsigned char *addr) 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; @@ -630,10 +838,7 @@ long GetMacAddrSys ( unsigned char *addr) continue; a = (unsigned char *) &sdlp->sdl_data[sdlp->sdl_nlen]; #else - /* - * XXX we don't have a way of getting the hardware - * address - */ + perror("in Get MAC Adress (internal) : No way to access hardware"); close(sd); return -1; #endif // AF_LINK @@ -650,170 +855,345 @@ long GetMacAddrSys ( unsigned char *addr) } 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 plateform"); + 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) +{ + int extended, carry = 0; + for(int i=0;i<6;i++) + { + extended = (carry << 8) + data[i]; + data[i] = extended / 10; + carry = extended % 10; + } + return carry; } +/** + * \brief Encode the mac address on a fixed length string of 15 characters. + * we save space this way. + */ std::string Util::GetMACAddress() { - // This is a rip from: http://cplus.kompf.de/macaddr.html for Linux/CYGWIN, HPUX and AIX - // and http://tangentsoft.net/wskfaq/examples/src/snmpmac.cpp for windows version - // and http://groups-beta.google.com/group/sol.lists.freebsd.hackers/msg/0d0f862e05fce6c0 for the FreeBSD version - // and http://developer.apple.com/samplecode/GetPrimaryMACAddress/GetPrimaryMACAddress.html for MacOSX version - u_char addr[6]; - std::string macaddr; - - long stat = GetMacAddrSys(addr); - if (0 == stat) + // 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) { - //printf( "MAC address = "); - for (int i=0; i<6; ++i) + // 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) { - //printf("%2.2x", addr[i]); - macaddr += Format("%2.2x", addr[i]); + 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); } - //printf( "\n"); - return macaddr; + + return sres; } else { - //printf( "No MAC address !\n" ); + gdcmStaticWarningMacro("Problem in finding the MAC Address"); return ""; } } /** - * \ingroup Util - * \brief Return the IP adress of the machine writting the DICOM image + * \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::GetIPAddress() +std::string Util::CreateUniqueUID(const std::string &root) { - // 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; jh_length; j++ ) - { - if( j > 0 ) str += "."; + std::string prefix; + std::string append; + if ( root.empty() ) + { + // gdcm UID prefix, as supplied by http://www.medicalconnections.co.uk + prefix = RootUID; + } + else + { + prefix = root; + } - str += Util::Format("%u", - (unsigned int)((unsigned char*)pHost->h_addr_list[i])[j]); - } - // str now contains one local IP address + // A root was specified use it to forge our new UID: + append += "."; + //append += Util::GetMACAddress(); // to save CPU time + append += Util::GDCM_MAC_ADRESS; + append += "."; + append += Util::GetCurrentDateTime(); + append += "."; + //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 ) + { + gdcmStaticErrorMacro( "Size of UID is too long." ); + // we need a hash function to truncate this number + // if only md5 was cross plateform + // MD5(append); + } -#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; + return prefix + append; } -/** - * \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) +void Util::SetRootUID(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; + if ( root.empty() ) + RootUID = GDCM_UID; + else + RootUID = root; } -template -std::ostream &binary_write(std::ostream &os, const T &val) +const std::string &Util::GetRootUID() { - return os.write(reinterpret_cast(&val), sizeof val); + return RootUID; } +//------------------------------------------------------------------------- +/** + * \brief binary_write binary_write + * @param os ostream to write to + * @param val 16 bits value to write + */ std::ostream &binary_write(std::ostream &os, const uint16_t &val) { -#ifdef GDCM_WORDS_BIGENDIAN - uint16_t swap; - swap = ((( val << 8 ) & 0x0ff00 ) | (( val >> 8 ) & 0x00ff ) ); - return os.write(reinterpret_cast(&swap), 2); +#if defined(GDCM_WORDS_BIGENDIAN) || defined(GDCM_FORCE_BIGENDIAN_EMULATION) + uint16_t swap; + swap = ( val << 8 | val >> 8 ); + + return os.write(reinterpret_cast(&swap), 2); #else - return os.write(reinterpret_cast(&val), 2); + return os.write(reinterpret_cast(&val), 2); #endif //GDCM_WORDS_BIGENDIAN } +/** + * \brief binary_write binary_write + * @param os ostream to write to + * @param val 32 bits value to write + */ std::ostream &binary_write(std::ostream &os, const uint32_t &val) { -#ifdef GDCM_WORDS_BIGENDIAN - uint32_t swap; - swap = ( ((val<<24) & 0xff000000) | ((val<<8) & 0x00ff0000) | - ((val>>8) & 0x0000ff00) | ((val>>24) & 0x000000ff) ); - return os.write(reinterpret_cast(&swap), 4); +#if defined(GDCM_WORDS_BIGENDIAN) || defined(GDCM_FORCE_BIGENDIAN_EMULATION) + uint32_t swap; + swap = ( (val<<24) | ((val<<8) & 0x00ff0000) | + ((val>>8) & 0x0000ff00) | (val>>24) ); + return os.write(reinterpret_cast(&swap), 4); #else - return os.write(reinterpret_cast(&val), 4); + return os.write(reinterpret_cast(&val), 4); #endif //GDCM_WORDS_BIGENDIAN } +/** + * \brief binary_write binary_write + * @param os ostream to write to + * @param val double (64 bits) value to write + */ +std::ostream &binary_write(std::ostream &os, const double &val) +{ +#if defined(GDCM_WORDS_BIGENDIAN) || defined(GDCM_FORCE_BIGENDIAN_EMULATION) + double swap = val; + + char *beg = (char *)&swap; + char *end = beg + 7; + char t; + for (unsigned int i = 0; i<7; i++) + { + t = *beg; + *beg = *end; + *end = t; + beg++, + end--; + } + return os.write(reinterpret_cast(&swap), 8); +#else + return os.write(reinterpret_cast(&val), 8); +#endif //GDCM_WORDS_BIGENDIAN +} + +/** + * \brief binary_write binary_write + * @param os ostream to write to + * @param val 8 bits characters aray to write + */ std::ostream &binary_write(std::ostream &os, const char *val) { - return os.write(val, strlen(val)); + return os.write(val, strlen(val)); } +/** + * \brief binary_write binary_write + * @param os ostream to write to + * @param val std::string value to write + */ std::ostream &binary_write(std::ostream &os, std::string const &val) { - return os.write(val.c_str(), val.size()); + return os.write(val.c_str(), val.size()); +} + +/** + * \brief binary_write binary_write + * @param os ostream to write to + * @param val 8 bits 'characters' aray to write + * @param len length of the 'value' to be written + */ +std::ostream &binary_write(std::ostream &os, const uint8_t *val, size_t len) +{ + // We are writting sizeof(char) thus no need to swap bytes + return os.write(reinterpret_cast(val), len); +} + +/** + * \brief binary_write binary_write + * @param os ostream to write to + * @param val 16 bits words aray to write + * @param len length (in bytes) of the 'value' to be written + */ +std::ostream &binary_write(std::ostream &os, const uint16_t *val, size_t len) +{ +// This is tricky since we are writting two bytes buffer. +// Be carefull with little endian vs big endian. +// Also this other trick is to allocate a small (efficient) buffer that store +// intermediate result before writting it. +#if defined(GDCM_WORDS_BIGENDIAN) || defined(GDCM_FORCE_BIGENDIAN_EMULATION) + const int BUFFER_SIZE = 4096; + static char buffer[BUFFER_SIZE]; + uint16_t *binArea16 = (uint16_t*)val; //for the const + + // how many BUFFER_SIZE long pieces in binArea ? + int nbPieces = len/BUFFER_SIZE; //(16 bits = 2 Bytes) + int remainingSize = len%BUFFER_SIZE; + + for (int j=0;j> 8 | *binArea16 << 8; + pbuffer++; + binArea16++; + } + os.write ( buffer, BUFFER_SIZE ); + } + if ( remainingSize > 0) + { + uint16_t *pbuffer = (uint16_t*)buffer; //reinitialize pbuffer + for (int i = 0; i < remainingSize/2; i++) + { + *pbuffer = *binArea16 >> 8 | *binArea16 << 8; + pbuffer++; + binArea16++; + } + os.write ( buffer, remainingSize ); + } + return os; +#else + return os.write(reinterpret_cast(val), len); +#endif +} + +//------------------------------------------------------------------------- +// Protected + +//------------------------------------------------------------------------- +// Private +/** + * \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__) || defined(__MINGW32__) + // with WinSock DLL we need to initialize 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; jh_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__) || defined(__MINGW32__) + WSACleanup(); +#endif + + } + } + // If an error occur r == -1 + // Most of the time it will return 127.0.0.1... + return str; +} + +void Util::hfpswap(double *a, double *b) +{ + double tmp; + tmp=*a; + *a=*b; + *b=tmp; } +//------------------------------------------------------------------------- } // end namespace gdcm