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