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