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