]> Creatis software - gdcm.git/blob - src/gdcmUtil.cxx
BUG: map<>::mapped_type is not part of the STL. Should fix issue on VS* compiler
[gdcm.git] / src / gdcmUtil.cxx
1 /*=========================================================================
2                                                                                 
3   Program:   gdcm
4   Module:    $RCSfile: gdcmUtil.cxx,v $
5   Language:  C++
6   Date:      $Date: 2007/10/17 08:57:55 $
7   Version:   $Revision: 1.189 $
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
22 #include <iostream>
23 #include <stdarg.h> // for va_list
24
25 // For GetCurrentDate, GetCurrentTime
26 #include <time.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29
30 #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__)
31 #include <sys/timeb.h>
32 #else
33 #include <sys/time.h>
34 #endif
35
36 #include <stdarg.h>  //only included in implementation file
37 #include <stdio.h>   //only included in implementation file
38
39 #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__)
40    #include <winsock.h>  // for gethostname and gethostbyname and GetTickCount...
41 // I haven't find a way to determine wether we need to under GetCurrentTime or not...
42 // I think the best solution would simply to get rid of this problematic function
43 // and use a 'less' common name...
44 #if !defined(__BORLANDC__) || (__BORLANDC__ >= 0x0560)
45    #undef GetCurrentTime
46 #endif
47 #else
48    #include <unistd.h>  // for gethostname
49    #include <netdb.h>   // for gethostbyname
50 #endif
51
52 // For GetMACAddress
53 #ifdef _WIN32
54    #include <snmp.h>
55    #include <conio.h>
56 #else
57    #include <unistd.h>
58    #include <stdlib.h>
59    #include <string.h>
60    #include <sys/types.h>
61 #endif
62
63 #ifdef CMAKE_HAVE_SYS_IOCTL_H
64    #include <sys/ioctl.h>  // For SIOCGIFCONF on Linux
65 #endif
66 #ifdef CMAKE_HAVE_SYS_SOCKET_H
67    #include <sys/socket.h>
68 #endif
69 #ifdef CMAKE_HAVE_SYS_SOCKIO_H
70    #include <sys/sockio.h>  // For SIOCGIFCONF on SunOS
71 #endif
72 #ifdef CMAKE_HAVE_NET_IF_H
73    #include <net/if.h>
74 #endif
75 #ifdef CMAKE_HAVE_NETINET_IN_H
76    #include <netinet/in.h>   //For IPPROTO_IP
77 #endif
78 #ifdef CMAKE_HAVE_NET_IF_DL_H
79    #include <net/if_dl.h>
80 #endif
81 #if defined(CMAKE_HAVE_NET_IF_ARP_H) && defined(__sun)
82    // This is absolutely necessary on SunOS
83    #include <net/if_arp.h>
84 #endif
85
86 // For GetCurrentThreadID()
87 #ifdef __linux__
88    #include <sys/types.h>
89    #include <linux/unistd.h>
90 #endif
91 #ifdef __sun
92    #include <thread.h>
93 #endif
94
95 namespace GDCM_NAME_SPACE
96 {
97 //-------------------------------------------------------------------------
98 const std::string Util::GDCM_UID = "1.2.826.0.1.3680043.2.1143";
99 std::string Util::RootUID        = GDCM_UID;
100 /*
101  * File Meta Information Version (0002,0001) shall contain a two byte OB 
102  * value consisting of a 0x00 byte, followed by 0x01 byte, and not the 
103  * value 0x0001 encoded as a little endian 16 bit short value, 
104  * which would be the other way around...
105  */
106
107 #if defined(GDCM_WORDS_BIGENDIAN) || defined(GDCM_FORCE_BIGENDIAN_EMULATION)
108    const uint16_t Util::FMIV = 0x0001;
109 #else
110    const uint16_t Util::FMIV = 0x0100;
111 #endif   
112    uint8_t *Util::FileMetaInformationVersion = (uint8_t *)&FMIV;
113
114    std::string Util::GDCM_MAC_ADRESS = GetMACAddress();
115
116 //-------------------------------------------------------------------------
117 // Public
118 /**
119  * \brief Provide a better 'c++' approach for sprintf
120  * For example c code is:
121  * char result[2048]; // hope 2048 is enough
122  * sprintf(result, "%04x|%04x", group , elem);
123  *
124  * c++ code is 
125  * std::ostringstream buf;
126  * buf << std::right << std::setw(4) << std::setfill('0') << std::hex
127  *     << group << "|" << std::right << std::setw(4) << std::setfill('0') 
128  *     << std::hex <<  elem;
129  * buf.str();
130  *
131  * gdcm style code is
132  * string result;
133  * result = gdcm::Util::Format("%04x|%04x", group , elem);
134  */
135 std::string Util::Format(const char *format, ...)
136 {
137    char buffer[2048]; // hope 2048 is enough
138    va_list args;
139    va_start(args, format);
140    vsprintf(buffer, format, args);  //might be a security flaw
141    va_end(args); // Each invocation of va_start should be matched 
142                  // by a corresponding invocation of va_end
143                  // args is then 'undefined'
144    return buffer;
145 }
146
147
148 /**
149  * \brief Because not available in C++ (?)
150  * @param str string to check
151  * @param tokens std::vector to receive the tokenized substrings
152  * @param delimiters string containing the character delimitors
153  
154  */
155 void Util::Tokenize (const std::string &str,
156                      std::vector<std::string> &tokens,
157                      const std::string &delimiters)
158 {
159    std::string::size_type lastPos = str.find_first_not_of(delimiters,0);
160    std::string::size_type pos     = str.find_first_of    (delimiters,lastPos);
161    while (std::string::npos != pos || std::string::npos != lastPos)
162    {
163       tokens.push_back(str.substr(lastPos, pos - lastPos));
164       lastPos = str.find_first_not_of(delimiters, pos);
165       pos     = str.find_first_of    (delimiters, lastPos);
166    }
167 }
168
169 /**
170  * \brief Because not available in C++ (?)
171  *        Counts the number of occurences of a substring within a string
172  * @param str string to check
173  * @param subStr substring to count
174  */
175  
176 int Util::CountSubstring (const std::string &str,
177                           const std::string &subStr)
178 {
179    int count = 0;                 // counts how many times it appears
180    std::string::size_type x = 0;  // The index position in the string
181
182    do
183    {
184       x = str.find(subStr,x);     // Find the substring
185       if (x != std::string::npos) // If present
186       {
187          count++;                 // increase the count
188          x += subStr.length();    // Skip this word
189       }
190    }
191    while (x != std::string::npos);// Carry on until not present
192
193    return count;
194 }
195
196 /**
197  * \brief  Checks whether a 'string' is printable or not (in order
198  *         to avoid corrupting the terminal of invocation when printing)
199  * @param s string to check
200  */
201 bool Util::IsCleanString(std::string const &s)
202 {
203    for(unsigned int i=0; i<s.size(); i++)
204    {
205       if (!isprint((unsigned char)s[i]) )
206       {
207          return false;
208       }
209    }
210    return true;   
211 }
212
213 /**
214  * \brief  Checks whether an 'area' is printable or not (in order
215  *         to avoid corrupting the terminal of invocation when printing)
216  * @param s area to check (uint8_t is just for prototyping. feel free to cast)
217  * @param l area length to check
218  */
219 bool Util::IsCleanArea(uint8_t *s, int l)
220 {
221    for( int i=0; i<l; i++)
222    {
223       if (!isprint((unsigned char)s[i]) )
224       {
225          return false;
226       }
227    }
228    return true;   
229 }
230 /**
231  * \brief  Weed out a string from the non-printable characters (in order
232  *         to avoid corrupting the terminal of invocation when printing)
233  * @param s string to check (uint8_t is just for prototyping. feel free to cast)
234  */
235 std::string Util::CreateCleanString(std::string const &s)
236 {
237    std::string str = s;
238
239    for(unsigned int i=0; i<str.size(); i++)
240    {
241       if (!isprint((unsigned char)str[i]) )
242       {
243          str[i] = '.';
244       }
245    }
246    if (str.size() > 0 )
247    {
248       if (!isprint((unsigned char)s[str.size()-1]) )
249       {
250          if (s[str.size()-1] == 0 )
251          {
252             str[str.size()-1] = ' ';
253          }
254       }
255    }
256    return str;
257 }
258 /**
259  * \brief  Replaces all special characters
260  * @param s string to modify
261  * @param rep replacement char
262  */
263 void Util::ReplaceSpecChar(std::string &s, std::string &rep)
264 {
265    unsigned int s_size = s.size();
266    for(unsigned int i=0; i<s_size; i++)
267    {
268       if (! ( s[i] == '.' || s[i] == '%' || s[i] == '_'
269           || (s[i] >= '+' && s[i] <= '-')       
270           || (s[i] >= 'a' && s[i] <= 'z')
271           || (s[i] >= '0' && s[i] <= '9')
272           || (s[i] >= 'A' && s[i] <= 'Z')))
273      {
274         s.replace(i, 1, rep);
275      }
276    }
277       // deal with Dicom strings trailing '\0' 
278    if(s[s_size-1] == rep.c_str()[0])
279       s.erase(s_size-1, 1);
280 }
281
282
283 /**
284  * \brief  Weed out a string from the non-printable characters (in order
285  *         to avoid corrupting the terminal of invocation when printing)
286  * @param s area to process (uint8_t is just for prototyping. feel free to cast)
287  * @param l area length to check
288  */
289 std::string Util::CreateCleanString(uint8_t *s, int l)
290 {
291    std::string str;
292
293    for( int i=0; i<l; i++)
294    {
295       if (!isprint((unsigned char)s[i]) )
296       {
297          str = str + '.';
298       }
299    else
300       {
301          str = str + (char )s[i];
302       }
303    }
304
305    return str;
306 }
307 /**
308  * \brief   Add a SEPARATOR to the end of the name if necessary
309  * @param   pathname file/directory name to normalize 
310  */
311 std::string Util::NormalizePath(std::string const &pathname)
312 {
313 /*
314    const char SEPARATOR_X      = '/';
315    const char SEPARATOR_WIN    = '\\';
316 #ifdef _WIN32
317    const std::string SEPARATOR = "\\";
318 #else
319    const std::string SEPARATOR = "/";
320 #endif
321 */
322    std::string name = pathname;
323    int size = name.size();
324
325 //   if ( name[size-1] != SEPARATOR_X && name[size-1] != SEPARATOR_WIN )
326    if ( name[size-1] != GDCM_FILESEPARATOR )
327    {
328       name += GDCM_FILESEPARATOR;
329    }
330    return name;
331 }
332
333 /**
334  * \brief   Get the (directory) path from a full path file name
335  * @param   fullName file/directory name to extract Path from
336  */
337 std::string Util::GetPath(std::string const &fullName)
338 {
339    std::string res = fullName;
340 /*
341    
342    int pos1 = res.rfind("/");
343    int pos2 = res.rfind("\\");
344    if ( pos1 > pos2 )
345    {
346       res.resize(pos1);
347    }
348    else
349    {
350       res.resize(pos2);
351    }
352 */
353    int pos = res.rfind(GDCM_FILESEPARATOR);
354    res.resize(pos);
355    return res;
356 }
357
358 /**
359  * \brief   Get the (last) name of a full path file name
360  * @param   fullName file/directory name to extract end name from
361  */
362 std::string Util::GetName(std::string const &fullName)
363 {   
364   std::string filename = fullName;
365 /*
366   std::string::size_type slash_pos = filename.rfind("/");
367   std::string::size_type backslash_pos = filename.rfind("\\");
368   // At least with my gcc4.0.1, unfound char results in pos =4294967295 ...
369   //slash_pos = slash_pos > backslash_pos ? slash_pos : backslash_pos;  
370   slash_pos = slash_pos < backslash_pos ? slash_pos : backslash_pos;
371 */
372   std::string::size_type slash_pos = filename.rfind(GDCM_FILESEPARATOR);
373   if (slash_pos != std::string::npos )
374     {
375     return filename.substr(slash_pos + 1);
376     }
377   else
378     {
379     return filename;
380     }
381
382
383 /**
384  * \brief   Get the current date of the system in a dicom string
385  */
386 std::string Util::GetCurrentDate()
387 {
388     char tmp[512];
389     time_t tloc;
390     time (&tloc);    
391     strftime(tmp,512,"%Y%m%d", localtime(&tloc) );
392     return tmp;
393 }
394
395 /**
396  * \brief   Get the current time of the system in a dicom string
397  */
398 std::string Util::GetCurrentTime()
399 {
400     char tmp[512];
401     time_t tloc;
402     time (&tloc);
403     strftime(tmp,512,"%H%M%S", localtime(&tloc) );
404     return tmp;  
405 }
406
407 /**
408  * \brief  Get both the date and time at the same time to avoid problem 
409  * around midnight where the two calls could be before and after midnight
410  */
411 std::string Util::GetCurrentDateTime()
412 {
413    char tmp[40];
414    long milliseconds;
415    time_t timep;
416   
417    // We need implementation specific functions to obtain millisecond precision
418 #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__)
419    struct timeb tb;
420    ::ftime(&tb);
421    timep = tb.time;
422    milliseconds = tb.millitm;
423 #else
424    struct timeval tv;
425    gettimeofday (&tv, NULL);
426    timep = tv.tv_sec;
427    // Compute milliseconds from microseconds.
428    milliseconds = tv.tv_usec / 1000;
429 #endif
430    // Obtain the time of day, and convert it to a tm struct.
431    struct tm *ptm = localtime (&timep);
432    // Format the date and time, down to a single second.
433    strftime (tmp, sizeof (tmp), "%Y%m%d%H%M%S", ptm);
434
435    // Add milliseconds
436    // Don't use Util::Format to accelerate execution of code
437    char tmpAll[80];
438    sprintf(tmpAll,"%s%03ld",tmp,milliseconds);
439
440    return tmpAll;
441 }
442
443 unsigned int Util::GetCurrentThreadID()
444 {
445 // FIXME the implementation is far from complete
446 #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__)
447   return (unsigned int)GetCurrentThreadId();
448 #else
449 #ifdef __linux__
450    return 0;
451    // Doesn't work on fedora, but is in the man page...
452    //return (unsigned int)gettid();
453 #else
454 #ifdef __sun
455    return (unsigned int)thr_self();
456 #else
457    //default implementation
458    return 0;
459 #endif // __sun
460 #endif // __linux__
461 #endif // Win32
462 }
463
464 unsigned int Util::GetCurrentProcessID()
465 {
466 #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__)
467   // NOTE: There is also a _getpid()...
468   return (unsigned int)GetCurrentProcessId();
469 #else
470   // get process identification, POSIX
471   return (unsigned int)getpid();
472 #endif
473 }
474
475 /**
476  * \brief   tells us whether the processor we are working with is BigEndian or not
477  */
478 bool Util::IsCurrentProcessorBigEndian()
479 {
480 #if defined(GDCM_WORDS_BIGENDIAN)
481    return true;
482 #else
483    return false;
484 #endif
485 }
486
487 /**
488  * \brief Create a /DICOM/ string:
489  * It should a of even length (no odd length ever)
490  * It can contain as many (if you are reading this from your
491  * editor the following character is backslash followed by zero
492  * that needed to be escaped with an extra backslash for doxygen) \\0
493  * as you want.
494  */
495 std::string Util::DicomString(const char *s, size_t l)
496 {
497    std::string r(s, s+l);
498    gdcmAssertMacro( !(r.size() % 2) ); // == basically 'l' is even
499    return r;
500 }
501
502 /**
503  * \brief Create a /DICOM/ string:
504  * It should a of even length (no odd length ever)
505  * It can contain as many (if you are reading this from your
506  * editor the following character is backslash followed by zero
507  * that needed to be escaped with an extra backslash for doxygen) \\0
508  * as you want.
509  * This function is similar to DicomString(const char*), 
510  * except it doesn't take a length. 
511  * It only pad with a null character if length is odd
512  */
513 std::string Util::DicomString(const char *s)
514 {
515    size_t l = strlen(s);
516    if ( l%2 )
517    {
518       l++;
519    }
520    std::string r(s, s+l);
521    gdcmAssertMacro( !(r.size() % 2) );
522    return r;
523 }
524
525 /**
526  * \brief Safely check the equality of two Dicom String:
527  *        - Both strings should be of even length
528  *        - We allow padding of even length string by either
529  *          a null character of a space
530  */
531 bool Util::DicomStringEqual(const std::string &s1, const char *s2)
532 {
533   // s2 is the string from the DICOM reference e.g. : 'MONOCHROME1'
534   std::string s1_even = s1; //Never change input parameter
535   std::string s2_even = DicomString( s2 );
536   if ( s1_even[s1_even.size()-1] == ' ' )
537   {
538     s1_even[s1_even.size()-1] = '\0'; //replace space character by null
539   }
540   return s1_even == s2_even;
541 }
542
543 /**
544  * \brief Safely compare two Dicom String:
545  *        - Both strings should be of even length
546  *        - We allow padding of even length string by either
547  *          a null character of a space
548  */
549 bool Util::CompareDicomString(const std::string &s1, const char *s2, int op)
550 {
551   // s2 is the string from the DICOM reference e.g. : 'MONOCHROME1'
552   std::string s1_even = s1; //Never change input parameter
553   std::string s2_even = DicomString( s2 );
554   if ( s1_even[s1_even.size()-1] == ' ' )
555   {
556     s1_even[s1_even.size()-1] = '\0'; //replace space character by null
557   }
558   switch (op)
559   {
560      case GDCM_EQUAL :
561         return s1_even == s2_even;
562      case GDCM_DIFFERENT :  
563         return s1_even != s2_even;
564      case GDCM_GREATER :  
565         return s1_even >  s2_even;  
566      case GDCM_GREATEROREQUAL :  
567         return s1_even >= s2_even;
568      case GDCM_LESS :
569         return s1_even <  s2_even;
570      case GDCM_LESSOREQUAL :
571         return s1_even <= s2_even;
572      default :
573         gdcmDebugMacro(" Wrong operator : " << op);
574         return false;
575   }
576 }
577
578 #ifdef _WIN32
579    typedef BOOL(WINAPI * pSnmpExtensionInit) (
580            IN DWORD dwTimeZeroReference,
581            OUT HANDLE * hPollForTrapEvent,
582            OUT AsnObjectIdentifier * supportedView);
583
584    typedef BOOL(WINAPI * pSnmpExtensionTrap) (
585            OUT AsnObjectIdentifier * enterprise,
586            OUT AsnInteger * genericTrap,
587            OUT AsnInteger * specificTrap,
588            OUT AsnTimeticks * timeStamp,
589            OUT RFC1157VarBindList * variableBindings);
590
591    typedef BOOL(WINAPI * pSnmpExtensionQuery) (
592            IN BYTE requestType,
593            IN OUT RFC1157VarBindList * variableBindings,
594            OUT AsnInteger * errorStatus,
595            OUT AsnInteger * errorIndex);
596
597    typedef BOOL(WINAPI * pSnmpExtensionInitEx) (
598            OUT AsnObjectIdentifier * supportedView);
599 #endif //_WIN32
600
601 #ifdef __sgi
602 static int SGIGetMacAddress(unsigned char *addr)
603 {
604   FILE *f = popen("/etc/nvram eaddr","r");
605   if(f == 0)
606     {
607     return -1;
608     }
609   unsigned int x[6];
610   if(fscanf(f,"%02x:%02x:%02x:%02x:%02x:%02x",
611             x,x+1,x+2,x+3,x+4,x+5) != 6)
612     {
613     pclose(f);
614     return -1;
615     }
616   for(unsigned int i = 0; i < 6; i++)
617     {
618     addr[i] = static_cast<unsigned char>(x[i]);
619     }
620   return 0;
621 }
622 #endif
623
624 /// \brief gets current M.A.C adress (for internal use only)
625 int GetMacAddrSys ( unsigned char *addr );
626 int GetMacAddrSys ( unsigned char *addr )
627 {
628 #ifdef _WIN32
629    WSADATA WinsockData;
630    if ( (WSAStartup(MAKEWORD(2, 0), &WinsockData)) != 0 ) 
631    {
632       std::cerr << "in Get MAC Adress (internal) : This program requires Winsock 2.x!" 
633              << std::endl;
634       return -1;
635    }
636
637    HANDLE PollForTrapEvent;
638    AsnObjectIdentifier SupportedView;
639    UINT OID_ifEntryType[]  = { 1, 3, 6, 1, 2, 1, 2, 2, 1, 3 };
640    UINT OID_ifEntryNum[]   = { 1, 3, 6, 1, 2, 1, 2, 1 };
641    UINT OID_ipMACEntAddr[] = { 1, 3, 6, 1, 2, 1, 2, 2, 1, 6 };
642    AsnObjectIdentifier MIB_ifMACEntAddr = {
643        sizeof(OID_ipMACEntAddr) / sizeof(UINT), OID_ipMACEntAddr };
644    AsnObjectIdentifier MIB_ifEntryType = {
645        sizeof(OID_ifEntryType) / sizeof(UINT), OID_ifEntryType };
646    AsnObjectIdentifier MIB_ifEntryNum = {
647        sizeof(OID_ifEntryNum) / sizeof(UINT), OID_ifEntryNum };
648    RFC1157VarBindList varBindList;
649    RFC1157VarBind varBind[2];
650    AsnInteger errorStatus;
651    AsnInteger errorIndex;
652    AsnObjectIdentifier MIB_NULL = { 0, 0 };
653    int ret;
654    int dtmp;
655    int j = 0;
656
657    // Load the SNMP dll and get the addresses of the functions necessary
658    HINSTANCE m_hInst = LoadLibrary("inetmib1.dll");
659    if (m_hInst < (HINSTANCE) HINSTANCE_ERROR)
660    {
661       return -1;
662    }
663    pSnmpExtensionInit m_Init =
664        (pSnmpExtensionInit) GetProcAddress(m_hInst, "SnmpExtensionInit");
665    pSnmpExtensionQuery m_Query =
666        (pSnmpExtensionQuery) GetProcAddress(m_hInst, "SnmpExtensionQuery");
667    m_Init(GetTickCount(), &PollForTrapEvent, &SupportedView);
668
669    /* Initialize the variable list to be retrieved by m_Query */
670    varBindList.list = varBind;
671    varBind[0].name = MIB_NULL;
672    varBind[1].name = MIB_NULL;
673
674    // Copy in the OID to find the number of entries in the
675    // Inteface table
676    varBindList.len = 1;        // Only retrieving one item
677    SNMP_oidcpy(&varBind[0].name, &MIB_ifEntryNum);
678    m_Query(ASN_RFC1157_GETNEXTREQUEST, &varBindList, &errorStatus,
679                  &errorIndex);
680 //   printf("# of adapters in this system : %i\n",
681 //          varBind[0].value.asnValue.number);
682    varBindList.len = 2;
683
684    // Copy in the OID of ifType, the type of interface
685    SNMP_oidcpy(&varBind[0].name, &MIB_ifEntryType);
686
687    // Copy in the OID of ifPhysAddress, the address
688    SNMP_oidcpy(&varBind[1].name, &MIB_ifMACEntAddr);
689
690    do
691    {
692       // Submit the query.  Responses will be loaded into varBindList.
693       // We can expect this call to succeed a # of times corresponding
694       // to the # of adapters reported to be in the system
695       ret = m_Query(ASN_RFC1157_GETNEXTREQUEST, &varBindList, &errorStatus,
696                     &errorIndex); 
697       if (!ret)
698       {
699          ret = 1;
700       }
701       else
702       {
703          // Confirm that the proper type has been returned
704          ret = SNMP_oidncmp(&varBind[0].name, &MIB_ifEntryType,
705                             MIB_ifEntryType.idLength);
706       }
707       if (!ret)
708       {
709          j++;
710          dtmp = varBind[0].value.asnValue.number;
711
712          // Type 6 describes ethernet interfaces
713          if (dtmp == 6)
714          {
715             // Confirm that we have an address here
716             ret = SNMP_oidncmp(&varBind[1].name, &MIB_ifMACEntAddr,
717                                MIB_ifMACEntAddr.idLength);
718             if ( !ret && varBind[1].value.asnValue.address.stream != NULL )
719             {
720                if ( (varBind[1].value.asnValue.address.stream[0] == 0x44)
721                  && (varBind[1].value.asnValue.address.stream[1] == 0x45)
722                  && (varBind[1].value.asnValue.address.stream[2] == 0x53)
723                  && (varBind[1].value.asnValue.address.stream[3] == 0x54)
724                  && (varBind[1].value.asnValue.address.stream[4] == 0x00) )
725                {
726                    // Ignore all dial-up networking adapters
727                    std::cerr << "in Get MAC Adress (internal) : Interface #" 
728                              << j << " is a DUN adapter\n";
729                    continue;
730                }
731                if ( (varBind[1].value.asnValue.address.stream[0] == 0x00)
732                  && (varBind[1].value.asnValue.address.stream[1] == 0x00)
733                  && (varBind[1].value.asnValue.address.stream[2] == 0x00)
734                  && (varBind[1].value.asnValue.address.stream[3] == 0x00)
735                  && (varBind[1].value.asnValue.address.stream[4] == 0x00)
736                  && (varBind[1].value.asnValue.address.stream[5] == 0x00) )
737                {
738                   // Ignore NULL addresses returned by other network
739                   // interfaces
740                   std::cerr << "in Get MAC Adress (internal) :  Interface #" 
741                             << j << " is a NULL address\n";
742                   continue;
743                }
744                memcpy( addr, varBind[1].value.asnValue.address.stream, 6);
745             }
746          }
747       }
748    } while (!ret);
749
750    // Free the bindings
751    SNMP_FreeVarBind(&varBind[0]);
752    SNMP_FreeVarBind(&varBind[1]);
753    return 0;
754 #endif //Win32 version
755
756 #if defined(__sgi)
757    return SGIGetMacAddress(addr);
758 #endif // __sgi
759
760
761 // implementation for POSIX system
762 #if defined(CMAKE_HAVE_NET_IF_ARP_H) && defined(__sun)
763    //The POSIX version is broken anyway on Solaris, plus would require full
764    //root power
765    struct  arpreq          parpreq;
766    struct  sockaddr_in     *psa;
767    struct  hostent         *phost;
768    char                    hostname[MAXHOSTNAMELEN];
769    char                    **paddrs;
770    int                     sock, status=0;
771
772    if (gethostname(hostname,  MAXHOSTNAMELEN) != 0 )
773    {
774       perror("in Get MAC Adress (internal) : gethostname");
775       return -1;
776    }
777    phost = gethostbyname(hostname);
778    paddrs = phost->h_addr_list;
779
780    sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
781    if (sock == -1 )
782    {
783       perror("in Get MAC Adress (internal) : sock");
784       return -1;
785    }
786    memset(&parpreq, 0, sizeof(struct arpreq));
787    psa = (struct sockaddr_in *) &parpreq.arp_pa;
788
789    memset(psa, 0, sizeof(struct sockaddr_in));
790    psa->sin_family = AF_INET;
791    memcpy(&psa->sin_addr, *paddrs, sizeof(struct in_addr));
792
793    status = ioctl(sock, SIOCGARP, &parpreq);
794    if (status == -1 )
795    {
796       perror("in Get MAC Adress (internal) : SIOCGARP");
797       return -1;
798    }
799    memcpy(addr, parpreq.arp_ha.sa_data, 6);
800
801    return 0;
802 #else
803 #ifdef CMAKE_HAVE_NET_IF_H
804    int       sd;
805    struct ifreq    ifr, *ifrp;
806    struct ifconf    ifc;
807    char buf[1024];
808    int      n, i;
809    unsigned char    *a;
810 #if defined(AF_LINK) && (!defined(SIOCGIFHWADDR) && !defined(SIOCGENADDR))
811    struct sockaddr_dl *sdlp;
812 #endif
813
814 //
815 // BSD 4.4 defines the size of an ifreq to be
816 // max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len
817 // However, under earlier systems, sa_len isn't present, so the size is 
818 // just sizeof(struct ifreq)
819 // We should investigate the use of SIZEOF_ADDR_IFREQ
820 //
821 #ifdef HAVE_SA_LEN
822    #ifndef max
823       #define max(a,b) ((a) > (b) ? (a) : (b))
824    #endif
825    #define ifreq_size(i) max(sizeof(struct ifreq),\
826         sizeof((i).ifr_name)+(i).ifr_addr.sa_len)
827 #else
828    #define ifreq_size(i) sizeof(struct ifreq)
829 #endif // HAVE_SA_LEN
830
831    if ( (sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0 )
832    {
833       return -1;
834    }
835    memset(buf, 0, sizeof(buf));
836    ifc.ifc_len = sizeof(buf);
837    ifc.ifc_buf = buf;
838    if (ioctl (sd, SIOCGIFCONF, (char *)&ifc) < 0)
839    {
840       close(sd);
841       return -1;
842    }
843    n = ifc.ifc_len;
844    for (i = 0; i < n; i+= ifreq_size(*ifrp) )
845    {
846       ifrp = (struct ifreq *)((char *) ifc.ifc_buf+i);
847       strncpy(ifr.ifr_name, ifrp->ifr_name, IFNAMSIZ);
848 #ifdef SIOCGIFHWADDR
849       if (ioctl(sd, SIOCGIFHWADDR, &ifr) < 0)
850          continue;
851       a = (unsigned char *) &ifr.ifr_hwaddr.sa_data;
852 #else
853 #ifdef SIOCGENADDR
854       // In theory this call should also work on Sun Solaris, but apparently
855       // SIOCGENADDR is not implemented properly thus the call 
856       // ioctl(sd, SIOCGENADDR, &ifr) always returns errno=2 
857       // (No such file or directory)
858       // Furthermore the DLAPI seems to require full root access
859       if (ioctl(sd, SIOCGENADDR, &ifr) < 0)
860          continue;
861       a = (unsigned char *) ifr.ifr_enaddr;
862 #else
863 #ifdef AF_LINK
864       sdlp = (struct sockaddr_dl *) &ifrp->ifr_addr;
865       if ((sdlp->sdl_family != AF_LINK) || (sdlp->sdl_alen != 6))
866          continue;
867       a = (unsigned char *) &sdlp->sdl_data[sdlp->sdl_nlen];
868 #else
869       perror("in Get MAC Adress (internal) : No way to access hardware");
870       close(sd);
871       return -1;
872 #endif // AF_LINK
873 #endif // SIOCGENADDR
874 #endif // SIOCGIFHWADDR
875       if (!a[0] && !a[1] && !a[2] && !a[3] && !a[4] && !a[5]) continue;
876
877       if (addr) 
878       {
879          memcpy(addr, a, 6);
880          close(sd);
881          return 0;
882       }
883    }
884    close(sd);
885 #endif
886    // Not implemented platforms (or no Ethernet cable !)
887    
888    /// \todo FIXME I wish we don't pollute command line applications when no Ethernet cable !
889    //perror("Probabely your computer is not connected on a network, therefore its MAC adress cannot be found (or there is a configuration problem on your platform)");
890
891    // But the following -> error: invalid use of 'this' in non-member function
892    //gdcmWarningMacro( "Probabely your computer is not connected on a network, therefore its MAC adress cannot be found (or there is a configuration problem on your platform)");
893
894    memset(addr,0,6);
895    return -1;
896 #endif //__sun
897 }
898
899 /**
900  * \brief Mini function to return the last digit from a number express in base 256
901  *        pre condition data contain an array of 6 unsigned char
902  *        post condition carry contain the last digit
903  */
904 inline int getlastdigit(unsigned char *data)
905 {
906   int extended, carry = 0;
907   for(int i=0;i<6;i++)
908     {
909     extended = (carry << 8) + data[i];
910     data[i] = extended / 10;
911     carry = extended % 10;
912     }
913   return carry;
914 }
915
916 /**
917  * \brief Encode the mac address on a fixed length string of 15 characters.
918  * we save space this way.
919  */
920 std::string Util::GetMACAddress()
921 {
922    // This code is the result of a long internet search to find something
923    // as compact as possible (not OS independant). We only have to separate
924    // 3 OS: Win32, SunOS and 'real' POSIX
925    // http://groups-beta.google.com/group/comp.unix.solaris/msg/ad36929d783d63be
926    // http://bdn.borland.com/article/0,1410,26040,00.html
927    unsigned char addr[6];
928
929    int stat = GetMacAddrSys(addr);
930    if (stat == 0)
931    {
932       // We need to convert a 6 digit number from base 256 to base 10, using integer
933       // would requires a 48bits one. To avoid this we have to reimplement the div + modulo 
934       // with string only
935       bool zero = false;
936       int res;
937       std::string sres;
938       while(!zero)
939       {
940          res = getlastdigit(addr);
941          sres.insert(sres.begin(), '0' + res);
942          zero = (addr[0] == 0) && (addr[1] == 0) && (addr[2] == 0) 
943              && (addr[3] == 0) && (addr[4] == 0) && (addr[5] == 0);
944       }
945
946       return sres;
947    }
948    else
949    {
950       gdcmStaticWarningMacro("Problem in finding the MAC Address");
951       return "";
952    }
953 }
954
955 /**
956  * \brief Creates a new UID. As stipulated in the DICOM ref
957  *        each time a DICOM image is created it should have 
958  *        a unique identifier (URI)
959  * @param root is the DICOM prefix assigned by IOS group
960  */
961 std::string Util::CreateUniqueUID(const std::string &root)
962 {
963    std::string prefix;
964    std::string append;
965    if ( root.empty() )
966    {
967       // gdcm UID prefix, as supplied by http://www.medicalconnections.co.uk
968       prefix = RootUID; 
969    }
970    else
971    {
972       prefix = root;
973    }
974
975    // A root was specified use it to forge our new UID:
976    append += ".";
977    //append += Util::GetMACAddress(); // to save CPU time
978    append += Util::GDCM_MAC_ADRESS;
979    append += ".";
980    append += Util::GetCurrentDateTime();
981    append += ".";
982    //Also add a mini random number just in case:
983    char tmp[10];
984    int r = (int) (100.0*rand()/RAND_MAX);
985    // Don't use Util::Format to accelerate the execution
986    sprintf(tmp,"%02d", r);
987    append += tmp;
988
989    // If append is too long we need to rehash it
990    if ( (prefix + append).size() > 64 )
991    {
992       gdcmStaticErrorMacro( "Size of UID is too long." );
993       // we need a hash function to truncate this number
994       // if only md5 was cross plateform
995       // MD5(append);
996    }
997
998    return prefix + append;
999 }
1000
1001 void Util::SetRootUID(const std::string &root)
1002 {
1003    if ( root.empty() )
1004       RootUID = GDCM_UID;
1005    else
1006       RootUID = root;
1007 }
1008
1009 const std::string &Util::GetRootUID()
1010 {
1011    return RootUID;
1012 }
1013
1014 //-------------------------------------------------------------------------
1015 /**
1016  * \brief binary_write binary_write
1017  * @param os ostream to write to 
1018  * @param val 16 bits value to write
1019  */ 
1020 std::ostream &binary_write(std::ostream &os, const uint16_t &val)
1021 {
1022 #if defined(GDCM_WORDS_BIGENDIAN) || defined(GDCM_FORCE_BIGENDIAN_EMULATION)
1023    uint16_t swap;
1024    swap = ( val << 8 | val >> 8 );
1025
1026    return os.write(reinterpret_cast<const char*>(&swap), 2);
1027 #else
1028    return os.write(reinterpret_cast<const char*>(&val), 2);
1029 #endif //GDCM_WORDS_BIGENDIAN
1030 }
1031
1032 /**
1033  * \brief binary_write binary_write
1034  * @param os ostream to write to
1035  * @param val 32 bits value to write
1036  */ 
1037 std::ostream &binary_write(std::ostream &os, const uint32_t &val)
1038 {
1039 #if defined(GDCM_WORDS_BIGENDIAN) || defined(GDCM_FORCE_BIGENDIAN_EMULATION)
1040    uint32_t swap;
1041    swap = (  (val<<24)               | ((val<<8)  & 0x00ff0000) | 
1042             ((val>>8)  & 0x0000ff00) |  (val>>24)               );
1043    return os.write(reinterpret_cast<const char*>(&swap), 4);
1044 #else
1045    return os.write(reinterpret_cast<const char*>(&val), 4);
1046 #endif //GDCM_WORDS_BIGENDIAN
1047 }
1048
1049 /**
1050  * \brief binary_write binary_write
1051  * @param os ostream to write to
1052  * @param val double (64 bits) value to write
1053  */ 
1054 std::ostream &binary_write(std::ostream &os, const double &val)
1055 {
1056 #if defined(GDCM_WORDS_BIGENDIAN) || defined(GDCM_FORCE_BIGENDIAN_EMULATION)    
1057    double swap = val;
1058    
1059    char *beg = (char *)&swap;
1060    char *end = beg + 7;
1061    char t;
1062    for (unsigned int i = 0; i<7; i++)
1063    {
1064       t    = *beg;
1065       *beg = *end;
1066       *end = t;
1067       beg++,
1068       end--;  
1069    }  
1070    return os.write(reinterpret_cast<const char*>(&swap), 8);
1071 #else
1072    return os.write(reinterpret_cast<const char*>(&val), 8);
1073 #endif //GDCM_WORDS_BIGENDIAN
1074 }
1075
1076 /**
1077  * \brief  binary_write binary_write
1078  * @param os ostream to write to
1079  * @param val 8 bits characters aray to write
1080  */ 
1081 std::ostream &binary_write(std::ostream &os, const char *val)
1082 {
1083    return os.write(val, strlen(val));
1084 }
1085
1086 /**
1087  * \brief  binary_write binary_write
1088  * @param os ostream to write to
1089  * @param val std::string value to write
1090  */ 
1091 std::ostream &binary_write(std::ostream &os, std::string const &val)
1092 {
1093    return os.write(val.c_str(), val.size());
1094 }
1095
1096 /**
1097  * \brief  binary_write binary_write
1098  * @param os ostream to write to
1099  * @param val 8 bits 'characters' aray to write
1100  * @param len length of the 'value' to be written
1101  */ 
1102 std::ostream &binary_write(std::ostream &os, const uint8_t *val, size_t len)
1103 {
1104    // We are writting sizeof(char) thus no need to swap bytes
1105    return os.write(reinterpret_cast<const char*>(val), len);
1106 }
1107
1108 /**
1109  * \brief  binary_write binary_write
1110  * @param os ostream to write to
1111  * @param val 16 bits words aray to write
1112  * @param len length (in bytes) of the 'value' to be written 
1113  */ 
1114 std::ostream &binary_write(std::ostream &os, const uint16_t *val, size_t len)
1115 {
1116 // This is tricky since we are writting two bytes buffer. 
1117 // Be carefull with little endian vs big endian. 
1118 // Also this other trick is to allocate a small (efficient) buffer that store
1119 // intermediate result before writting it.
1120 #if defined(GDCM_WORDS_BIGENDIAN) || defined(GDCM_FORCE_BIGENDIAN_EMULATION)
1121    const int BUFFER_SIZE = 4096;
1122    static char buffer[BUFFER_SIZE];
1123    uint16_t *binArea16 = (uint16_t*)val; //for the const
1124  
1125    // how many BUFFER_SIZE long pieces in binArea ?
1126    int nbPieces = len/BUFFER_SIZE; //(16 bits = 2 Bytes)
1127    int remainingSize = len%BUFFER_SIZE;
1128
1129    for (int j=0;j<nbPieces;j++)
1130    {
1131       uint16_t *pbuffer  = (uint16_t*)buffer; //reinitialize pbuffer
1132       for (int i = 0; i < BUFFER_SIZE/2; i++)
1133       {
1134          *pbuffer = *binArea16 >> 8 | *binArea16 << 8;
1135          pbuffer++;
1136          binArea16++;
1137       }
1138       os.write ( buffer, BUFFER_SIZE );
1139    }
1140    if ( remainingSize > 0)
1141    {
1142       uint16_t *pbuffer  = (uint16_t*)buffer; //reinitialize pbuffer
1143       for (int i = 0; i < remainingSize/2; i++)
1144       {
1145          *pbuffer = *binArea16 >> 8 | *binArea16 << 8;
1146          pbuffer++;
1147          binArea16++;
1148       }
1149       os.write ( buffer, remainingSize );
1150    }
1151    return os;
1152 #else
1153    return os.write(reinterpret_cast<const char*>(val), len);
1154 #endif
1155 }
1156
1157 std::string Util::ConvertToMD5 (std::string &inPszToCrypt)
1158 {
1159    char *szChar      = new char[ inPszToCrypt.size()+1 ];
1160    char *szHexOutput = new char[ 16 * 2 + 1 ];
1161    int nLen,nDi;
1162    strcpy( szChar, inPszToCrypt.c_str() );
1163    // création du code md5
1164    nLen = strlen( szChar );
1165    md5_state_t state;
1166    uint8_t digest[ 16 ];
1167    md5_init   ( &state );
1168    md5_append ( &state, (const uint8_t *)szChar, nLen);
1169    md5_finish ( &state, digest );
1170    for ( nDi = 0; nDi < 16; nDi++)
1171       sprintf( szHexOutput + nDi * 2, "%02x", digest[ nDi ] );
1172    szHexOutput[16 * 2]=0;
1173    delete [] szChar;
1174    std::string md5String=szHexOutput;
1175    delete [] szHexOutput;
1176    return md5String;
1177 }
1178
1179 //-------------------------------------------------------------------------
1180 // Protected
1181
1182 //-------------------------------------------------------------------------
1183 // Private
1184 /**
1185  * \brief   Return the IP adress of the machine writting the DICOM image
1186  */
1187 std::string Util::GetIPAddress()
1188 {
1189    // This is a rip from 
1190    // http://www.codeguru.com/Cpp/I-N/internet/network/article.php/c3445/
1191 #ifndef HOST_NAME_MAX
1192    // SUSv2 guarantees that `Host names are limited to 255 bytes'.
1193    // POSIX 1003.1-2001 guarantees that `Host names (not including the
1194    // terminating NUL) are limited to HOST_NAME_MAX bytes'.
1195 #define HOST_NAME_MAX 255
1196    // In this case we should maybe check the string was not truncated.
1197    // But I don't known how to check that...
1198 #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__)
1199    // with WinSock DLL we need to initialize the WinSock before using gethostname
1200    WORD wVersionRequested = MAKEWORD(1,0);
1201    WSADATA WSAData;
1202    int err = WSAStartup(wVersionRequested,&WSAData);
1203    if (err != 0)
1204    {
1205       // Tell the user that we could not find a usable
1206       // WinSock DLL.
1207       WSACleanup();
1208       return "127.0.0.1";
1209    }
1210 #endif
1211   
1212 #endif //HOST_NAME_MAX
1213
1214    std::string str;
1215    char szHostName[HOST_NAME_MAX+1];
1216    int r = gethostname(szHostName, HOST_NAME_MAX);
1217  
1218    if ( r == 0 )
1219    {
1220       // Get host adresses
1221       struct hostent *pHost = gethostbyname(szHostName);
1222  
1223       for( int i = 0; pHost!= NULL && pHost->h_addr_list[i]!= NULL; i++ )
1224       {
1225          for( int j = 0; j<pHost->h_length; j++ )
1226          {
1227             if ( j > 0 ) str += ".";
1228  
1229             str += Util::Format("%u", 
1230                 (unsigned int)((unsigned char*)pHost->h_addr_list[i])[j]);
1231          }
1232          // str now contains one local IP address 
1233  
1234 #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__)
1235    WSACleanup();
1236 #endif
1237
1238       }
1239    }
1240    // If an error occur r == -1
1241    // Most of the time it will return 127.0.0.1...
1242    return str;
1243 }
1244
1245 void Util::hfpswap(double *a, double *b)
1246 {
1247    double tmp;
1248    tmp=*a;
1249    *a=*b;
1250    *b=tmp;
1251 }
1252
1253 // for MD5
1254 /*
1255   Copyright (C) 1999, 2000, 2002 Aladdin Enterprises.  All rights reserved.
1256
1257   This software is provided 'as-is', without any express or implied
1258   warranty.  In no event will the authors be held liable for any damages
1259   arising from the use of this software.
1260
1261   Permission is granted to anyone to use this software for any purpose,
1262   including commercial applications, and to alter it and redistribute it
1263   freely, subject to the following restrictions:
1264
1265   1. The origin of this software must not be misrepresented; you must not
1266      claim that you wrote the original software. If you use this software
1267      in a product, an acknowledgment in the product documentation would be
1268      appreciated but is not required.
1269   2. Altered source versions must be plainly marked as such, and must not be
1270      misrepresented as being the original software.
1271   3. This notice may not be removed or altered from any source distribution.
1272
1273   L. Peter Deutsch
1274
1275   ghost@aladdin.com
1276  */
1277
1278 /* $Id: gdcmUtil.cxx,v 1.189 2007/10/17 08:57:55 jpr Exp $ */
1279
1280 /*
1281   Independent implementation of MD5 (RFC 1321).
1282   This code implements the MD5 Algorithm defined in RFC 1321, whose
1283   text is available at
1284
1285  http://www.ietf.org/rfc/rfc1321.txt
1286
1287   The code is derived from the text of the RFC, including the test suite
1288   (section A.5) but excluding the rest of Appendix A.  It does not include
1289   any code or documentation that is identified in the RFC as being
1290   copyrighted.
1291
1292   The original and principal author of md5.c is L. Peter Deutsch
1293   <ghost@aladdin.com>.  Other authors are noted in the change history
1294   that follows (in reverse chronological order):
1295
1296   2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
1297       either statically or dynamically; added missing #include <string.h>
1298       in library.
1299   2002-03-11 lpd Corrected argument list for main(), and added int return
1300       type, in test program and T value program.
1301   2002-02-21 lpd Added missing #include <stdio.h> in test program.
1302   2000-07-03 lpd Patched to eliminate warnings about "constant is
1303       unsigned in ANSI C, signed in traditional"; made test program
1304       self-checking.
1305   1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
1306   1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
1307   1999-05-03 lpd Original version.
1308  */
1309
1310 //#include "md5.h"
1311 //#include <string.h>
1312
1313 #undef BYTE_ORDER     /* 1 = big-endian, -1 = little-endian, 0 = unknown */
1314 #ifdef ARCH_IS_BIG_ENDIAN
1315 #  define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
1316 #else
1317 #  define BYTE_ORDER 0
1318 #endif
1319
1320
1321 #define T_MASK ((uint16_t)~0)
1322 #define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
1323 #define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
1324 #define T3    0x242070db
1325 #define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
1326 #define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
1327 #define T6    0x4787c62a
1328 #define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
1329 #define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
1330 #define T9    0x698098d8
1331 #define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
1332 #define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
1333 #define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
1334 #define T13    0x6b901122
1335 #define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
1336 #define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
1337 #define T16    0x49b40821
1338 #define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
1339 #define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
1340 #define T19    0x265e5a51
1341 #define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
1342 #define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
1343 #define T22    0x02441453
1344 #define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
1345 #define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
1346 #define T25    0x21e1cde6
1347 #define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
1348 #define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
1349 #define T28    0x455a14ed
1350 #define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
1351 #define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
1352 #define T31    0x676f02d9
1353 #define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
1354 #define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
1355 #define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
1356 #define T35    0x6d9d6122
1357 #define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
1358 #define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
1359 #define T38    0x4bdecfa9
1360 #define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
1361 #define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
1362 #define T41    0x289b7ec6
1363 #define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
1364 #define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
1365 #define T44    0x04881d05
1366 #define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
1367 #define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
1368 #define T47    0x1fa27cf8
1369 #define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
1370 #define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
1371 #define T50    0x432aff97
1372 #define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
1373 #define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
1374 #define T53    0x655b59c3
1375 #define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
1376 #define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
1377 #define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
1378 #define T57    0x6fa87e4f
1379 #define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
1380 #define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
1381 #define T60    0x4e0811a1
1382 #define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
1383 #define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
1384 #define T63    0x2ad7d2bb
1385 #define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
1386
1387
1388 void
1389 Util::md5_process(md5_state_t *pms, const uint8_t *data /*[64]*/)
1390 {
1391     uint16_t
1392     a = pms->abcd[0], b = pms->abcd[1],
1393     c = pms->abcd[2], d = pms->abcd[3];
1394     uint16_t t;
1395
1396 #if BYTE_ORDER > 0
1397     /* Define storage only for big-endian CPUs. */
1398     uint16_t X[16];
1399 #else
1400     /* Define storage for little-endian or both types of CPUs. */
1401     uint16_t xbuf[16];
1402     const uint16_t *X;
1403 #endif
1404     {
1405 #if BYTE_ORDER == 0
1406 /*
1407  * Determine dynamically whether this is a big-endian or
1408  * little-endian machine, since we can use a more efficient
1409  * algorithm on the latter.
1410  */
1411 static const int w = 1;
1412
1413 if (*((const uint8_t *)&w)) /* dynamic little-endian */
1414 #endif
1415 #if BYTE_ORDER <= 0  /* little-endian */
1416 {
1417     /*
1418      * On little-endian machines, we can process properly aligned
1419      * data without copying it.
1420      */
1421     if (!((data - (const uint8_t *)0) & 3)) {
1422     /* data are properly aligned */
1423        X = (const uint16_t *)data;
1424     } else {
1425      /* not aligned */
1426      memcpy(xbuf, data, 64);
1427      X = xbuf;
1428     }
1429 }
1430 #endif
1431 #if BYTE_ORDER == 0
1432 else  /* dynamic big-endian */
1433 #endif
1434 #if BYTE_ORDER >= 0 /* big-endian */
1435 {
1436     /*
1437      * On big-endian machines, we must arrange the bytes in the
1438      * right order.
1439      */
1440     const uint8_t *xp = data;
1441     int i;
1442
1443 #  if BYTE_ORDER == 0
1444      X = xbuf; /* (dynamic only) */
1445 #  else
1446 #    define xbuf /* (static only)  */
1447 #  endif
1448       for (i = 0; i < 16; ++i, xp += 4)
1449          xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
1450       }
1451 #endif
1452     }
1453
1454 #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
1455
1456     /* Round 1. */
1457     /* Let [abcd k s i] denote the operation
1458        a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
1459
1460 #define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
1461 #define SET(a, b, c, d, k, s, Ti) \
1462      t = a + F(b,c,d) + X[k] + Ti;\
1463      a = ROTATE_LEFT(t, s) + b
1464     /* Do the following 16 operations. */
1465     SET(a, b, c, d,  0,  7,  T1);
1466     SET(d, a, b, c,  1, 12,  T2);
1467     SET(c, d, a, b,  2, 17,  T3);
1468     SET(b, c, d, a,  3, 22,  T4);
1469     SET(a, b, c, d,  4,  7,  T5);
1470     SET(d, a, b, c,  5, 12,  T6);
1471     SET(c, d, a, b,  6, 17,  T7);
1472     SET(b, c, d, a,  7, 22,  T8);
1473     SET(a, b, c, d,  8,  7,  T9);
1474     SET(d, a, b, c,  9, 12, T10);
1475     SET(c, d, a, b, 10, 17, T11);
1476     SET(b, c, d, a, 11, 22, T12);
1477     SET(a, b, c, d, 12,  7, T13);
1478     SET(d, a, b, c, 13, 12, T14);
1479     SET(c, d, a, b, 14, 17, T15);
1480     SET(b, c, d, a, 15, 22, T16);
1481 #undef SET
1482      /* Round 2. */
1483      /* Let [abcd k s i] denote the operation
1484           a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
1485
1486 #define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
1487 #define SET(a, b, c, d, k, s, Ti)\
1488   t = a + G(b,c,d) + X[k] + Ti;  \
1489   a = ROTATE_LEFT(t, s) + b
1490      /* Do the following 16 operations. */
1491     SET(a, b, c, d,  1,  5, T17);
1492     SET(d, a, b, c,  6,  9, T18);
1493     SET(c, d, a, b, 11, 14, T19);
1494     SET(b, c, d, a,  0, 20, T20);
1495     SET(a, b, c, d,  5,  5, T21);
1496     SET(d, a, b, c, 10,  9, T22);
1497     SET(c, d, a, b, 15, 14, T23);
1498     SET(b, c, d, a,  4, 20, T24);
1499     SET(a, b, c, d,  9,  5, T25);
1500     SET(d, a, b, c, 14,  9, T26);
1501     SET(c, d, a, b,  3, 14, T27);
1502     SET(b, c, d, a,  8, 20, T28);
1503     SET(a, b, c, d, 13,  5, T29);
1504     SET(d, a, b, c,  2,  9, T30);
1505     SET(c, d, a, b,  7, 14, T31);
1506     SET(b, c, d, a, 12, 20, T32);
1507 #undef SET
1508      /* Round 3. */
1509      /* Let [abcd k s t] denote the operation
1510           a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
1511 #define H(x, y, z) ((x) ^ (y) ^ (z))
1512 #define SET(a, b, c, d, k, s, Ti)\
1513   t = a + H(b,c,d) + X[k] + Ti;  \
1514   a = ROTATE_LEFT(t, s) + b
1515   
1516      /* Do the following 16 operations. */
1517     SET(a, b, c, d,  5,  4, T33);
1518     SET(d, a, b, c,  8, 11, T34);
1519     SET(c, d, a, b, 11, 16, T35);
1520     SET(b, c, d, a, 14, 23, T36);
1521     SET(a, b, c, d,  1,  4, T37);
1522     SET(d, a, b, c,  4, 11, T38);
1523     SET(c, d, a, b,  7, 16, T39);
1524     SET(b, c, d, a, 10, 23, T40);
1525     SET(a, b, c, d, 13,  4, T41);
1526     SET(d, a, b, c,  0, 11, T42);
1527     SET(c, d, a, b,  3, 16, T43);
1528     SET(b, c, d, a,  6, 23, T44);
1529     SET(a, b, c, d,  9,  4, T45);
1530     SET(d, a, b, c, 12, 11, T46);
1531     SET(c, d, a, b, 15, 16, T47);
1532     SET(b, c, d, a,  2, 23, T48);
1533 #undef SET
1534      /* Round 4. */
1535      /* Let [abcd k s t] denote the operation
1536           a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
1537 #define I(x, y, z) ((y) ^ ((x) | ~(z)))
1538 #define SET(a, b, c, d, k, s, Ti)\
1539   t = a + I(b,c,d) + X[k] + Ti;  \
1540   a = ROTATE_LEFT(t, s) + b
1541   
1542      /* Do the following 16 operations. */
1543     SET(a, b, c, d,  0,  6, T49);
1544     SET(d, a, b, c,  7, 10, T50);
1545     SET(c, d, a, b, 14, 15, T51);
1546     SET(b, c, d, a,  5, 21, T52);
1547     SET(a, b, c, d, 12,  6, T53);
1548     SET(d, a, b, c,  3, 10, T54);
1549     SET(c, d, a, b, 10, 15, T55);
1550     SET(b, c, d, a,  1, 21, T56);
1551     SET(a, b, c, d,  8,  6, T57);
1552     SET(d, a, b, c, 15, 10, T58);
1553     SET(c, d, a, b,  6, 15, T59);
1554     SET(b, c, d, a, 13, 21, T60);
1555     SET(a, b, c, d,  4,  6, T61);
1556     SET(d, a, b, c, 11, 10, T62);
1557     SET(c, d, a, b,  2, 15, T63);
1558     SET(b, c, d, a,  9, 21, T64);
1559
1560 #undef SET
1561      /* Then perform the following additions. (That is increment each
1562         of the four registers by the value it had before this block
1563         was started.) */
1564     pms->abcd[0] += a;
1565     pms->abcd[1] += b;
1566     pms->abcd[2] += c;
1567     pms->abcd[3] += d;
1568 }
1569 void
1570 Util::md5_init(md5_state_t *pms)
1571 {
1572     pms->count[0] = pms->count[1] = 0;
1573     pms->abcd[0] = 0x67452301;
1574     pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
1575     pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
1576     pms->abcd[3] = 0x10325476;
1577 }
1578
1579
1580 void
1581 Util::md5_append(md5_state_t *pms, const uint8_t *data, int nbytes)
1582 {
1583     const uint8_t *p = data;
1584     int left = nbytes;
1585     int offset = (pms->count[0] >> 3) & 63;
1586     uint16_t nbits = (uint16_t)(nbytes << 3);
1587     if (nbytes <= 0)
1588        return;
1589     /* Update the message length. */
1590     pms->count[1] += nbytes >> 29;
1591     pms->count[0] += nbits;
1592     if (pms->count[0] < nbits)
1593        pms->count[1]++;
1594     /* Process an initial partial block. */
1595     if (offset) {
1596        int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
1597        memcpy(pms->buf + offset, p, copy);
1598        if (offset + copy < 64)
1599           return;
1600        p += copy;
1601        left -= copy;
1602        md5_process(pms, pms->buf);
1603     }
1604     /* Process full blocks. */
1605     for (; left >= 64; p += 64, left -= 64)
1606       md5_process(pms, p);
1607     /* Process a final partial block. */
1608     if (left)
1609       memcpy(pms->buf, p, left);
1610 }
1611 void
1612 Util::md5_finish(md5_state_t *pms, uint8_t digest[16])
1613 {
1614     static const uint8_t pad[64] = {
1615        0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1616        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1617        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1618        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
1619     };
1620
1621     uint8_t data[8];
1622     int i;
1623     /* Save the length before padding. */
1624     for (i = 0; i < 8; ++i)
1625        data[i] = (uint8_t)(pms->count[i >> 2] >> ((i & 3) << 3));
1626     /* Pad to 56 bytes mod 64. */
1627     md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
1628     /* Append the length. */
1629     md5_append(pms, data, 8);
1630     for (i = 0; i < 16; ++i)
1631       digest[i] = (uint8_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
1632 }
1633
1634 //-------------------------------------------------------------------------
1635 } // end namespace gdcm
1636