]> Creatis software - gdcm.git/blob - src/gdcmUtil.cxx
559b21ee0be8ab6ab5fc2f11f28799d73b1844c3
[gdcm.git] / src / gdcmUtil.cxx
1 /*=========================================================================
2                                                                                 
3   Program:   gdcm
4   Module:    $RCSfile: gdcmUtil.cxx,v $
5   Language:  C++
6   Date:      $Date: 2005/01/15 22:19:10 $
7   Version:   $Revision: 1.95 $
8                                                                                 
9   Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
10   l'Image). All rights reserved. See Doc/License.txt or
11   http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details.
12                                                                                 
13      This software is distributed WITHOUT ANY WARRANTY; without even
14      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15      PURPOSE.  See the above copyright notices for more information.
16                                                                                 
17 =========================================================================*/
18
19 #include "gdcmUtil.h"
20 #include "gdcmDebug.h"
21 #include <iostream>
22
23 // For GetCurrentDate, GetCurrentTime
24 #include <time.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27
28 #include <stdarg.h>  //only included in implementation file
29 #include <stdio.h>   //only included in implementation file
30
31 #if defined(_MSC_VER)
32    #include <winsock.h>  // for gethostname & gethostbyname
33    #undef GetCurrentTime
34 #else
35 #ifndef __BORLANDC__
36    #include <unistd.h>  // for gethostname
37    #include <netdb.h>   // for gethostbyname
38 #endif
39 #endif
40
41 // For GetMACAddress
42 #ifdef _WIN32
43 #include <snmp.h>
44 #include <conio.h>
45 #else
46 #include <unistd.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <sys/types.h>
50 #endif
51
52 #ifdef __sun
53 //#include <time.h>
54 #include <netdb.h>
55 #include <arpa/inet.h>
56 #include <net/if_arp.h>
57 #else
58 //#include <fcntl.h>
59 //#include <errno.h>
60 //#include <sys/time.h>
61 #include <sys/stat.h>
62 #include <sys/file.h>
63 #endif //__sun
64
65 // How do I do that in CMake ?
66 #ifdef __APPLE__
67 #define HAVE_SA_LEN
68 #define CMAKE_HAVE_NET_IF_DL_H
69 #define CMAKE_HAVE_NETINET_IN_H
70 #define CMAKE_HAVE_NET_IF_H
71 #endif //APPLE
72
73 #ifdef CMAKE_HAVE_SYS_IOCTL_H
74 #include <sys/ioctl.h>  // For SIOCGIFCONF on Linux
75 #endif
76 #ifdef CMAKE_HAVE_SYS_SOCKET_H
77 #include <sys/socket.h>
78 #endif
79 #ifdef CMAKE_HAVE_SYS_SOCKIO_H
80 #include <sys/sockio.h>  // For SIOCGIFCONF on SunOS
81 #endif
82 #ifdef CMAKE_HAVE_NET_IF_H
83 #include <net/if.h>
84 #endif
85 #ifdef CMAKE_HAVE_NETINET_IN_H
86 #include <netinet/in.h>   //For IPPROTO_IP
87 #endif
88 #ifdef CMAKE_HAVE_NET_IF_DL_H
89 #include <net/if_dl.h>
90 #endif
91
92
93 namespace gdcm 
94 {
95 /**
96  * \ingroup Globals
97  * \brief Provide a better 'c++' approach for sprintf
98  * For example c code is:
99  * sprintf(trash, "%04x|%04x", group , elem);
100  *
101  * c++ code is 
102  * std::ostringstream buf;
103  * buf << std::right << std::setw(4) << std::setfill('0') << std::hex
104  *     << group << "|" << std::right << std::setw(4) << std::setfill('0') 
105  *     << std::hex <<  elem;
106  * buf.str();
107  *
108  * gdcm style code is
109  * Format("%04x|%04x", group , elem);
110  */
111
112 std::string Util::Format(const char *format, ...)
113 {
114    char buffer[2048];
115    va_list args;
116    va_start(args, format);
117    vsprintf(buffer, format, args);  //might be a security flaw
118    va_end(args); // Each invocation of va_start should be matched 
119                  // by a corresponding invocation of va_end
120                  // args is then 'undefined'
121    return buffer;
122 }
123
124
125 /**
126  * \ingroup Globals
127  * \brief Because not available in C++ (?)
128  */
129 void Util::Tokenize (const std::string &str,
130                      std::vector<std::string> &tokens,
131                      const std::string& delimiters)
132 {
133    std::string::size_type lastPos = str.find_first_not_of(delimiters,0);
134    std::string::size_type pos     = str.find_first_of    (delimiters,lastPos);
135    while (std::string::npos != pos || std::string::npos != lastPos)
136    {
137       tokens.push_back(str.substr(lastPos, pos - lastPos));
138       lastPos = str.find_first_not_of(delimiters, pos);
139       pos     = str.find_first_of    (delimiters, lastPos);
140    }
141 }
142
143 /**
144  * \ingroup Globals
145  * \brief Because not available in C++ (?)
146  *        Counts the number of occurences of a substring within a string
147  */
148  
149 int Util::CountSubstring (const std::string &str,
150                           const std::string &subStr)
151 {
152    int count = 0;   // counts how many times it appears
153    std::string::size_type x = 0;       // The index position in the string
154
155    do
156    {
157       x = str.find(subStr,x);       // Find the substring
158       if (x != std::string::npos)   // If present
159       {
160          count++;                  // increase the count
161          x += subStr.length();     // Skip this word
162       }
163    }
164    while (x != std::string::npos);  // Carry on until not present
165
166    return count;
167 }
168
169 /**
170  * \ingroup Globals
171  * \brief  Weed out a string from the non-printable characters (in order
172  *         to avoid corrupting the terminal of invocation when printing)
173  * @param s string to remove non printable characters from
174  */
175 std::string Util::CreateCleanString(std::string const &s)
176 {
177    std::string str = s;
178
179    for(unsigned int i=0; i<str.size(); i++)
180    {
181       if(!isprint((unsigned char)str[i]))
182       {
183          str[i] = '.';
184       }
185    }
186
187    if(str.size() > 0)
188    {
189       if(!isprint((unsigned char)s[str.size()-1]))
190       {
191          if(s[str.size()-1] == 0)
192          {
193             str[str.size()-1] = ' ';
194          }
195       }
196    }
197
198    return str;
199 }
200
201 /**
202  * \ingroup Globals
203  * \brief   Add a SEPARATOR to the end of the name is necessary
204  * @param   pathname file/directory name to normalize 
205  */
206 std::string Util::NormalizePath(std::string const &pathname)
207 {
208    const char SEPARATOR_X      = '/';
209    const char SEPARATOR_WIN    = '\\';
210    const std::string SEPARATOR = "/";
211    std::string name = pathname;
212    int size = name.size();
213
214    if( name[size-1] != SEPARATOR_X && name[size-1] != SEPARATOR_WIN )
215    {
216       name += SEPARATOR;
217    }
218    return name;
219 }
220
221 /**
222  * \ingroup Globals
223  * \brief   Get the (directory) path from a full path file name
224  * @param   fullName file/directory name to extract Path from
225  */
226 std::string Util::GetPath(std::string const &fullName)
227 {
228    std::string res = fullName;
229    int pos1 = res.rfind("/");
230    int pos2 = res.rfind("\\");
231    if( pos1 > pos2)
232    {
233       res.resize(pos1);
234    }
235    else
236    {
237       res.resize(pos2);
238    }
239
240    return res;
241 }
242
243 /**
244  * \ingroup Util
245  * \brief   Get the (last) name of a full path file name
246  * @param   fullName file/directory name to extract end name from
247  */
248 std::string Util::GetName(std::string const &fullName)
249 {   
250   std::string filename = fullName;
251
252   std::string::size_type slash_pos = filename.rfind("/");
253   std::string::size_type backslash_pos = filename.rfind("\\");
254   slash_pos = slash_pos > backslash_pos ? slash_pos : backslash_pos;
255   if(slash_pos != std::string::npos)
256     {
257     return filename.substr(slash_pos + 1);
258     }
259   else
260     {
261     return filename;
262     }
263
264
265 /**
266  * \ingroup Util
267  * \brief   Get the current date of the system in a dicom string
268  */
269 std::string Util::GetCurrentDate()
270 {
271     char tmp[512];
272     time_t tloc;
273     time (&tloc);    
274     strftime(tmp,512,"%Y%m%d", localtime(&tloc) );
275     return tmp;
276 }
277
278 /**
279  * \ingroup Util
280  * \brief   Get the current time of the system in a dicom string
281  */
282 std::string Util::GetCurrentTime()
283 {
284     char tmp[512];
285     time_t tloc;
286     time (&tloc);
287     strftime(tmp,512,"%H%M%S", localtime(&tloc) );
288     return tmp;  
289 }
290
291 /**
292  * \brief Create a /DICOM/ string:
293  * It should a of even length (no odd length ever)
294  * It can contain as many (if you are reading this from your
295  * editor the following character is is backslash followed by zero
296  * that needed to be escaped with an extra backslash for doxygen) \\0
297  * as you want.
298  */
299 std::string Util::DicomString(const char *s, size_t l)
300 {
301    std::string r(s, s+l);
302    gdcmAssertMacro( !(r.size() % 2) ); // == basically 'l' is even
303    return r;
304 }
305
306 /**
307  * \ingroup Util
308  * \brief Create a /DICOM/ string:
309  * It should a of even lenght (no odd length ever)
310  * It can contain as many (if you are reading this from your
311  * editor the following character is is backslash followed by zero
312  * that needed to be escaped with an extra backslash for doxygen) \\0
313  * as you want.
314  * This function is similar to DicomString(const char*), 
315  * except it doesn't take a lenght. 
316  * It only pad with a null character if length is odd
317  */
318 std::string Util::DicomString(const char *s)
319 {
320    size_t l = strlen(s);
321    if( l%2 )
322    {
323       l++;
324    }
325    std::string r(s, s+l);
326    gdcmAssertMacro( !(r.size() % 2) );
327    return r;
328 }
329
330 /**
331  * \ingroup Util
332  * \brief Safely compare two Dicom String:
333  *        - Both string should be of even lenght
334  *        - We allow padding of even lenght string by either a null 
335  *          character of a space
336  */
337 bool Util::DicomStringEqual(const std::string &s1, const char *s2)
338 {
339   // s2 is the string from the DICOM reference: 'MONOCHROME1'
340   std::string s1_even = s1; //Never change input parameter
341   std::string s2_even = DicomString( s2 );
342   if( s1_even[s1_even.size()-1] == ' ')
343   {
344     s1_even[s1_even.size()-1] = '\0'; //replace space character by null
345   }
346   return s1_even == s2_even;
347 }
348
349
350
351 /**
352  * \ingroup Util
353  * \brief   tells us if the processor we are working with is BigEndian or not
354  */
355 bool Util::IsCurrentProcessorBigEndian()
356 {
357 #ifdef GDCM_WORDS_BIGENDIAN
358    return true;
359 #else
360    return false;
361 #endif
362 }
363
364
365
366 #ifdef _WIN32
367 typedef BOOL(WINAPI * pSnmpExtensionInit) (
368         IN DWORD dwTimeZeroReference,
369         OUT HANDLE * hPollForTrapEvent,
370         OUT AsnObjectIdentifier * supportedView);
371
372 typedef BOOL(WINAPI * pSnmpExtensionTrap) (
373         OUT AsnObjectIdentifier * enterprise,
374         OUT AsnInteger * genericTrap,
375         OUT AsnInteger * specificTrap,
376         OUT AsnTimeticks * timeStamp,
377         OUT RFC1157VarBindList * variableBindings);
378
379 typedef BOOL(WINAPI * pSnmpExtensionQuery) (
380         IN BYTE requestType,
381         IN OUT RFC1157VarBindList * variableBindings,
382         OUT AsnInteger * errorStatus,
383         OUT AsnInteger * errorIndex);
384
385 typedef BOOL(WINAPI * pSnmpExtensionInitEx) (
386         OUT AsnObjectIdentifier * supportedView);
387 #endif //_WIN32
388
389
390 long GetMacAddrSys ( unsigned char *addr)
391 {
392 #ifdef _WIN32
393    WSADATA WinsockData;
394    if (WSAStartup(MAKEWORD(2, 0), &WinsockData) != 0) 
395    {
396       std::cerr << "This program requires Winsock 2.x!" << std::endl;
397       return -1;
398    }
399
400    HANDLE PollForTrapEvent;
401    AsnObjectIdentifier SupportedView;
402    UINT OID_ifEntryType[] = { 1, 3, 6, 1, 2, 1, 2, 2, 1, 3 };
403    UINT OID_ifEntryNum[] = { 1, 3, 6, 1, 2, 1, 2, 1 };
404    UINT OID_ipMACEntAddr[] = { 1, 3, 6, 1, 2, 1, 2, 2, 1, 6 };
405    AsnObjectIdentifier MIB_ifMACEntAddr = {
406        sizeof(OID_ipMACEntAddr) / sizeof(UINT), OID_ipMACEntAddr };
407    AsnObjectIdentifier MIB_ifEntryType = {
408        sizeof(OID_ifEntryType) / sizeof(UINT), OID_ifEntryType };
409    AsnObjectIdentifier MIB_ifEntryNum = {
410        sizeof(OID_ifEntryNum) / sizeof(UINT), OID_ifEntryNum };
411    RFC1157VarBindList varBindList;
412    RFC1157VarBind varBind[2];
413    AsnInteger errorStatus;
414    AsnInteger errorIndex;
415    AsnObjectIdentifier MIB_NULL = { 0, 0 };
416    int ret;
417    int dtmp;
418    int i = 0, j = 0;
419    BOOL found = FALSE;
420
421    // Load the SNMP dll and get the addresses of the functions necessary
422    HINSTANCE m_hInst = LoadLibrary("inetmib1.dll");
423    if (m_hInst < (HINSTANCE) HINSTANCE_ERROR)
424    {
425       m_hInst = NULL;
426       return -1;
427    }
428    pSnmpExtensionInit m_Init =
429        (pSnmpExtensionInit) GetProcAddress(m_hInst, "SnmpExtensionInit");
430    pSnmpExtensionInitEx m_InitEx =
431        (pSnmpExtensionInitEx) GetProcAddress(m_hInst, "SnmpExtensionInitEx");
432    pSnmpExtensionQuery m_Query =
433        (pSnmpExtensionQuery) GetProcAddress(m_hInst, "SnmpExtensionQuery");
434    pSnmpExtensionTrap m_Trap =
435        (pSnmpExtensionTrap) GetProcAddress(m_hInst, "SnmpExtensionTrap");
436    m_Init(GetTickCount(), &PollForTrapEvent, &SupportedView);
437
438    /* Initialize the variable list to be retrieved by m_Query */
439    varBindList.list = varBind;
440    varBind[0].name = MIB_NULL;
441    varBind[1].name = MIB_NULL;
442
443    // Copy in the OID to find the number of entries in the
444    // Inteface table
445    varBindList.len = 1;        // Only retrieving one item
446    SNMP_oidcpy(&varBind[0].name, &MIB_ifEntryNum);
447    ret = m_Query(ASN_RFC1157_GETNEXTREQUEST, &varBindList, &errorStatus,
448                  &errorIndex);
449 //   printf("# of adapters in this system : %i\n",
450 //          varBind[0].value.asnValue.number); varBindList.len = 2;
451
452    // Copy in the OID of ifType, the type of interface
453    SNMP_oidcpy(&varBind[0].name, &MIB_ifEntryType);
454
455    // Copy in the OID of ifPhysAddress, the address
456    SNMP_oidcpy(&varBind[1].name, &MIB_ifMACEntAddr);
457
458    do
459    {
460       // Submit the query.  Responses will be loaded into varBindList.
461       // We can expect this call to succeed a # of times corresponding
462       // to the # of adapters reported to be in the system
463       ret = m_Query(ASN_RFC1157_GETNEXTREQUEST, &varBindList, &errorStatus,
464                     &errorIndex); 
465       if (!ret)
466       {
467          ret = 1;
468       }
469       else
470       {
471          // Confirm that the proper type has been returned
472          ret = SNMP_oidncmp(&varBind[0].name, &MIB_ifEntryType,
473                             MIB_ifEntryType.idLength);
474       }
475       if (!ret)
476       {
477          j++;
478          dtmp = varBind[0].value.asnValue.number;
479          printf("Interface #%i type : %i\n", j, dtmp);
480
481          // Type 6 describes ethernet interfaces
482          if (dtmp == 6)
483          {
484             // Confirm that we have an address here
485             ret = SNMP_oidncmp(&varBind[1].name, &MIB_ifMACEntAddr,
486                                MIB_ifMACEntAddr.idLength);
487             if ( !ret && varBind[1].value.asnValue.address.stream != NULL )
488             {
489                if ( (varBind[1].value.asnValue.address.stream[0] == 0x44)
490                  && (varBind[1].value.asnValue.address.stream[1] == 0x45)
491                  && (varBind[1].value.asnValue.address.stream[2] == 0x53)
492                  && (varBind[1].value.asnValue.address.stream[3] == 0x54)
493                  && (varBind[1].value.asnValue.address.stream[4] == 0x00) )
494                {
495                    // Ignore all dial-up networking adapters
496                    printf("Interface #%i is a DUN adapter\n", j);
497                    continue;
498                }
499                if ( (varBind[1].value.asnValue.address.stream[0] == 0x00)
500                  && (varBind[1].value.asnValue.address.stream[1] == 0x00)
501                  && (varBind[1].value.asnValue.address.stream[2] == 0x00)
502                  && (varBind[1].value.asnValue.address.stream[3] == 0x00)
503                  && (varBind[1].value.asnValue.address.stream[4] == 0x00)
504                  && (varBind[1].value.asnValue.address.stream[5] == 0x00) )
505                {
506                   // Ignore NULL addresses returned by other network
507                   // interfaces
508                   printf("Interface #%i is a NULL address\n", j);
509                   continue;
510                }
511                memcpy( addr, varBind[1].value.asnValue.address.stream, 6);
512             }
513          }
514       }
515    } while (!ret);
516
517    // Free the bindings
518    SNMP_FreeVarBind(&varBind[0]);
519    SNMP_FreeVarBind(&varBind[1]);
520    return 0;
521 #endif //Win32 version
522
523
524 // implementation for POSIX system
525 #ifdef __sun
526    //The POSIX version is broken anyway on Solaris, plus would require full
527    //root power
528    int                     i;
529    struct  arpreq          parpreq;
530    struct  sockaddr_in     sa, *psa;
531    struct  in_addr         inaddr;
532    struct  hostent         *phost;
533    char                    hostname[MAXHOSTNAMELEN];
534    unsigned char           *ptr;
535    char                    **paddrs;
536    int                     sock, status=0;
537
538    gethostname(hostname,  MAXHOSTNAMELEN);
539    phost = gethostbyname(hostname);
540    paddrs = phost->h_addr_list;
541
542    //memcpy(&inaddr.s_addr, *paddrs, sizeof(inaddr.s_addr));
543    sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
544
545    if(sock == -1)
546    {
547       perror("sock");
548       return -1;
549    }
550    memset(&parpreq, 0, sizeof(struct arpreq));
551    psa = (struct sockaddr_in *) &parpreq.arp_pa;
552    memset(psa, 0, sizeof(struct sockaddr_in));
553    psa->sin_family = AF_INET;
554    memcpy(&psa->sin_addr, *paddrs, sizeof(struct in_addr));
555
556    status = ioctl(sock, SIOCGARP, &parpreq);
557
558    if(status == -1)
559    {
560       perror("SIOCGARP");
561       //exit(-1);
562       return -1;
563    }
564
565     memcpy(addr, parpreq.arp_ha.sa_data, 6);
566 //    printf("MAC Address: %x:%x:%x:%x:%x:%x\n",
567 //
568 //           parpreq.arp_ha.sa_data[0],
569 //           parpreq.arp_ha.sa_data[1],
570 //           parpreq.arp_ha.sa_data[2],
571 //           parpreq.arp_ha.sa_data[3],
572 //           parpreq.arp_ha.sa_data[4],
573 //
574 //            parpreq.arp_ha.sa_data[5]);
575
576    return 0;
577 #else
578 #ifdef CMAKE_HAVE_NET_IF_H
579    int       sd;
580    struct ifreq    ifr, *ifrp;
581    struct ifconf    ifc;
582    char buf[1024];
583    int      n, i;
584    unsigned char    *a;
585 #ifdef AF_LINK
586    struct sockaddr_dl *sdlp;
587 #endif
588
589 //
590 // BSD 4.4 defines the size of an ifreq to be
591 // max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len
592 // However, under earlier systems, sa_len isn't present, so the size is 
593 // just sizeof(struct ifreq)
594 // We should investiage the use of SIZEOF_ADDR_IFREQ
595 //
596 #ifdef HAVE_SA_LEN
597 #ifndef max
598 #define max(a,b) ((a) > (b) ? (a) : (b))
599 #endif
600 #define ifreq_size(i) max(sizeof(struct ifreq),\
601      sizeof((i).ifr_name)+(i).ifr_addr.sa_len)
602 #else
603 #define ifreq_size(i) sizeof(struct ifreq)
604 #endif // HAVE_SA_LEN
605
606    if( (sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0 )
607    {
608       return -1;
609    }
610    memset(buf, 0, sizeof(buf));
611    ifc.ifc_len = sizeof(buf);
612    ifc.ifc_buf = buf;
613    if (ioctl (sd, SIOCGIFCONF, (char *)&ifc) < 0)
614    {
615       close(sd);
616       return -1;
617    }
618    n = ifc.ifc_len;
619    for (i = 0; i < n; i+= ifreq_size(*ifrp) )
620    {
621       ifrp = (struct ifreq *)((char *) ifc.ifc_buf+i);
622       strncpy(ifr.ifr_name, ifrp->ifr_name, IFNAMSIZ);
623 #ifdef SIOCGIFHWADDR
624       if (ioctl(sd, SIOCGIFHWADDR, &ifr) < 0)
625          continue;
626       a = (unsigned char *) &ifr.ifr_hwaddr.sa_data;
627 #else
628 #ifdef SIOCGENADDR
629       if (ioctl(sd, SIOCGENADDR, &ifr) < 0)
630          continue;
631       a = (unsigned char *) ifr.ifr_enaddr;
632 #else
633 #ifdef AF_LINK
634       sdlp = (struct sockaddr_dl *) &ifrp->ifr_addr;
635       if ((sdlp->sdl_family != AF_LINK) || (sdlp->sdl_alen != 6))
636          continue;
637       a = (unsigned char *) &sdlp->sdl_data[sdlp->sdl_nlen];
638 #else
639       /*
640        * XXX we don't have a way of getting the hardware
641        * address
642        */
643       close(sd);
644       return -1;
645 #endif // AF_LINK
646 #endif // SIOCGENADDR
647 #endif // SIOCGIFHWADDR
648       if (!a[0] && !a[1] && !a[2] && !a[3] && !a[4] && !a[5]) continue;
649
650       if (addr) 
651       {
652          memcpy(addr, a, 6);
653          close(sd);
654          return 0;
655       }
656    }
657    close(sd);
658 #endif
659    return -1;
660 #endif //__sun
661
662 }
663
664 std::string Util::GetMACAddress()
665 {
666    // This is a rip from: http://cplus.kompf.de/macaddr.html for Linux/CYGWIN, HPUX and AIX 
667    // and http://tangentsoft.net/wskfaq/examples/src/snmpmac.cpp for windows version
668    // and http://groups-beta.google.com/group/sol.lists.freebsd.hackers/msg/0d0f862e05fce6c0 for the FreeBSD version
669    // and http://developer.apple.com/samplecode/GetPrimaryMACAddress/GetPrimaryMACAddress.html for MacOSX version
670    u_char addr[6];
671    std::string macaddr;
672  
673    long stat = GetMacAddrSys(addr);
674    if (0 == stat)
675    {
676       //printf( "MAC address = ");
677       for (int i=0; i<6; ++i) 
678       {
679          //printf("%2.2x", addr[i]);
680          macaddr += Format("%2.2x", addr[i]);
681       }
682        //printf( "\n");
683       return macaddr;
684    }
685    else
686    {
687       //printf( "No MAC address !\n" );
688       return "";
689    }
690 }
691
692 /**
693  * \ingroup Util
694  * \brief   Return the IP adress of the machine writting the DICOM image
695  */
696 std::string Util::GetIPAddress()
697 {
698   // This is a rip from 
699   // http://www.codeguru.com/Cpp/I-N/internet/network/article.php/c3445/
700 #ifndef HOST_NAME_MAX
701   // SUSv2 guarantees that `Host names are limited to 255 bytes'.
702   // POSIX 1003.1-2001 guarantees that `Host names (not including the
703   // terminating NUL) are limited to HOST_NAME_MAX bytes'.
704 #  define HOST_NAME_MAX 255
705   // In this case we should maybe check the string was not truncated.
706   // But I don't known how to check that...
707 #if defined(_MSC_VER) || defined(__BORLANDC__)
708   // with WinSock DLL we need to initialise the WinSock before using gethostname
709   WORD wVersionRequested = MAKEWORD(1,0);
710   WSADATA WSAData;
711   int err = WSAStartup(wVersionRequested,&WSAData);
712   if (err != 0)
713   {
714       // Tell the user that we could not find a usable
715       // WinSock DLL.
716       WSACleanup();
717       return "127.0.0.1";
718   }
719 #endif
720   
721 #endif //HOST_NAME_MAX
722
723   std::string str;
724   char szHostName[HOST_NAME_MAX+1];
725   int r = gethostname(szHostName, HOST_NAME_MAX);
726
727   if( r == 0 )
728   {
729     // Get host adresses
730     struct hostent *pHost = gethostbyname(szHostName);
731
732     for( int i = 0; pHost!= NULL && pHost->h_addr_list[i]!= NULL; i++ )
733     {
734       for( int j = 0; j<pHost->h_length; j++ )
735       {
736         if( j > 0 ) str += ".";
737
738         str += Util::Format("%u", 
739             (unsigned int)((unsigned char*)pHost->h_addr_list[i])[j]);
740       }
741       // str now contains one local IP address 
742
743 #if defined(_MSC_VER) || defined(__BORLANDC__)
744   WSACleanup();
745 #endif
746   
747     }
748   }
749   // If an error occur r == -1
750   // Most of the time it will return 127.0.0.1...
751   return str;
752 }
753
754 /**
755  * \ingroup Util
756  * \brief Creates a new UID. As stipulate in the DICOM ref
757  *        each time a DICOM image is create it should have 
758  *        a unique identifier (URI)
759  */
760 std::string Util::CreateUniqueUID(const std::string &root)
761 {
762   // The code works as follow:
763   // echo "gdcm" | od -b
764   // 0000000 147 144 143 155 012
765   // Therefore we return
766   // radical + 147.144.143.155 + IP + time()
767   std::string radical = root;
768   if( !root.size() ) //anything better ?
769   {
770     radical = "0.0."; // Is this really usefull ?
771   }
772   // else
773   // A root was specified use it to forge our new UID:
774   radical += "147.144.143.155"; // gdcm
775   radical += ".";
776   radical += Util::GetIPAddress();
777   radical += ".";
778   radical += Util::GetCurrentDate();
779   radical += ".";
780   radical += Util::GetCurrentTime();
781
782   return radical;
783 }
784
785 template <class T>
786 std::ostream &binary_write(std::ostream &os, const T &val)
787 {
788     return os.write(reinterpret_cast<const char*>(&val), sizeof val);
789 }
790
791 std::ostream &binary_write(std::ostream &os, const uint16_t &val)
792 {
793 #ifdef GDCM_WORDS_BIGENDIAN
794     uint16_t swap;
795     swap = ((( val << 8 ) & 0x0ff00 ) | (( val >> 8 ) & 0x00ff ) );
796     return os.write(reinterpret_cast<const char*>(&swap), 2);
797 #else
798     return os.write(reinterpret_cast<const char*>(&val), 2);
799 #endif //GDCM_WORDS_BIGENDIAN
800 }
801
802 std::ostream &binary_write(std::ostream &os, const uint32_t &val)
803 {
804 #ifdef GDCM_WORDS_BIGENDIAN
805     uint32_t swap;
806     swap = ( ((val<<24) & 0xff000000) | ((val<<8)  & 0x00ff0000) | 
807              ((val>>8)  & 0x0000ff00) | ((val>>24) & 0x000000ff) );
808     return os.write(reinterpret_cast<const char*>(&swap), 4);
809 #else
810     return os.write(reinterpret_cast<const char*>(&val), 4);
811 #endif //GDCM_WORDS_BIGENDIAN
812 }
813
814 std::ostream &binary_write(std::ostream &os, const char *val)
815 {
816     return os.write(val, strlen(val));
817 }
818
819 std::ostream &binary_write(std::ostream &os, std::string const &val)
820 {
821     return os.write(val.c_str(), val.size());
822 }
823
824 } // end namespace gdcm
825