gdcmUtil.cxx

Go to the documentation of this file.
00001 /*=========================================================================
00002                                                                                 
00003   Program:   gdcm
00004   Module:    $RCSfile: gdcmUtil.cxx,v $
00005   Language:  C++
00006   Date:      $Date: 2007/05/23 14:18:11 $
00007   Version:   $Revision: 1.187 $
00008                                                                                 
00009   Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
00010   l'Image). All rights reserved. See Doc/License.txt or
00011   http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details.
00012                                                                                 
00013      This software is distributed WITHOUT ANY WARRANTY; without even
00014      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
00015      PURPOSE.  See the above copyright notices for more information.
00016                                                                                 
00017 =========================================================================*/
00018 
00019 #include "gdcmUtil.h"
00020 #include "gdcmDebug.h"
00021 
00022 #include <iostream>
00023 #include <stdarg.h> // for va_list
00024 
00025 // For GetCurrentDate, GetCurrentTime
00026 #include <time.h>
00027 #include <sys/types.h>
00028 #include <sys/stat.h>
00029 
00030 #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__)
00031 #include <sys/timeb.h>
00032 #else
00033 #include <sys/time.h>
00034 #endif
00035 
00036 #include <stdarg.h>  //only included in implementation file
00037 #include <stdio.h>   //only included in implementation file
00038 
00039 #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__)
00040    #include <winsock.h>  // for gethostname and gethostbyname and GetTickCount...
00041 // I haven't find a way to determine wether we need to under GetCurrentTime or not...
00042 // I think the best solution would simply to get rid of this problematic function
00043 // and use a 'less' common name...
00044 #if !defined(__BORLANDC__) || (__BORLANDC__ >= 0x0560)
00045    #undef GetCurrentTime
00046 #endif
00047 #else
00048    #include <unistd.h>  // for gethostname
00049    #include <netdb.h>   // for gethostbyname
00050 #endif
00051 
00052 // For GetMACAddress
00053 #ifdef _WIN32
00054    #include <snmp.h>
00055    #include <conio.h>
00056 #else
00057    #include <unistd.h>
00058    #include <stdlib.h>
00059    #include <string.h>
00060    #include <sys/types.h>
00061 #endif
00062 
00063 #ifdef CMAKE_HAVE_SYS_IOCTL_H
00064    #include <sys/ioctl.h>  // For SIOCGIFCONF on Linux
00065 #endif
00066 #ifdef CMAKE_HAVE_SYS_SOCKET_H
00067    #include <sys/socket.h>
00068 #endif
00069 #ifdef CMAKE_HAVE_SYS_SOCKIO_H
00070    #include <sys/sockio.h>  // For SIOCGIFCONF on SunOS
00071 #endif
00072 #ifdef CMAKE_HAVE_NET_IF_H
00073    #include <net/if.h>
00074 #endif
00075 #ifdef CMAKE_HAVE_NETINET_IN_H
00076    #include <netinet/in.h>   //For IPPROTO_IP
00077 #endif
00078 #ifdef CMAKE_HAVE_NET_IF_DL_H
00079    #include <net/if_dl.h>
00080 #endif
00081 #if defined(CMAKE_HAVE_NET_IF_ARP_H) && defined(__sun)
00082    // This is absolutely necessary on SunOS
00083    #include <net/if_arp.h>
00084 #endif
00085 
00086 // For GetCurrentThreadID()
00087 #ifdef __linux__
00088    #include <sys/types.h>
00089    #include <linux/unistd.h>
00090 #endif
00091 #ifdef __sun
00092    #include <thread.h>
00093 #endif
00094 
00095 namespace GDCM_NAME_SPACE
00096 {
00097 //-------------------------------------------------------------------------
00098 const std::string Util::GDCM_UID = "1.2.826.0.1.3680043.2.1143";
00099 std::string Util::RootUID        = GDCM_UID;
00100 /*
00101  * File Meta Information Version (0002,0001) shall contain a two byte OB 
00102  * value consisting of a 0x00 byte, followed by 0x01 byte, and not the 
00103  * value 0x0001 encoded as a little endian 16 bit short value, 
00104  * which would be the other way around...
00105  */
00106 const uint16_t Util::FMIV = 0x0100;
00107 uint8_t *Util::FileMetaInformationVersion = (uint8_t *)&FMIV;
00108 std::string Util::GDCM_MAC_ADRESS = GetMACAddress();
00109 
00110 //-------------------------------------------------------------------------
00111 // Public
00129 std::string Util::Format(const char *format, ...)
00130 {
00131    char buffer[2048]; // hope 2048 is enough
00132    va_list args;
00133    va_start(args, format);
00134    vsprintf(buffer, format, args);  //might be a security flaw
00135    va_end(args); // Each invocation of va_start should be matched 
00136                  // by a corresponding invocation of va_end
00137                  // args is then 'undefined'
00138    return buffer;
00139 }
00140 
00141 
00149 void Util::Tokenize (const std::string &str,
00150                      std::vector<std::string> &tokens,
00151                      const std::string &delimiters)
00152 {
00153    std::string::size_type lastPos = str.find_first_not_of(delimiters,0);
00154    std::string::size_type pos     = str.find_first_of    (delimiters,lastPos);
00155    while (std::string::npos != pos || std::string::npos != lastPos)
00156    {
00157       tokens.push_back(str.substr(lastPos, pos - lastPos));
00158       lastPos = str.find_first_not_of(delimiters, pos);
00159       pos     = str.find_first_of    (delimiters, lastPos);
00160    }
00161 }
00162 
00170 int Util::CountSubstring (const std::string &str,
00171                           const std::string &subStr)
00172 {
00173    int count = 0;                 // counts how many times it appears
00174    std::string::size_type x = 0;  // The index position in the string
00175 
00176    do
00177    {
00178       x = str.find(subStr,x);     // Find the substring
00179       if (x != std::string::npos) // If present
00180       {
00181          count++;                 // increase the count
00182          x += subStr.length();    // Skip this word
00183       }
00184    }
00185    while (x != std::string::npos);// Carry on until not present
00186 
00187    return count;
00188 }
00189 
00195 bool Util::IsCleanString(std::string const &s)
00196 {
00197    for(unsigned int i=0; i<s.size(); i++)
00198    {
00199       if (!isprint((unsigned char)s[i]) )
00200       {
00201          return false;
00202       }
00203    }
00204    return true;   
00205 }
00206 
00213 bool Util::IsCleanArea(uint8_t *s, int l)
00214 {
00215    for( int i=0; i<l; i++)
00216    {
00217       if (!isprint((unsigned char)s[i]) )
00218       {
00219          return false;
00220       }
00221    }
00222    return true;   
00223 }
00229 std::string Util::CreateCleanString(std::string const &s)
00230 {
00231    std::string str = s;
00232 
00233    for(unsigned int i=0; i<str.size(); i++)
00234    {
00235       if (!isprint((unsigned char)str[i]) )
00236       {
00237          str[i] = '.';
00238       }
00239    }
00240 
00241    if (str.size() > 0 )
00242    {
00243       if (!isprint((unsigned char)s[str.size()-1]) )
00244       {
00245          if (s[str.size()-1] == 0 )
00246          {
00247             str[str.size()-1] = ' ';
00248          }
00249       }
00250    }
00251 
00252    return str;
00253 }
00254 
00261 std::string Util::CreateCleanString(uint8_t *s, int l)
00262 {
00263    std::string str;
00264 
00265    for( int i=0; i<l; i++)
00266    {
00267       if (!isprint((unsigned char)s[i]) )
00268       {
00269          str = str + '.';
00270       }
00271    else
00272       {
00273          str = str + (char )s[i];
00274       }
00275    }
00276 
00277    return str;
00278 }
00283 std::string Util::NormalizePath(std::string const &pathname)
00284 {
00285 /*
00286    const char SEPARATOR_X      = '/';
00287    const char SEPARATOR_WIN    = '\\';
00288 #ifdef _WIN32
00289    const std::string SEPARATOR = "\\";
00290 #else
00291    const std::string SEPARATOR = "/";
00292 #endif
00293 */
00294    std::string name = pathname;
00295    int size = name.size();
00296 
00297 //   if ( name[size-1] != SEPARATOR_X && name[size-1] != SEPARATOR_WIN )
00298    if ( name[size-1] != GDCM_FILESEPARATOR )
00299    {
00300       name += GDCM_FILESEPARATOR;
00301    }
00302    return name;
00303 }
00304 
00309 std::string Util::GetPath(std::string const &fullName)
00310 {
00311    std::string res = fullName;
00312 /*
00313    
00314    int pos1 = res.rfind("/");
00315    int pos2 = res.rfind("\\");
00316    if ( pos1 > pos2 )
00317    {
00318       res.resize(pos1);
00319    }
00320    else
00321    {
00322       res.resize(pos2);
00323    }
00324 */
00325    int pos = res.rfind(GDCM_FILESEPARATOR);
00326    res.resize(pos);
00327    return res;
00328 }
00329 
00334 std::string Util::GetName(std::string const &fullName)
00335 {   
00336   std::string filename = fullName;
00337 /*
00338   std::string::size_type slash_pos = filename.rfind("/");
00339   std::string::size_type backslash_pos = filename.rfind("\\");
00340   // At least with my gcc4.0.1, unfound char results in pos =4294967295 ...
00341   //slash_pos = slash_pos > backslash_pos ? slash_pos : backslash_pos;  
00342   slash_pos = slash_pos < backslash_pos ? slash_pos : backslash_pos;
00343 */
00344   std::string::size_type slash_pos = filename.rfind(GDCM_FILESEPARATOR);
00345   if (slash_pos != std::string::npos )
00346     {
00347     return filename.substr(slash_pos + 1);
00348     }
00349   else
00350     {
00351     return filename;
00352     }
00353 } 
00354 
00358 std::string Util::GetCurrentDate()
00359 {
00360     char tmp[512];
00361     time_t tloc;
00362     time (&tloc);    
00363     strftime(tmp,512,"%Y%m%d", localtime(&tloc) );
00364     return tmp;
00365 }
00366 
00370 std::string Util::GetCurrentTime()
00371 {
00372     char tmp[512];
00373     time_t tloc;
00374     time (&tloc);
00375     strftime(tmp,512,"%H%M%S", localtime(&tloc) );
00376     return tmp;  
00377 }
00378 
00383 std::string Util::GetCurrentDateTime()
00384 {
00385    char tmp[40];
00386    long milliseconds;
00387    time_t timep;
00388   
00389    // We need implementation specific functions to obtain millisecond precision
00390 #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__)
00391    struct timeb tb;
00392    ::ftime(&tb);
00393    timep = tb.time;
00394    milliseconds = tb.millitm;
00395 #else
00396    struct timeval tv;
00397    gettimeofday (&tv, NULL);
00398    timep = tv.tv_sec;
00399    // Compute milliseconds from microseconds.
00400    milliseconds = tv.tv_usec / 1000;
00401 #endif
00402    // Obtain the time of day, and convert it to a tm struct.
00403    struct tm *ptm = localtime (&timep);
00404    // Format the date and time, down to a single second.
00405    strftime (tmp, sizeof (tmp), "%Y%m%d%H%M%S", ptm);
00406 
00407    // Add milliseconds
00408    // Don't use Util::Format to accelerate execution of code
00409    char tmpAll[80];
00410    sprintf(tmpAll,"%s%03ld",tmp,milliseconds);
00411 
00412    return tmpAll;
00413 }
00414 
00415 unsigned int Util::GetCurrentThreadID()
00416 {
00417 // FIXME the implementation is far from complete
00418 #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__)
00419   return (unsigned int)GetCurrentThreadId();
00420 #else
00421 #ifdef __linux__
00422    return 0;
00423    // Doesn't work on fedora, but is in the man page...
00424    //return (unsigned int)gettid();
00425 #else
00426 #ifdef __sun
00427    return (unsigned int)thr_self();
00428 #else
00429    //default implementation
00430    return 0;
00431 #endif // __sun
00432 #endif // __linux__
00433 #endif // Win32
00434 }
00435 
00436 unsigned int Util::GetCurrentProcessID()
00437 {
00438 #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__)
00439   // NOTE: There is also a _getpid()...
00440   return (unsigned int)GetCurrentProcessId();
00441 #else
00442   // get process identification, POSIX
00443   return (unsigned int)getpid();
00444 #endif
00445 }
00446 
00450 bool Util::IsCurrentProcessorBigEndian()
00451 {
00452 #if defined(GDCM_WORDS_BIGENDIAN)
00453    return true;
00454 #else
00455    return false;
00456 #endif
00457 }
00458 
00467 std::string Util::DicomString(const char *s, size_t l)
00468 {
00469    std::string r(s, s+l);
00470    gdcmAssertMacro( !(r.size() % 2) ); // == basically 'l' is even
00471    return r;
00472 }
00473 
00485 std::string Util::DicomString(const char *s)
00486 {
00487    size_t l = strlen(s);
00488    if ( l%2 )
00489    {
00490       l++;
00491    }
00492    std::string r(s, s+l);
00493    gdcmAssertMacro( !(r.size() % 2) );
00494    return r;
00495 }
00496 
00503 bool Util::DicomStringEqual(const std::string &s1, const char *s2)
00504 {
00505   // s2 is the string from the DICOM reference e.g. : 'MONOCHROME1'
00506   std::string s1_even = s1; //Never change input parameter
00507   std::string s2_even = DicomString( s2 );
00508   if ( s1_even[s1_even.size()-1] == ' ' )
00509   {
00510     s1_even[s1_even.size()-1] = '\0'; //replace space character by null
00511   }
00512   return s1_even == s2_even;
00513 }
00514 
00521 bool Util::CompareDicomString(const std::string &s1, const char *s2, int op)
00522 {
00523   // s2 is the string from the DICOM reference e.g. : 'MONOCHROME1'
00524   std::string s1_even = s1; //Never change input parameter
00525   std::string s2_even = DicomString( s2 );
00526   if ( s1_even[s1_even.size()-1] == ' ' )
00527   {
00528     s1_even[s1_even.size()-1] = '\0'; //replace space character by null
00529   }
00530   switch (op)
00531   {
00532      case GDCM_EQUAL :
00533         return s1_even == s2_even;
00534      case GDCM_DIFFERENT :  
00535         return s1_even != s2_even;
00536      case GDCM_GREATER :  
00537         return s1_even >  s2_even;  
00538      case GDCM_GREATEROREQUAL :  
00539         return s1_even >= s2_even;
00540      case GDCM_LESS :
00541         return s1_even <  s2_even;
00542      case GDCM_LESSOREQUAL :
00543         return s1_even <= s2_even;
00544      default :
00545         gdcmDebugMacro(" Wrong operator : " << op);
00546         return false;
00547   }
00548 }
00549 
00550 #ifdef _WIN32
00551    typedef BOOL(WINAPI * pSnmpExtensionInit) (
00552            IN DWORD dwTimeZeroReference,
00553            OUT HANDLE * hPollForTrapEvent,
00554            OUT AsnObjectIdentifier * supportedView);
00555 
00556    typedef BOOL(WINAPI * pSnmpExtensionTrap) (
00557            OUT AsnObjectIdentifier * enterprise,
00558            OUT AsnInteger * genericTrap,
00559            OUT AsnInteger * specificTrap,
00560            OUT AsnTimeticks * timeStamp,
00561            OUT RFC1157VarBindList * variableBindings);
00562 
00563    typedef BOOL(WINAPI * pSnmpExtensionQuery) (
00564            IN BYTE requestType,
00565            IN OUT RFC1157VarBindList * variableBindings,
00566            OUT AsnInteger * errorStatus,
00567            OUT AsnInteger * errorIndex);
00568 
00569    typedef BOOL(WINAPI * pSnmpExtensionInitEx) (
00570            OUT AsnObjectIdentifier * supportedView);
00571 #endif //_WIN32
00572 
00573 #ifdef __sgi
00574 static int SGIGetMacAddress(unsigned char *addr)
00575 {
00576   FILE *f = popen("/etc/nvram eaddr","r");
00577   if(f == 0)
00578     {
00579     return -1;
00580     }
00581   unsigned int x[6];
00582   if(fscanf(f,"%02x:%02x:%02x:%02x:%02x:%02x",
00583             x,x+1,x+2,x+3,x+4,x+5) != 6)
00584     {
00585     pclose(f);
00586     return -1;
00587     }
00588   for(unsigned int i = 0; i < 6; i++)
00589     {
00590     addr[i] = static_cast<unsigned char>(x[i]);
00591     }
00592   return 0;
00593 }
00594 #endif
00595 
00597 int GetMacAddrSys ( unsigned char *addr );
00598 int GetMacAddrSys ( unsigned char *addr )
00599 {
00600 #ifdef _WIN32
00601    WSADATA WinsockData;
00602    if ( (WSAStartup(MAKEWORD(2, 0), &WinsockData)) != 0 ) 
00603    {
00604       std::cerr << "in Get MAC Adress (internal) : This program requires Winsock 2.x!" 
00605              << std::endl;
00606       return -1;
00607    }
00608 
00609    HANDLE PollForTrapEvent;
00610    AsnObjectIdentifier SupportedView;
00611    UINT OID_ifEntryType[]  = { 1, 3, 6, 1, 2, 1, 2, 2, 1, 3 };
00612    UINT OID_ifEntryNum[]   = { 1, 3, 6, 1, 2, 1, 2, 1 };
00613    UINT OID_ipMACEntAddr[] = { 1, 3, 6, 1, 2, 1, 2, 2, 1, 6 };
00614    AsnObjectIdentifier MIB_ifMACEntAddr = {
00615        sizeof(OID_ipMACEntAddr) / sizeof(UINT), OID_ipMACEntAddr };
00616    AsnObjectIdentifier MIB_ifEntryType = {
00617        sizeof(OID_ifEntryType) / sizeof(UINT), OID_ifEntryType };
00618    AsnObjectIdentifier MIB_ifEntryNum = {
00619        sizeof(OID_ifEntryNum) / sizeof(UINT), OID_ifEntryNum };
00620    RFC1157VarBindList varBindList;
00621    RFC1157VarBind varBind[2];
00622    AsnInteger errorStatus;
00623    AsnInteger errorIndex;
00624    AsnObjectIdentifier MIB_NULL = { 0, 0 };
00625    int ret;
00626    int dtmp;
00627    int j = 0;
00628 
00629    // Load the SNMP dll and get the addresses of the functions necessary
00630    HINSTANCE m_hInst = LoadLibrary("inetmib1.dll");
00631    if (m_hInst < (HINSTANCE) HINSTANCE_ERROR)
00632    {
00633       return -1;
00634    }
00635    pSnmpExtensionInit m_Init =
00636        (pSnmpExtensionInit) GetProcAddress(m_hInst, "SnmpExtensionInit");
00637    pSnmpExtensionQuery m_Query =
00638        (pSnmpExtensionQuery) GetProcAddress(m_hInst, "SnmpExtensionQuery");
00639    m_Init(GetTickCount(), &PollForTrapEvent, &SupportedView);
00640 
00641    /* Initialize the variable list to be retrieved by m_Query */
00642    varBindList.list = varBind;
00643    varBind[0].name = MIB_NULL;
00644    varBind[1].name = MIB_NULL;
00645 
00646    // Copy in the OID to find the number of entries in the
00647    // Inteface table
00648    varBindList.len = 1;        // Only retrieving one item
00649    SNMP_oidcpy(&varBind[0].name, &MIB_ifEntryNum);
00650    m_Query(ASN_RFC1157_GETNEXTREQUEST, &varBindList, &errorStatus,
00651                  &errorIndex);
00652 //   printf("# of adapters in this system : %i\n",
00653 //          varBind[0].value.asnValue.number);
00654    varBindList.len = 2;
00655 
00656    // Copy in the OID of ifType, the type of interface
00657    SNMP_oidcpy(&varBind[0].name, &MIB_ifEntryType);
00658 
00659    // Copy in the OID of ifPhysAddress, the address
00660    SNMP_oidcpy(&varBind[1].name, &MIB_ifMACEntAddr);
00661 
00662    do
00663    {
00664       // Submit the query.  Responses will be loaded into varBindList.
00665       // We can expect this call to succeed a # of times corresponding
00666       // to the # of adapters reported to be in the system
00667       ret = m_Query(ASN_RFC1157_GETNEXTREQUEST, &varBindList, &errorStatus,
00668                     &errorIndex); 
00669       if (!ret)
00670       {
00671          ret = 1;
00672       }
00673       else
00674       {
00675          // Confirm that the proper type has been returned
00676          ret = SNMP_oidncmp(&varBind[0].name, &MIB_ifEntryType,
00677                             MIB_ifEntryType.idLength);
00678       }
00679       if (!ret)
00680       {
00681          j++;
00682          dtmp = varBind[0].value.asnValue.number;
00683 
00684          // Type 6 describes ethernet interfaces
00685          if (dtmp == 6)
00686          {
00687             // Confirm that we have an address here
00688             ret = SNMP_oidncmp(&varBind[1].name, &MIB_ifMACEntAddr,
00689                                MIB_ifMACEntAddr.idLength);
00690             if ( !ret && varBind[1].value.asnValue.address.stream != NULL )
00691             {
00692                if ( (varBind[1].value.asnValue.address.stream[0] == 0x44)
00693                  && (varBind[1].value.asnValue.address.stream[1] == 0x45)
00694                  && (varBind[1].value.asnValue.address.stream[2] == 0x53)
00695                  && (varBind[1].value.asnValue.address.stream[3] == 0x54)
00696                  && (varBind[1].value.asnValue.address.stream[4] == 0x00) )
00697                {
00698                    // Ignore all dial-up networking adapters
00699                    std::cerr << "in Get MAC Adress (internal) : Interface #" 
00700                              << j << " is a DUN adapter\n";
00701                    continue;
00702                }
00703                if ( (varBind[1].value.asnValue.address.stream[0] == 0x00)
00704                  && (varBind[1].value.asnValue.address.stream[1] == 0x00)
00705                  && (varBind[1].value.asnValue.address.stream[2] == 0x00)
00706                  && (varBind[1].value.asnValue.address.stream[3] == 0x00)
00707                  && (varBind[1].value.asnValue.address.stream[4] == 0x00)
00708                  && (varBind[1].value.asnValue.address.stream[5] == 0x00) )
00709                {
00710                   // Ignore NULL addresses returned by other network
00711                   // interfaces
00712                   std::cerr << "in Get MAC Adress (internal) :  Interface #" 
00713                             << j << " is a NULL address\n";
00714                   continue;
00715                }
00716                memcpy( addr, varBind[1].value.asnValue.address.stream, 6);
00717             }
00718          }
00719       }
00720    } while (!ret);
00721 
00722    // Free the bindings
00723    SNMP_FreeVarBind(&varBind[0]);
00724    SNMP_FreeVarBind(&varBind[1]);
00725    return 0;
00726 #endif //Win32 version
00727 
00728 #if defined(__sgi)
00729    return SGIGetMacAddress(addr);
00730 #endif // __sgi
00731 
00732 
00733 // implementation for POSIX system
00734 #if defined(CMAKE_HAVE_NET_IF_ARP_H) && defined(__sun)
00735    //The POSIX version is broken anyway on Solaris, plus would require full
00736    //root power
00737    struct  arpreq          parpreq;
00738    struct  sockaddr_in     *psa;
00739    struct  hostent         *phost;
00740    char                    hostname[MAXHOSTNAMELEN];
00741    char                    **paddrs;
00742    int                     sock, status=0;
00743 
00744    if (gethostname(hostname,  MAXHOSTNAMELEN) != 0 )
00745    {
00746       perror("in Get MAC Adress (internal) : gethostname");
00747       return -1;
00748    }
00749    phost = gethostbyname(hostname);
00750    paddrs = phost->h_addr_list;
00751 
00752    sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
00753    if (sock == -1 )
00754    {
00755       perror("in Get MAC Adress (internal) : sock");
00756       return -1;
00757    }
00758    memset(&parpreq, 0, sizeof(struct arpreq));
00759    psa = (struct sockaddr_in *) &parpreq.arp_pa;
00760 
00761    memset(psa, 0, sizeof(struct sockaddr_in));
00762    psa->sin_family = AF_INET;
00763    memcpy(&psa->sin_addr, *paddrs, sizeof(struct in_addr));
00764 
00765    status = ioctl(sock, SIOCGARP, &parpreq);
00766    if (status == -1 )
00767    {
00768       perror("in Get MAC Adress (internal) : SIOCGARP");
00769       return -1;
00770    }
00771    memcpy(addr, parpreq.arp_ha.sa_data, 6);
00772 
00773    return 0;
00774 #else
00775 #ifdef CMAKE_HAVE_NET_IF_H
00776    int       sd;
00777    struct ifreq    ifr, *ifrp;
00778    struct ifconf    ifc;
00779    char buf[1024];
00780    int      n, i;
00781    unsigned char    *a;
00782 #if defined(AF_LINK) && (!defined(SIOCGIFHWADDR) && !defined(SIOCGENADDR))
00783    struct sockaddr_dl *sdlp;
00784 #endif
00785 
00786 //
00787 // BSD 4.4 defines the size of an ifreq to be
00788 // max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len
00789 // However, under earlier systems, sa_len isn't present, so the size is 
00790 // just sizeof(struct ifreq)
00791 // We should investigate the use of SIZEOF_ADDR_IFREQ
00792 //
00793 #ifdef HAVE_SA_LEN
00794    #ifndef max
00795       #define max(a,b) ((a) > (b) ? (a) : (b))
00796    #endif
00797    #define ifreq_size(i) max(sizeof(struct ifreq),\
00798         sizeof((i).ifr_name)+(i).ifr_addr.sa_len)
00799 #else
00800    #define ifreq_size(i) sizeof(struct ifreq)
00801 #endif // HAVE_SA_LEN
00802 
00803    if ( (sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0 )
00804    {
00805       return -1;
00806    }
00807    memset(buf, 0, sizeof(buf));
00808    ifc.ifc_len = sizeof(buf);
00809    ifc.ifc_buf = buf;
00810    if (ioctl (sd, SIOCGIFCONF, (char *)&ifc) < 0)
00811    {
00812       close(sd);
00813       return -1;
00814    }
00815    n = ifc.ifc_len;
00816    for (i = 0; i < n; i+= ifreq_size(*ifrp) )
00817    {
00818       ifrp = (struct ifreq *)((char *) ifc.ifc_buf+i);
00819       strncpy(ifr.ifr_name, ifrp->ifr_name, IFNAMSIZ);
00820 #ifdef SIOCGIFHWADDR
00821       if (ioctl(sd, SIOCGIFHWADDR, &ifr) < 0)
00822          continue;
00823       a = (unsigned char *) &ifr.ifr_hwaddr.sa_data;
00824 #else
00825 #ifdef SIOCGENADDR
00826       // In theory this call should also work on Sun Solaris, but apparently
00827       // SIOCGENADDR is not implemented properly thus the call 
00828       // ioctl(sd, SIOCGENADDR, &ifr) always returns errno=2 
00829       // (No such file or directory)
00830       // Furthermore the DLAPI seems to require full root access
00831       if (ioctl(sd, SIOCGENADDR, &ifr) < 0)
00832          continue;
00833       a = (unsigned char *) ifr.ifr_enaddr;
00834 #else
00835 #ifdef AF_LINK
00836       sdlp = (struct sockaddr_dl *) &ifrp->ifr_addr;
00837       if ((sdlp->sdl_family != AF_LINK) || (sdlp->sdl_alen != 6))
00838          continue;
00839       a = (unsigned char *) &sdlp->sdl_data[sdlp->sdl_nlen];
00840 #else
00841       perror("in Get MAC Adress (internal) : No way to access hardware");
00842       close(sd);
00843       return -1;
00844 #endif // AF_LINK
00845 #endif // SIOCGENADDR
00846 #endif // SIOCGIFHWADDR
00847       if (!a[0] && !a[1] && !a[2] && !a[3] && !a[4] && !a[5]) continue;
00848 
00849       if (addr) 
00850       {
00851          memcpy(addr, a, 6);
00852          close(sd);
00853          return 0;
00854       }
00855    }
00856    close(sd);
00857 #endif
00858    // Not implemented platforms (or no Ethernet cable !)
00859    
00861    //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)");
00862 
00863    // But the following -> error: invalid use of 'this' in non-member function
00864    //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)");
00865 
00866    memset(addr,0,6);
00867    return -1;
00868 #endif //__sun
00869 }
00870 
00876 inline int getlastdigit(unsigned char *data)
00877 {
00878   int extended, carry = 0;
00879   for(int i=0;i<6;i++)
00880     {
00881     extended = (carry << 8) + data[i];
00882     data[i] = extended / 10;
00883     carry = extended % 10;
00884     }
00885   return carry;
00886 }
00887 
00892 std::string Util::GetMACAddress()
00893 {
00894    // This code is the result of a long internet search to find something
00895    // as compact as possible (not OS independant). We only have to separate
00896    // 3 OS: Win32, SunOS and 'real' POSIX
00897    // http://groups-beta.google.com/group/comp.unix.solaris/msg/ad36929d783d63be
00898    // http://bdn.borland.com/article/0,1410,26040,00.html
00899    unsigned char addr[6];
00900 
00901    int stat = GetMacAddrSys(addr);
00902    if (stat == 0)
00903    {
00904       // We need to convert a 6 digit number from base 256 to base 10, using integer
00905       // would requires a 48bits one. To avoid this we have to reimplement the div + modulo 
00906       // with string only
00907       bool zero = false;
00908       int res;
00909       std::string sres;
00910       while(!zero)
00911       {
00912          res = getlastdigit(addr);
00913          sres.insert(sres.begin(), '0' + res);
00914          zero = (addr[0] == 0) && (addr[1] == 0) && (addr[2] == 0) 
00915              && (addr[3] == 0) && (addr[4] == 0) && (addr[5] == 0);
00916       }
00917 
00918       return sres;
00919    }
00920    else
00921    {
00922       gdcmStaticWarningMacro("Problem in finding the MAC Address");
00923       return "";
00924    }
00925 }
00926 
00933 std::string Util::CreateUniqueUID(const std::string &root)
00934 {
00935    std::string prefix;
00936    std::string append;
00937    if ( root.empty() )
00938    {
00939       // gdcm UID prefix, as supplied by http://www.medicalconnections.co.uk
00940       prefix = RootUID; 
00941    }
00942    else
00943    {
00944       prefix = root;
00945    }
00946 
00947    // A root was specified use it to forge our new UID:
00948    append += ".";
00949    //append += Util::GetMACAddress(); // to save CPU time
00950    append += Util::GDCM_MAC_ADRESS;
00951    append += ".";
00952    append += Util::GetCurrentDateTime();
00953    append += ".";
00954    //Also add a mini random number just in case:
00955    char tmp[10];
00956    int r = (int) (100.0*rand()/RAND_MAX);
00957    // Don't use Util::Format to accelerate the execution
00958    sprintf(tmp,"%02d", r);
00959    append += tmp;
00960 
00961    // If append is too long we need to rehash it
00962    if ( (prefix + append).size() > 64 )
00963    {
00964       gdcmStaticErrorMacro( "Size of UID is too long." );
00965       // we need a hash function to truncate this number
00966       // if only md5 was cross plateform
00967       // MD5(append);
00968    }
00969 
00970    return prefix + append;
00971 }
00972 
00973 void Util::SetRootUID(const std::string &root)
00974 {
00975    if ( root.empty() )
00976       RootUID = GDCM_UID;
00977    else
00978       RootUID = root;
00979 }
00980 
00981 const std::string &Util::GetRootUID()
00982 {
00983    return RootUID;
00984 }
00985 
00986 //-------------------------------------------------------------------------
00992 std::ostream &binary_write(std::ostream &os, const uint16_t &val)
00993 {
00994 #if defined(GDCM_WORDS_BIGENDIAN) || defined(GDCM_FORCE_BIGENDIAN_EMULATION)
00995    uint16_t swap;
00996    swap = ( val << 8 | val >> 8 );
00997 
00998    return os.write(reinterpret_cast<const char*>(&swap), 2);
00999 #else
01000    return os.write(reinterpret_cast<const char*>(&val), 2);
01001 #endif //GDCM_WORDS_BIGENDIAN
01002 }
01003 
01009 std::ostream &binary_write(std::ostream &os, const uint32_t &val)
01010 {
01011 #if defined(GDCM_WORDS_BIGENDIAN) || defined(GDCM_FORCE_BIGENDIAN_EMULATION)
01012    uint32_t swap;
01013    swap = (  (val<<24)               | ((val<<8)  & 0x00ff0000) | 
01014             ((val>>8)  & 0x0000ff00) |  (val>>24)               );
01015    return os.write(reinterpret_cast<const char*>(&swap), 4);
01016 #else
01017    return os.write(reinterpret_cast<const char*>(&val), 4);
01018 #endif //GDCM_WORDS_BIGENDIAN
01019 }
01020 
01026 std::ostream &binary_write(std::ostream &os, const double &val)
01027 {
01028 #if defined(GDCM_WORDS_BIGENDIAN) || defined(GDCM_FORCE_BIGENDIAN_EMULATION)    
01029    double swap = val;
01030    
01031    char *beg = (char *)&swap;
01032    char *end = beg + 7;
01033    char t;
01034    for (unsigned int i = 0; i<7; i++)
01035    {
01036       t    = *beg;
01037       *beg = *end;
01038       *end = t;
01039       beg++,
01040       end--;  
01041    }  
01042    return os.write(reinterpret_cast<const char*>(&swap), 8);
01043 #else
01044    return os.write(reinterpret_cast<const char*>(&val), 8);
01045 #endif //GDCM_WORDS_BIGENDIAN
01046 }
01047 
01053 std::ostream &binary_write(std::ostream &os, const char *val)
01054 {
01055    return os.write(val, strlen(val));
01056 }
01057 
01063 std::ostream &binary_write(std::ostream &os, std::string const &val)
01064 {
01065    return os.write(val.c_str(), val.size());
01066 }
01067 
01074 std::ostream &binary_write(std::ostream &os, const uint8_t *val, size_t len)
01075 {
01076    // We are writting sizeof(char) thus no need to swap bytes
01077    return os.write(reinterpret_cast<const char*>(val), len);
01078 }
01079 
01086 std::ostream &binary_write(std::ostream &os, const uint16_t *val, size_t len)
01087 {
01088 // This is tricky since we are writting two bytes buffer. 
01089 // Be carefull with little endian vs big endian. 
01090 // Also this other trick is to allocate a small (efficient) buffer that store
01091 // intermediate result before writting it.
01092 #if defined(GDCM_WORDS_BIGENDIAN) || defined(GDCM_FORCE_BIGENDIAN_EMULATION)
01093    const int BUFFER_SIZE = 4096;
01094    static char buffer[BUFFER_SIZE];
01095    uint16_t *binArea16 = (uint16_t*)val; //for the const
01096  
01097    // how many BUFFER_SIZE long pieces in binArea ?
01098    int nbPieces = len/BUFFER_SIZE; //(16 bits = 2 Bytes)
01099    int remainingSize = len%BUFFER_SIZE;
01100 
01101    for (int j=0;j<nbPieces;j++)
01102    {
01103       uint16_t *pbuffer  = (uint16_t*)buffer; //reinitialize pbuffer
01104       for (int i = 0; i < BUFFER_SIZE/2; i++)
01105       {
01106          *pbuffer = *binArea16 >> 8 | *binArea16 << 8;
01107          pbuffer++;
01108          binArea16++;
01109       }
01110       os.write ( buffer, BUFFER_SIZE );
01111    }
01112    if ( remainingSize > 0)
01113    {
01114       uint16_t *pbuffer  = (uint16_t*)buffer; //reinitialize pbuffer
01115       for (int i = 0; i < remainingSize/2; i++)
01116       {
01117          *pbuffer = *binArea16 >> 8 | *binArea16 << 8;
01118          pbuffer++;
01119          binArea16++;
01120       }
01121       os.write ( buffer, remainingSize );
01122    }
01123    return os;
01124 #else
01125    return os.write(reinterpret_cast<const char*>(val), len);
01126 #endif
01127 }
01128 
01129 std::string Util::ConvertToMD5 (std::string &inPszToCrypt)
01130 {
01131    char *szChar      = new char[ inPszToCrypt.size()+1 ];
01132    char *szHexOutput = new char[ 16 * 2 + 1 ];
01133    int nLen,nDi;
01134    strcpy( szChar, inPszToCrypt.c_str() );
01135    // création du code md5
01136    nLen = strlen( szChar );
01137    md5_state_t state;
01138    uint8_t digest[ 16 ];
01139    md5_init   ( &state );
01140    md5_append ( &state, (const uint8_t *)szChar, nLen);
01141    md5_finish ( &state, digest );
01142    for ( nDi = 0; nDi < 16; nDi++)
01143       sprintf( szHexOutput + nDi * 2, "%02x", digest[ nDi ] );
01144    szHexOutput[16 * 2]=0;
01145    delete [] szChar;
01146    std::string md5String=szHexOutput;
01147    delete [] szHexOutput;
01148    return md5String;
01149 }
01150 
01151 //-------------------------------------------------------------------------
01152 // Protected
01153 
01154 //-------------------------------------------------------------------------
01155 // Private
01159 std::string Util::GetIPAddress()
01160 {
01161    // This is a rip from 
01162    // http://www.codeguru.com/Cpp/I-N/internet/network/article.php/c3445/
01163 #ifndef HOST_NAME_MAX
01164    // SUSv2 guarantees that `Host names are limited to 255 bytes'.
01165    // POSIX 1003.1-2001 guarantees that `Host names (not including the
01166    // terminating NUL) are limited to HOST_NAME_MAX bytes'.
01167 #define HOST_NAME_MAX 255
01168    // In this case we should maybe check the string was not truncated.
01169    // But I don't known how to check that...
01170 #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__)
01171    // with WinSock DLL we need to initialize the WinSock before using gethostname
01172    WORD wVersionRequested = MAKEWORD(1,0);
01173    WSADATA WSAData;
01174    int err = WSAStartup(wVersionRequested,&WSAData);
01175    if (err != 0)
01176    {
01177       // Tell the user that we could not find a usable
01178       // WinSock DLL.
01179       WSACleanup();
01180       return "127.0.0.1";
01181    }
01182 #endif
01183   
01184 #endif //HOST_NAME_MAX
01185 
01186    std::string str;
01187    char szHostName[HOST_NAME_MAX+1];
01188    int r = gethostname(szHostName, HOST_NAME_MAX);
01189  
01190    if ( r == 0 )
01191    {
01192       // Get host adresses
01193       struct hostent *pHost = gethostbyname(szHostName);
01194  
01195       for( int i = 0; pHost!= NULL && pHost->h_addr_list[i]!= NULL; i++ )
01196       {
01197          for( int j = 0; j<pHost->h_length; j++ )
01198          {
01199             if ( j > 0 ) str += ".";
01200  
01201             str += Util::Format("%u", 
01202                 (unsigned int)((unsigned char*)pHost->h_addr_list[i])[j]);
01203          }
01204          // str now contains one local IP address 
01205  
01206 #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__)
01207    WSACleanup();
01208 #endif
01209 
01210       }
01211    }
01212    // If an error occur r == -1
01213    // Most of the time it will return 127.0.0.1...
01214    return str;
01215 }
01216 
01217 void Util::hfpswap(double *a, double *b)
01218 {
01219    double tmp;
01220    tmp=*a;
01221    *a=*b;
01222    *b=tmp;
01223 }
01224 
01225 // for MD5
01226 /*
01227   Copyright (C) 1999, 2000, 2002 Aladdin Enterprises.  All rights reserved.
01228 
01229   This software is provided 'as-is', without any express or implied
01230   warranty.  In no event will the authors be held liable for any damages
01231   arising from the use of this software.
01232 
01233   Permission is granted to anyone to use this software for any purpose,
01234   including commercial applications, and to alter it and redistribute it
01235   freely, subject to the following restrictions:
01236 
01237   1. The origin of this software must not be misrepresented; you must not
01238      claim that you wrote the original software. If you use this software
01239      in a product, an acknowledgment in the product documentation would be
01240      appreciated but is not required.
01241   2. Altered source versions must be plainly marked as such, and must not be
01242      misrepresented as being the original software.
01243   3. This notice may not be removed or altered from any source distribution.
01244 
01245   L. Peter Deutsch
01246 
01247   ghost@aladdin.com
01248  */
01249 
01250 /* $Id: gdcmUtil.cxx,v 1.187 2007/05/23 14:18:11 jpr Exp $ */
01251 
01252 /*
01253   Independent implementation of MD5 (RFC 1321).
01254   This code implements the MD5 Algorithm defined in RFC 1321, whose
01255   text is available at
01256 
01257  http://www.ietf.org/rfc/rfc1321.txt
01258 
01259   The code is derived from the text of the RFC, including the test suite
01260   (section A.5) but excluding the rest of Appendix A.  It does not include
01261   any code or documentation that is identified in the RFC as being
01262   copyrighted.
01263 
01264   The original and principal author of md5.c is L. Peter Deutsch
01265   <ghost@aladdin.com>.  Other authors are noted in the change history
01266   that follows (in reverse chronological order):
01267 
01268   2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
01269       either statically or dynamically; added missing #include <string.h>
01270       in library.
01271   2002-03-11 lpd Corrected argument list for main(), and added int return
01272       type, in test program and T value program.
01273   2002-02-21 lpd Added missing #include <stdio.h> in test program.
01274   2000-07-03 lpd Patched to eliminate warnings about "constant is
01275       unsigned in ANSI C, signed in traditional"; made test program
01276       self-checking.
01277   1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
01278   1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
01279   1999-05-03 lpd Original version.
01280  */
01281 
01282 //#include "md5.h"
01283 //#include <string.h>
01284 
01285 #undef BYTE_ORDER     /* 1 = big-endian, -1 = little-endian, 0 = unknown */
01286 #ifdef ARCH_IS_BIG_ENDIAN
01287 #  define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
01288 #else
01289 #  define BYTE_ORDER 0
01290 #endif
01291 
01292 
01293 #define T_MASK ((uint16_t)~0)
01294 #define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
01295 #define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
01296 #define T3    0x242070db
01297 #define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
01298 #define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
01299 #define T6    0x4787c62a
01300 #define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
01301 #define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
01302 #define T9    0x698098d8
01303 #define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
01304 #define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
01305 #define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
01306 #define T13    0x6b901122
01307 #define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
01308 #define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
01309 #define T16    0x49b40821
01310 #define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
01311 #define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
01312 #define T19    0x265e5a51
01313 #define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
01314 #define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
01315 #define T22    0x02441453
01316 #define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
01317 #define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
01318 #define T25    0x21e1cde6
01319 #define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
01320 #define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
01321 #define T28    0x455a14ed
01322 #define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
01323 #define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
01324 #define T31    0x676f02d9
01325 #define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
01326 #define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
01327 #define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
01328 #define T35    0x6d9d6122
01329 #define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
01330 #define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
01331 #define T38    0x4bdecfa9
01332 #define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
01333 #define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
01334 #define T41    0x289b7ec6
01335 #define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
01336 #define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
01337 #define T44    0x04881d05
01338 #define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
01339 #define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
01340 #define T47    0x1fa27cf8
01341 #define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
01342 #define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
01343 #define T50    0x432aff97
01344 #define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
01345 #define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
01346 #define T53    0x655b59c3
01347 #define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
01348 #define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
01349 #define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
01350 #define T57    0x6fa87e4f
01351 #define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
01352 #define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
01353 #define T60    0x4e0811a1
01354 #define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
01355 #define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
01356 #define T63    0x2ad7d2bb
01357 #define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
01358 
01359 
01360 void
01361 Util::md5_process(md5_state_t *pms, const uint8_t *data /*[64]*/)
01362 {
01363     uint16_t
01364     a = pms->abcd[0], b = pms->abcd[1],
01365     c = pms->abcd[2], d = pms->abcd[3];
01366     uint16_t t;
01367 
01368 #if BYTE_ORDER > 0
01369     /* Define storage only for big-endian CPUs. */
01370     uint16_t X[16];
01371 #else
01372     /* Define storage for little-endian or both types of CPUs. */
01373     uint16_t xbuf[16];
01374     const uint16_t *X;
01375 #endif
01376     {
01377 #if BYTE_ORDER == 0
01378 /*
01379  * Determine dynamically whether this is a big-endian or
01380  * little-endian machine, since we can use a more efficient
01381  * algorithm on the latter.
01382  */
01383 static const int w = 1;
01384 
01385 if (*((const uint8_t *)&w)) /* dynamic little-endian */
01386 #endif
01387 #if BYTE_ORDER <= 0  /* little-endian */
01388 {
01389     /*
01390      * On little-endian machines, we can process properly aligned
01391      * data without copying it.
01392      */
01393     if (!((data - (const uint8_t *)0) & 3)) {
01394     /* data are properly aligned */
01395        X = (const uint16_t *)data;
01396     } else {
01397      /* not aligned */
01398      memcpy(xbuf, data, 64);
01399      X = xbuf;
01400     }
01401 }
01402 #endif
01403 #if BYTE_ORDER == 0
01404 else  /* dynamic big-endian */
01405 #endif
01406 #if BYTE_ORDER >= 0 /* big-endian */
01407 {
01408     /*
01409      * On big-endian machines, we must arrange the bytes in the
01410      * right order.
01411      */
01412     const uint8_t *xp = data;
01413     int i;
01414 
01415 #  if BYTE_ORDER == 0
01416      X = xbuf; /* (dynamic only) */
01417 #  else
01418 #    define xbuf /* (static only)  */
01419 #  endif
01420       for (i = 0; i < 16; ++i, xp += 4)
01421          xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
01422       }
01423 #endif
01424     }
01425 
01426 #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
01427 
01428     /* Round 1. */
01429     /* Let [abcd k s i] denote the operation
01430        a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
01431 
01432 #define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
01433 #define SET(a, b, c, d, k, s, Ti) \
01434      t = a + F(b,c,d) + X[k] + Ti;\
01435      a = ROTATE_LEFT(t, s) + b
01436     /* Do the following 16 operations. */
01437     SET(a, b, c, d,  0,  7,  T1);
01438     SET(d, a, b, c,  1, 12,  T2);
01439     SET(c, d, a, b,  2, 17,  T3);
01440     SET(b, c, d, a,  3, 22,  T4);
01441     SET(a, b, c, d,  4,  7,  T5);
01442     SET(d, a, b, c,  5, 12,  T6);
01443     SET(c, d, a, b,  6, 17,  T7);
01444     SET(b, c, d, a,  7, 22,  T8);
01445     SET(a, b, c, d,  8,  7,  T9);
01446     SET(d, a, b, c,  9, 12, T10);
01447     SET(c, d, a, b, 10, 17, T11);
01448     SET(b, c, d, a, 11, 22, T12);
01449     SET(a, b, c, d, 12,  7, T13);
01450     SET(d, a, b, c, 13, 12, T14);
01451     SET(c, d, a, b, 14, 17, T15);
01452     SET(b, c, d, a, 15, 22, T16);
01453 #undef SET
01454      /* Round 2. */
01455      /* Let [abcd k s i] denote the operation
01456           a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
01457 
01458 #define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
01459 #define SET(a, b, c, d, k, s, Ti)\
01460   t = a + G(b,c,d) + X[k] + Ti;  \
01461   a = ROTATE_LEFT(t, s) + b
01462      /* Do the following 16 operations. */
01463     SET(a, b, c, d,  1,  5, T17);
01464     SET(d, a, b, c,  6,  9, T18);
01465     SET(c, d, a, b, 11, 14, T19);
01466     SET(b, c, d, a,  0, 20, T20);
01467     SET(a, b, c, d,  5,  5, T21);
01468     SET(d, a, b, c, 10,  9, T22);
01469     SET(c, d, a, b, 15, 14, T23);
01470     SET(b, c, d, a,  4, 20, T24);
01471     SET(a, b, c, d,  9,  5, T25);
01472     SET(d, a, b, c, 14,  9, T26);
01473     SET(c, d, a, b,  3, 14, T27);
01474     SET(b, c, d, a,  8, 20, T28);
01475     SET(a, b, c, d, 13,  5, T29);
01476     SET(d, a, b, c,  2,  9, T30);
01477     SET(c, d, a, b,  7, 14, T31);
01478     SET(b, c, d, a, 12, 20, T32);
01479 #undef SET
01480      /* Round 3. */
01481      /* Let [abcd k s t] denote the operation
01482           a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
01483 #define H(x, y, z) ((x) ^ (y) ^ (z))
01484 #define SET(a, b, c, d, k, s, Ti)\
01485   t = a + H(b,c,d) + X[k] + Ti;  \
01486   a = ROTATE_LEFT(t, s) + b
01487   
01488      /* Do the following 16 operations. */
01489     SET(a, b, c, d,  5,  4, T33);
01490     SET(d, a, b, c,  8, 11, T34);
01491     SET(c, d, a, b, 11, 16, T35);
01492     SET(b, c, d, a, 14, 23, T36);
01493     SET(a, b, c, d,  1,  4, T37);
01494     SET(d, a, b, c,  4, 11, T38);
01495     SET(c, d, a, b,  7, 16, T39);
01496     SET(b, c, d, a, 10, 23, T40);
01497     SET(a, b, c, d, 13,  4, T41);
01498     SET(d, a, b, c,  0, 11, T42);
01499     SET(c, d, a, b,  3, 16, T43);
01500     SET(b, c, d, a,  6, 23, T44);
01501     SET(a, b, c, d,  9,  4, T45);
01502     SET(d, a, b, c, 12, 11, T46);
01503     SET(c, d, a, b, 15, 16, T47);
01504     SET(b, c, d, a,  2, 23, T48);
01505 #undef SET
01506      /* Round 4. */
01507      /* Let [abcd k s t] denote the operation
01508           a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
01509 #define I(x, y, z) ((y) ^ ((x) | ~(z)))
01510 #define SET(a, b, c, d, k, s, Ti)\
01511   t = a + I(b,c,d) + X[k] + Ti;  \
01512   a = ROTATE_LEFT(t, s) + b
01513   
01514      /* Do the following 16 operations. */
01515     SET(a, b, c, d,  0,  6, T49);
01516     SET(d, a, b, c,  7, 10, T50);
01517     SET(c, d, a, b, 14, 15, T51);
01518     SET(b, c, d, a,  5, 21, T52);
01519     SET(a, b, c, d, 12,  6, T53);
01520     SET(d, a, b, c,  3, 10, T54);
01521     SET(c, d, a, b, 10, 15, T55);
01522     SET(b, c, d, a,  1, 21, T56);
01523     SET(a, b, c, d,  8,  6, T57);
01524     SET(d, a, b, c, 15, 10, T58);
01525     SET(c, d, a, b,  6, 15, T59);
01526     SET(b, c, d, a, 13, 21, T60);
01527     SET(a, b, c, d,  4,  6, T61);
01528     SET(d, a, b, c, 11, 10, T62);
01529     SET(c, d, a, b,  2, 15, T63);
01530     SET(b, c, d, a,  9, 21, T64);
01531 
01532 #undef SET
01533      /* Then perform the following additions. (That is increment each
01534         of the four registers by the value it had before this block
01535         was started.) */
01536     pms->abcd[0] += a;
01537     pms->abcd[1] += b;
01538     pms->abcd[2] += c;
01539     pms->abcd[3] += d;
01540 }
01541 void
01542 Util::md5_init(md5_state_t *pms)
01543 {
01544     pms->count[0] = pms->count[1] = 0;
01545     pms->abcd[0] = 0x67452301;
01546     pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
01547     pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
01548     pms->abcd[3] = 0x10325476;
01549 }
01550 
01551 
01552 void
01553 Util::md5_append(md5_state_t *pms, const uint8_t *data, int nbytes)
01554 {
01555     const uint8_t *p = data;
01556     int left = nbytes;
01557     int offset = (pms->count[0] >> 3) & 63;
01558     uint16_t nbits = (uint16_t)(nbytes << 3);
01559     if (nbytes <= 0)
01560        return;
01561     /* Update the message length. */
01562     pms->count[1] += nbytes >> 29;
01563     pms->count[0] += nbits;
01564     if (pms->count[0] < nbits)
01565        pms->count[1]++;
01566     /* Process an initial partial block. */
01567     if (offset) {
01568        int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
01569        memcpy(pms->buf + offset, p, copy);
01570        if (offset + copy < 64)
01571           return;
01572        p += copy;
01573        left -= copy;
01574        md5_process(pms, pms->buf);
01575     }
01576     /* Process full blocks. */
01577     for (; left >= 64; p += 64, left -= 64)
01578       md5_process(pms, p);
01579     /* Process a final partial block. */
01580     if (left)
01581       memcpy(pms->buf, p, left);
01582 }
01583 void
01584 Util::md5_finish(md5_state_t *pms, uint8_t digest[16])
01585 {
01586     static const uint8_t pad[64] = {
01587        0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
01588        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
01589        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
01590        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
01591     };
01592 
01593     uint8_t data[8];
01594     int i;
01595     /* Save the length before padding. */
01596     for (i = 0; i < 8; ++i)
01597        data[i] = (uint8_t)(pms->count[i >> 2] >> ((i & 3) << 3));
01598     /* Pad to 56 bytes mod 64. */
01599     md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
01600     /* Append the length. */
01601     md5_append(pms, data, 8);
01602     for (i = 0; i < 16; ++i)
01603       digest[i] = (uint8_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
01604 }
01605 
01606 //-------------------------------------------------------------------------
01607 } // end namespace gdcm
01608 

Generated on Fri Aug 24 12:59:32 2007 for gdcm by  doxygen 1.4.6