]> Creatis software - gdcm.git/blob - src/gdcmUtil.cxx
avoid Doxygen Warnings
[gdcm.git] / src / gdcmUtil.cxx
1 /*=========================================================================
2                                                                                 
3   Program:   gdcm
4   Module:    $RCSfile: gdcmUtil.cxx,v $
5   Language:  C++
6   Date:      $Date: 2007/05/23 14:18:11 $
7   Version:   $Revision: 1.187 $
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
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 Ethernet cable !)
859    
860    /// \todo FIXME I wish we don't pollute command line applications when no Ethernet cable !
861    //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)");
862
863    // But the following -> error: invalid use of 'this' in non-member function
864    //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)");
865
866    memset(addr,0,6);
867    return -1;
868 #endif //__sun
869 }
870
871 /**
872  * \brief Mini function to return the last digit from a number express in base 256
873  *        pre condition data contain an array of 6 unsigned char
874  *        post condition carry contain the last digit
875  */
876 inline int getlastdigit(unsigned char *data)
877 {
878   int extended, carry = 0;
879   for(int i=0;i<6;i++)
880     {
881     extended = (carry << 8) + data[i];
882     data[i] = extended / 10;
883     carry = extended % 10;
884     }
885   return carry;
886 }
887
888 /**
889  * \brief Encode the mac address on a fixed length string of 15 characters.
890  * we save space this way.
891  */
892 std::string Util::GetMACAddress()
893 {
894    // This code is the result of a long internet search to find something
895    // as compact as possible (not OS independant). We only have to separate
896    // 3 OS: Win32, SunOS and 'real' POSIX
897    // http://groups-beta.google.com/group/comp.unix.solaris/msg/ad36929d783d63be
898    // http://bdn.borland.com/article/0,1410,26040,00.html
899    unsigned char addr[6];
900
901    int stat = GetMacAddrSys(addr);
902    if (stat == 0)
903    {
904       // We need to convert a 6 digit number from base 256 to base 10, using integer
905       // would requires a 48bits one. To avoid this we have to reimplement the div + modulo 
906       // with string only
907       bool zero = false;
908       int res;
909       std::string sres;
910       while(!zero)
911       {
912          res = getlastdigit(addr);
913          sres.insert(sres.begin(), '0' + res);
914          zero = (addr[0] == 0) && (addr[1] == 0) && (addr[2] == 0) 
915              && (addr[3] == 0) && (addr[4] == 0) && (addr[5] == 0);
916       }
917
918       return sres;
919    }
920    else
921    {
922       gdcmStaticWarningMacro("Problem in finding the MAC Address");
923       return "";
924    }
925 }
926
927 /**
928  * \brief Creates a new UID. As stipulated in the DICOM ref
929  *        each time a DICOM image is created it should have 
930  *        a unique identifier (URI)
931  * @param root is the DICOM prefix assigned by IOS group
932  */
933 std::string Util::CreateUniqueUID(const std::string &root)
934 {
935    std::string prefix;
936    std::string append;
937    if ( root.empty() )
938    {
939       // gdcm UID prefix, as supplied by http://www.medicalconnections.co.uk
940       prefix = RootUID; 
941    }
942    else
943    {
944       prefix = root;
945    }
946
947    // A root was specified use it to forge our new UID:
948    append += ".";
949    //append += Util::GetMACAddress(); // to save CPU time
950    append += Util::GDCM_MAC_ADRESS;
951    append += ".";
952    append += Util::GetCurrentDateTime();
953    append += ".";
954    //Also add a mini random number just in case:
955    char tmp[10];
956    int r = (int) (100.0*rand()/RAND_MAX);
957    // Don't use Util::Format to accelerate the execution
958    sprintf(tmp,"%02d", r);
959    append += tmp;
960
961    // If append is too long we need to rehash it
962    if ( (prefix + append).size() > 64 )
963    {
964       gdcmStaticErrorMacro( "Size of UID is too long." );
965       // we need a hash function to truncate this number
966       // if only md5 was cross plateform
967       // MD5(append);
968    }
969
970    return prefix + append;
971 }
972
973 void Util::SetRootUID(const std::string &root)
974 {
975    if ( root.empty() )
976       RootUID = GDCM_UID;
977    else
978       RootUID = root;
979 }
980
981 const std::string &Util::GetRootUID()
982 {
983    return RootUID;
984 }
985
986 //-------------------------------------------------------------------------
987 /**
988  * \brief binary_write binary_write
989  * @param os ostream to write to 
990  * @param val 16 bits value to write
991  */ 
992 std::ostream &binary_write(std::ostream &os, const uint16_t &val)
993 {
994 #if defined(GDCM_WORDS_BIGENDIAN) || defined(GDCM_FORCE_BIGENDIAN_EMULATION)
995    uint16_t swap;
996    swap = ( val << 8 | val >> 8 );
997
998    return os.write(reinterpret_cast<const char*>(&swap), 2);
999 #else
1000    return os.write(reinterpret_cast<const char*>(&val), 2);
1001 #endif //GDCM_WORDS_BIGENDIAN
1002 }
1003
1004 /**
1005  * \brief binary_write binary_write
1006  * @param os ostream to write to
1007  * @param val 32 bits value to write
1008  */ 
1009 std::ostream &binary_write(std::ostream &os, const uint32_t &val)
1010 {
1011 #if defined(GDCM_WORDS_BIGENDIAN) || defined(GDCM_FORCE_BIGENDIAN_EMULATION)
1012    uint32_t swap;
1013    swap = (  (val<<24)               | ((val<<8)  & 0x00ff0000) | 
1014             ((val>>8)  & 0x0000ff00) |  (val>>24)               );
1015    return os.write(reinterpret_cast<const char*>(&swap), 4);
1016 #else
1017    return os.write(reinterpret_cast<const char*>(&val), 4);
1018 #endif //GDCM_WORDS_BIGENDIAN
1019 }
1020
1021 /**
1022  * \brief binary_write binary_write
1023  * @param os ostream to write to
1024  * @param val double (64 bits) value to write
1025  */ 
1026 std::ostream &binary_write(std::ostream &os, const double &val)
1027 {
1028 #if defined(GDCM_WORDS_BIGENDIAN) || defined(GDCM_FORCE_BIGENDIAN_EMULATION)    
1029    double swap = val;
1030    
1031    char *beg = (char *)&swap;
1032    char *end = beg + 7;
1033    char t;
1034    for (unsigned int i = 0; i<7; i++)
1035    {
1036       t    = *beg;
1037       *beg = *end;
1038       *end = t;
1039       beg++,
1040       end--;  
1041    }  
1042    return os.write(reinterpret_cast<const char*>(&swap), 8);
1043 #else
1044    return os.write(reinterpret_cast<const char*>(&val), 8);
1045 #endif //GDCM_WORDS_BIGENDIAN
1046 }
1047
1048 /**
1049  * \brief  binary_write binary_write
1050  * @param os ostream to write to
1051  * @param val 8 bits characters aray to write
1052  */ 
1053 std::ostream &binary_write(std::ostream &os, const char *val)
1054 {
1055    return os.write(val, strlen(val));
1056 }
1057
1058 /**
1059  * \brief  binary_write binary_write
1060  * @param os ostream to write to
1061  * @param val std::string value to write
1062  */ 
1063 std::ostream &binary_write(std::ostream &os, std::string const &val)
1064 {
1065    return os.write(val.c_str(), val.size());
1066 }
1067
1068 /**
1069  * \brief  binary_write binary_write
1070  * @param os ostream to write to
1071  * @param val 8 bits 'characters' aray to write
1072  * @param len length of the 'value' to be written
1073  */ 
1074 std::ostream &binary_write(std::ostream &os, const uint8_t *val, size_t len)
1075 {
1076    // We are writting sizeof(char) thus no need to swap bytes
1077    return os.write(reinterpret_cast<const char*>(val), len);
1078 }
1079
1080 /**
1081  * \brief  binary_write binary_write
1082  * @param os ostream to write to
1083  * @param val 16 bits words aray to write
1084  * @param len length (in bytes) of the 'value' to be written 
1085  */ 
1086 std::ostream &binary_write(std::ostream &os, const uint16_t *val, size_t len)
1087 {
1088 // This is tricky since we are writting two bytes buffer. 
1089 // Be carefull with little endian vs big endian. 
1090 // Also this other trick is to allocate a small (efficient) buffer that store
1091 // intermediate result before writting it.
1092 #if defined(GDCM_WORDS_BIGENDIAN) || defined(GDCM_FORCE_BIGENDIAN_EMULATION)
1093    const int BUFFER_SIZE = 4096;
1094    static char buffer[BUFFER_SIZE];
1095    uint16_t *binArea16 = (uint16_t*)val; //for the const
1096  
1097    // how many BUFFER_SIZE long pieces in binArea ?
1098    int nbPieces = len/BUFFER_SIZE; //(16 bits = 2 Bytes)
1099    int remainingSize = len%BUFFER_SIZE;
1100
1101    for (int j=0;j<nbPieces;j++)
1102    {
1103       uint16_t *pbuffer  = (uint16_t*)buffer; //reinitialize pbuffer
1104       for (int i = 0; i < BUFFER_SIZE/2; i++)
1105       {
1106          *pbuffer = *binArea16 >> 8 | *binArea16 << 8;
1107          pbuffer++;
1108          binArea16++;
1109       }
1110       os.write ( buffer, BUFFER_SIZE );
1111    }
1112    if ( remainingSize > 0)
1113    {
1114       uint16_t *pbuffer  = (uint16_t*)buffer; //reinitialize pbuffer
1115       for (int i = 0; i < remainingSize/2; i++)
1116       {
1117          *pbuffer = *binArea16 >> 8 | *binArea16 << 8;
1118          pbuffer++;
1119          binArea16++;
1120       }
1121       os.write ( buffer, remainingSize );
1122    }
1123    return os;
1124 #else
1125    return os.write(reinterpret_cast<const char*>(val), len);
1126 #endif
1127 }
1128
1129 std::string Util::ConvertToMD5 (std::string &inPszToCrypt)
1130 {
1131    char *szChar      = new char[ inPszToCrypt.size()+1 ];
1132    char *szHexOutput = new char[ 16 * 2 + 1 ];
1133    int nLen,nDi;
1134    strcpy( szChar, inPszToCrypt.c_str() );
1135    // création du code md5
1136    nLen = strlen( szChar );
1137    md5_state_t state;
1138    uint8_t digest[ 16 ];
1139    md5_init   ( &state );
1140    md5_append ( &state, (const uint8_t *)szChar, nLen);
1141    md5_finish ( &state, digest );
1142    for ( nDi = 0; nDi < 16; nDi++)
1143       sprintf( szHexOutput + nDi * 2, "%02x", digest[ nDi ] );
1144    szHexOutput[16 * 2]=0;
1145    delete [] szChar;
1146    std::string md5String=szHexOutput;
1147    delete [] szHexOutput;
1148    return md5String;
1149 }
1150
1151 //-------------------------------------------------------------------------
1152 // Protected
1153
1154 //-------------------------------------------------------------------------
1155 // Private
1156 /**
1157  * \brief   Return the IP adress of the machine writting the DICOM image
1158  */
1159 std::string Util::GetIPAddress()
1160 {
1161    // This is a rip from 
1162    // http://www.codeguru.com/Cpp/I-N/internet/network/article.php/c3445/
1163 #ifndef HOST_NAME_MAX
1164    // SUSv2 guarantees that `Host names are limited to 255 bytes'.
1165    // POSIX 1003.1-2001 guarantees that `Host names (not including the
1166    // terminating NUL) are limited to HOST_NAME_MAX bytes'.
1167 #define HOST_NAME_MAX 255
1168    // In this case we should maybe check the string was not truncated.
1169    // But I don't known how to check that...
1170 #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__)
1171    // with WinSock DLL we need to initialize the WinSock before using gethostname
1172    WORD wVersionRequested = MAKEWORD(1,0);
1173    WSADATA WSAData;
1174    int err = WSAStartup(wVersionRequested,&WSAData);
1175    if (err != 0)
1176    {
1177       // Tell the user that we could not find a usable
1178       // WinSock DLL.
1179       WSACleanup();
1180       return "127.0.0.1";
1181    }
1182 #endif
1183   
1184 #endif //HOST_NAME_MAX
1185
1186    std::string str;
1187    char szHostName[HOST_NAME_MAX+1];
1188    int r = gethostname(szHostName, HOST_NAME_MAX);
1189  
1190    if ( r == 0 )
1191    {
1192       // Get host adresses
1193       struct hostent *pHost = gethostbyname(szHostName);
1194  
1195       for( int i = 0; pHost!= NULL && pHost->h_addr_list[i]!= NULL; i++ )
1196       {
1197          for( int j = 0; j<pHost->h_length; j++ )
1198          {
1199             if ( j > 0 ) str += ".";
1200  
1201             str += Util::Format("%u", 
1202                 (unsigned int)((unsigned char*)pHost->h_addr_list[i])[j]);
1203          }
1204          // str now contains one local IP address 
1205  
1206 #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__)
1207    WSACleanup();
1208 #endif
1209
1210       }
1211    }
1212    // If an error occur r == -1
1213    // Most of the time it will return 127.0.0.1...
1214    return str;
1215 }
1216
1217 void Util::hfpswap(double *a, double *b)
1218 {
1219    double tmp;
1220    tmp=*a;
1221    *a=*b;
1222    *b=tmp;
1223 }
1224
1225 // for MD5
1226 /*
1227   Copyright (C) 1999, 2000, 2002 Aladdin Enterprises.  All rights reserved.
1228
1229   This software is provided 'as-is', without any express or implied
1230   warranty.  In no event will the authors be held liable for any damages
1231   arising from the use of this software.
1232
1233   Permission is granted to anyone to use this software for any purpose,
1234   including commercial applications, and to alter it and redistribute it
1235   freely, subject to the following restrictions:
1236
1237   1. The origin of this software must not be misrepresented; you must not
1238      claim that you wrote the original software. If you use this software
1239      in a product, an acknowledgment in the product documentation would be
1240      appreciated but is not required.
1241   2. Altered source versions must be plainly marked as such, and must not be
1242      misrepresented as being the original software.
1243   3. This notice may not be removed or altered from any source distribution.
1244
1245   L. Peter Deutsch
1246
1247   ghost@aladdin.com
1248  */
1249
1250 /* $Id: gdcmUtil.cxx,v 1.187 2007/05/23 14:18:11 jpr Exp $ */
1251
1252 /*
1253   Independent implementation of MD5 (RFC 1321).
1254   This code implements the MD5 Algorithm defined in RFC 1321, whose
1255   text is available at
1256
1257  http://www.ietf.org/rfc/rfc1321.txt
1258
1259   The code is derived from the text of the RFC, including the test suite
1260   (section A.5) but excluding the rest of Appendix A.  It does not include
1261   any code or documentation that is identified in the RFC as being
1262   copyrighted.
1263
1264   The original and principal author of md5.c is L. Peter Deutsch
1265   <ghost@aladdin.com>.  Other authors are noted in the change history
1266   that follows (in reverse chronological order):
1267
1268   2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
1269       either statically or dynamically; added missing #include <string.h>
1270       in library.
1271   2002-03-11 lpd Corrected argument list for main(), and added int return
1272       type, in test program and T value program.
1273   2002-02-21 lpd Added missing #include <stdio.h> in test program.
1274   2000-07-03 lpd Patched to eliminate warnings about "constant is
1275       unsigned in ANSI C, signed in traditional"; made test program
1276       self-checking.
1277   1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
1278   1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
1279   1999-05-03 lpd Original version.
1280  */
1281
1282 //#include "md5.h"
1283 //#include <string.h>
1284
1285 #undef BYTE_ORDER     /* 1 = big-endian, -1 = little-endian, 0 = unknown */
1286 #ifdef ARCH_IS_BIG_ENDIAN
1287 #  define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
1288 #else
1289 #  define BYTE_ORDER 0
1290 #endif
1291
1292
1293 #define T_MASK ((uint16_t)~0)
1294 #define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
1295 #define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
1296 #define T3    0x242070db
1297 #define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
1298 #define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
1299 #define T6    0x4787c62a
1300 #define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
1301 #define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
1302 #define T9    0x698098d8
1303 #define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
1304 #define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
1305 #define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
1306 #define T13    0x6b901122
1307 #define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
1308 #define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
1309 #define T16    0x49b40821
1310 #define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
1311 #define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
1312 #define T19    0x265e5a51
1313 #define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
1314 #define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
1315 #define T22    0x02441453
1316 #define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
1317 #define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
1318 #define T25    0x21e1cde6
1319 #define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
1320 #define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
1321 #define T28    0x455a14ed
1322 #define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
1323 #define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
1324 #define T31    0x676f02d9
1325 #define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
1326 #define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
1327 #define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
1328 #define T35    0x6d9d6122
1329 #define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
1330 #define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
1331 #define T38    0x4bdecfa9
1332 #define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
1333 #define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
1334 #define T41    0x289b7ec6
1335 #define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
1336 #define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
1337 #define T44    0x04881d05
1338 #define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
1339 #define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
1340 #define T47    0x1fa27cf8
1341 #define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
1342 #define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
1343 #define T50    0x432aff97
1344 #define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
1345 #define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
1346 #define T53    0x655b59c3
1347 #define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
1348 #define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
1349 #define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
1350 #define T57    0x6fa87e4f
1351 #define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
1352 #define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
1353 #define T60    0x4e0811a1
1354 #define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
1355 #define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
1356 #define T63    0x2ad7d2bb
1357 #define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
1358
1359
1360 void
1361 Util::md5_process(md5_state_t *pms, const uint8_t *data /*[64]*/)
1362 {
1363     uint16_t
1364     a = pms->abcd[0], b = pms->abcd[1],
1365     c = pms->abcd[2], d = pms->abcd[3];
1366     uint16_t t;
1367
1368 #if BYTE_ORDER > 0
1369     /* Define storage only for big-endian CPUs. */
1370     uint16_t X[16];
1371 #else
1372     /* Define storage for little-endian or both types of CPUs. */
1373     uint16_t xbuf[16];
1374     const uint16_t *X;
1375 #endif
1376     {
1377 #if BYTE_ORDER == 0
1378 /*
1379  * Determine dynamically whether this is a big-endian or
1380  * little-endian machine, since we can use a more efficient
1381  * algorithm on the latter.
1382  */
1383 static const int w = 1;
1384
1385 if (*((const uint8_t *)&w)) /* dynamic little-endian */
1386 #endif
1387 #if BYTE_ORDER <= 0  /* little-endian */
1388 {
1389     /*
1390      * On little-endian machines, we can process properly aligned
1391      * data without copying it.
1392      */
1393     if (!((data - (const uint8_t *)0) & 3)) {
1394     /* data are properly aligned */
1395        X = (const uint16_t *)data;
1396     } else {
1397      /* not aligned */
1398      memcpy(xbuf, data, 64);
1399      X = xbuf;
1400     }
1401 }
1402 #endif
1403 #if BYTE_ORDER == 0
1404 else  /* dynamic big-endian */
1405 #endif
1406 #if BYTE_ORDER >= 0 /* big-endian */
1407 {
1408     /*
1409      * On big-endian machines, we must arrange the bytes in the
1410      * right order.
1411      */
1412     const uint8_t *xp = data;
1413     int i;
1414
1415 #  if BYTE_ORDER == 0
1416      X = xbuf; /* (dynamic only) */
1417 #  else
1418 #    define xbuf /* (static only)  */
1419 #  endif
1420       for (i = 0; i < 16; ++i, xp += 4)
1421          xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
1422       }
1423 #endif
1424     }
1425
1426 #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
1427
1428     /* Round 1. */
1429     /* Let [abcd k s i] denote the operation
1430        a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
1431
1432 #define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
1433 #define SET(a, b, c, d, k, s, Ti) \
1434      t = a + F(b,c,d) + X[k] + Ti;\
1435      a = ROTATE_LEFT(t, s) + b
1436     /* Do the following 16 operations. */
1437     SET(a, b, c, d,  0,  7,  T1);
1438     SET(d, a, b, c,  1, 12,  T2);
1439     SET(c, d, a, b,  2, 17,  T3);
1440     SET(b, c, d, a,  3, 22,  T4);
1441     SET(a, b, c, d,  4,  7,  T5);
1442     SET(d, a, b, c,  5, 12,  T6);
1443     SET(c, d, a, b,  6, 17,  T7);
1444     SET(b, c, d, a,  7, 22,  T8);
1445     SET(a, b, c, d,  8,  7,  T9);
1446     SET(d, a, b, c,  9, 12, T10);
1447     SET(c, d, a, b, 10, 17, T11);
1448     SET(b, c, d, a, 11, 22, T12);
1449     SET(a, b, c, d, 12,  7, T13);
1450     SET(d, a, b, c, 13, 12, T14);
1451     SET(c, d, a, b, 14, 17, T15);
1452     SET(b, c, d, a, 15, 22, T16);
1453 #undef SET
1454      /* Round 2. */
1455      /* Let [abcd k s i] denote the operation
1456           a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
1457
1458 #define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
1459 #define SET(a, b, c, d, k, s, Ti)\
1460   t = a + G(b,c,d) + X[k] + Ti;  \
1461   a = ROTATE_LEFT(t, s) + b
1462      /* Do the following 16 operations. */
1463     SET(a, b, c, d,  1,  5, T17);
1464     SET(d, a, b, c,  6,  9, T18);
1465     SET(c, d, a, b, 11, 14, T19);
1466     SET(b, c, d, a,  0, 20, T20);
1467     SET(a, b, c, d,  5,  5, T21);
1468     SET(d, a, b, c, 10,  9, T22);
1469     SET(c, d, a, b, 15, 14, T23);
1470     SET(b, c, d, a,  4, 20, T24);
1471     SET(a, b, c, d,  9,  5, T25);
1472     SET(d, a, b, c, 14,  9, T26);
1473     SET(c, d, a, b,  3, 14, T27);
1474     SET(b, c, d, a,  8, 20, T28);
1475     SET(a, b, c, d, 13,  5, T29);
1476     SET(d, a, b, c,  2,  9, T30);
1477     SET(c, d, a, b,  7, 14, T31);
1478     SET(b, c, d, a, 12, 20, T32);
1479 #undef SET
1480      /* Round 3. */
1481      /* Let [abcd k s t] denote the operation
1482           a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
1483 #define H(x, y, z) ((x) ^ (y) ^ (z))
1484 #define SET(a, b, c, d, k, s, Ti)\
1485   t = a + H(b,c,d) + X[k] + Ti;  \
1486   a = ROTATE_LEFT(t, s) + b
1487   
1488      /* Do the following 16 operations. */
1489     SET(a, b, c, d,  5,  4, T33);
1490     SET(d, a, b, c,  8, 11, T34);
1491     SET(c, d, a, b, 11, 16, T35);
1492     SET(b, c, d, a, 14, 23, T36);
1493     SET(a, b, c, d,  1,  4, T37);
1494     SET(d, a, b, c,  4, 11, T38);
1495     SET(c, d, a, b,  7, 16, T39);
1496     SET(b, c, d, a, 10, 23, T40);
1497     SET(a, b, c, d, 13,  4, T41);
1498     SET(d, a, b, c,  0, 11, T42);
1499     SET(c, d, a, b,  3, 16, T43);
1500     SET(b, c, d, a,  6, 23, T44);
1501     SET(a, b, c, d,  9,  4, T45);
1502     SET(d, a, b, c, 12, 11, T46);
1503     SET(c, d, a, b, 15, 16, T47);
1504     SET(b, c, d, a,  2, 23, T48);
1505 #undef SET
1506      /* Round 4. */
1507      /* Let [abcd k s t] denote the operation
1508           a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
1509 #define I(x, y, z) ((y) ^ ((x) | ~(z)))
1510 #define SET(a, b, c, d, k, s, Ti)\
1511   t = a + I(b,c,d) + X[k] + Ti;  \
1512   a = ROTATE_LEFT(t, s) + b
1513   
1514      /* Do the following 16 operations. */
1515     SET(a, b, c, d,  0,  6, T49);
1516     SET(d, a, b, c,  7, 10, T50);
1517     SET(c, d, a, b, 14, 15, T51);
1518     SET(b, c, d, a,  5, 21, T52);
1519     SET(a, b, c, d, 12,  6, T53);
1520     SET(d, a, b, c,  3, 10, T54);
1521     SET(c, d, a, b, 10, 15, T55);
1522     SET(b, c, d, a,  1, 21, T56);
1523     SET(a, b, c, d,  8,  6, T57);
1524     SET(d, a, b, c, 15, 10, T58);
1525     SET(c, d, a, b,  6, 15, T59);
1526     SET(b, c, d, a, 13, 21, T60);
1527     SET(a, b, c, d,  4,  6, T61);
1528     SET(d, a, b, c, 11, 10, T62);
1529     SET(c, d, a, b,  2, 15, T63);
1530     SET(b, c, d, a,  9, 21, T64);
1531
1532 #undef SET
1533      /* Then perform the following additions. (That is increment each
1534         of the four registers by the value it had before this block
1535         was started.) */
1536     pms->abcd[0] += a;
1537     pms->abcd[1] += b;
1538     pms->abcd[2] += c;
1539     pms->abcd[3] += d;
1540 }
1541 void
1542 Util::md5_init(md5_state_t *pms)
1543 {
1544     pms->count[0] = pms->count[1] = 0;
1545     pms->abcd[0] = 0x67452301;
1546     pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
1547     pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
1548     pms->abcd[3] = 0x10325476;
1549 }
1550
1551
1552 void
1553 Util::md5_append(md5_state_t *pms, const uint8_t *data, int nbytes)
1554 {
1555     const uint8_t *p = data;
1556     int left = nbytes;
1557     int offset = (pms->count[0] >> 3) & 63;
1558     uint16_t nbits = (uint16_t)(nbytes << 3);
1559     if (nbytes <= 0)
1560        return;
1561     /* Update the message length. */
1562     pms->count[1] += nbytes >> 29;
1563     pms->count[0] += nbits;
1564     if (pms->count[0] < nbits)
1565        pms->count[1]++;
1566     /* Process an initial partial block. */
1567     if (offset) {
1568        int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
1569        memcpy(pms->buf + offset, p, copy);
1570        if (offset + copy < 64)
1571           return;
1572        p += copy;
1573        left -= copy;
1574        md5_process(pms, pms->buf);
1575     }
1576     /* Process full blocks. */
1577     for (; left >= 64; p += 64, left -= 64)
1578       md5_process(pms, p);
1579     /* Process a final partial block. */
1580     if (left)
1581       memcpy(pms->buf, p, left);
1582 }
1583 void
1584 Util::md5_finish(md5_state_t *pms, uint8_t digest[16])
1585 {
1586     static const uint8_t pad[64] = {
1587        0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1588        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1589        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1590        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
1591     };
1592
1593     uint8_t data[8];
1594     int i;
1595     /* Save the length before padding. */
1596     for (i = 0; i < 8; ++i)
1597        data[i] = (uint8_t)(pms->count[i >> 2] >> ((i & 3) << 3));
1598     /* Pad to 56 bytes mod 64. */
1599     md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
1600     /* Append the length. */
1601     md5_append(pms, data, 8);
1602     for (i = 0; i < 16; ++i)
1603       digest[i] = (uint8_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
1604 }
1605
1606 //-------------------------------------------------------------------------
1607 } // end namespace gdcm
1608