1 /*=========================================================================
4 Module: $RCSfile: gdcmUtil.cxx,v $
6 Date: $Date: 2007/10/17 08:57:55 $
7 Version: $Revision: 1.189 $
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.
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.
17 =========================================================================*/
20 #include "gdcmDebug.h"
23 #include <stdarg.h> // for va_list
25 // For GetCurrentDate, GetCurrentTime
27 #include <sys/types.h>
30 #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__)
31 #include <sys/timeb.h>
36 #include <stdarg.h> //only included in implementation file
37 #include <stdio.h> //only included in implementation file
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)
48 #include <unistd.h> // for gethostname
49 #include <netdb.h> // for gethostbyname
60 #include <sys/types.h>
63 #ifdef CMAKE_HAVE_SYS_IOCTL_H
64 #include <sys/ioctl.h> // For SIOCGIFCONF on Linux
66 #ifdef CMAKE_HAVE_SYS_SOCKET_H
67 #include <sys/socket.h>
69 #ifdef CMAKE_HAVE_SYS_SOCKIO_H
70 #include <sys/sockio.h> // For SIOCGIFCONF on SunOS
72 #ifdef CMAKE_HAVE_NET_IF_H
75 #ifdef CMAKE_HAVE_NETINET_IN_H
76 #include <netinet/in.h> //For IPPROTO_IP
78 #ifdef CMAKE_HAVE_NET_IF_DL_H
79 #include <net/if_dl.h>
81 #if defined(CMAKE_HAVE_NET_IF_ARP_H) && defined(__sun)
82 // This is absolutely necessary on SunOS
83 #include <net/if_arp.h>
86 // For GetCurrentThreadID()
88 #include <sys/types.h>
89 #include <linux/unistd.h>
95 namespace GDCM_NAME_SPACE
97 //-------------------------------------------------------------------------
98 const std::string Util::GDCM_UID = "1.2.826.0.1.3680043.2.1143";
99 std::string Util::RootUID = GDCM_UID;
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...
107 #if defined(GDCM_WORDS_BIGENDIAN) || defined(GDCM_FORCE_BIGENDIAN_EMULATION)
108 const uint16_t Util::FMIV = 0x0001;
110 const uint16_t Util::FMIV = 0x0100;
112 uint8_t *Util::FileMetaInformationVersion = (uint8_t *)&FMIV;
114 std::string Util::GDCM_MAC_ADRESS = GetMACAddress();
116 //-------------------------------------------------------------------------
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);
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;
133 * result = gdcm::Util::Format("%04x|%04x", group , elem);
135 std::string Util::Format(const char *format, ...)
137 char buffer[2048]; // hope 2048 is enough
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'
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
155 void Util::Tokenize (const std::string &str,
156 std::vector<std::string> &tokens,
157 const std::string &delimiters)
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)
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);
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
176 int Util::CountSubstring (const std::string &str,
177 const std::string &subStr)
179 int count = 0; // counts how many times it appears
180 std::string::size_type x = 0; // The index position in the string
184 x = str.find(subStr,x); // Find the substring
185 if (x != std::string::npos) // If present
187 count++; // increase the count
188 x += subStr.length(); // Skip this word
191 while (x != std::string::npos);// Carry on until not present
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
201 bool Util::IsCleanString(std::string const &s)
203 for(unsigned int i=0; i<s.size(); i++)
205 if (!isprint((unsigned char)s[i]) )
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
219 bool Util::IsCleanArea(uint8_t *s, int l)
221 for( int i=0; i<l; i++)
223 if (!isprint((unsigned char)s[i]) )
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)
235 std::string Util::CreateCleanString(std::string const &s)
239 for(unsigned int i=0; i<str.size(); i++)
241 if (!isprint((unsigned char)str[i]) )
248 if (!isprint((unsigned char)s[str.size()-1]) )
250 if (s[str.size()-1] == 0 )
252 str[str.size()-1] = ' ';
259 * \brief Replaces all special characters
260 * @param s string to modify
261 * @param rep replacement char
263 void Util::ReplaceSpecChar(std::string &s, std::string &rep)
265 unsigned int s_size = s.size();
266 for(unsigned int i=0; i<s_size; i++)
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')))
274 s.replace(i, 1, rep);
277 // deal with Dicom strings trailing '\0'
278 if(s[s_size-1] == rep.c_str()[0])
279 s.erase(s_size-1, 1);
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
289 std::string Util::CreateCleanString(uint8_t *s, int l)
293 for( int i=0; i<l; i++)
295 if (!isprint((unsigned char)s[i]) )
301 str = str + (char )s[i];
308 * \brief Add a SEPARATOR to the end of the name if necessary
309 * @param pathname file/directory name to normalize
311 std::string Util::NormalizePath(std::string const &pathname)
314 const char SEPARATOR_X = '/';
315 const char SEPARATOR_WIN = '\\';
317 const std::string SEPARATOR = "\\";
319 const std::string SEPARATOR = "/";
322 std::string name = pathname;
323 int size = name.size();
325 // if ( name[size-1] != SEPARATOR_X && name[size-1] != SEPARATOR_WIN )
326 if ( name[size-1] != GDCM_FILESEPARATOR )
328 name += GDCM_FILESEPARATOR;
334 * \brief Get the (directory) path from a full path file name
335 * @param fullName file/directory name to extract Path from
337 std::string Util::GetPath(std::string const &fullName)
339 std::string res = fullName;
342 int pos1 = res.rfind("/");
343 int pos2 = res.rfind("\\");
353 int pos = res.rfind(GDCM_FILESEPARATOR);
359 * \brief Get the (last) name of a full path file name
360 * @param fullName file/directory name to extract end name from
362 std::string Util::GetName(std::string const &fullName)
364 std::string filename = fullName;
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;
372 std::string::size_type slash_pos = filename.rfind(GDCM_FILESEPARATOR);
373 if (slash_pos != std::string::npos )
375 return filename.substr(slash_pos + 1);
384 * \brief Get the current date of the system in a dicom string
386 std::string Util::GetCurrentDate()
391 strftime(tmp,512,"%Y%m%d", localtime(&tloc) );
396 * \brief Get the current time of the system in a dicom string
398 std::string Util::GetCurrentTime()
403 strftime(tmp,512,"%H%M%S", localtime(&tloc) );
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
411 std::string Util::GetCurrentDateTime()
417 // We need implementation specific functions to obtain millisecond precision
418 #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__)
422 milliseconds = tb.millitm;
425 gettimeofday (&tv, NULL);
427 // Compute milliseconds from microseconds.
428 milliseconds = tv.tv_usec / 1000;
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);
436 // Don't use Util::Format to accelerate execution of code
438 sprintf(tmpAll,"%s%03ld",tmp,milliseconds);
443 unsigned int Util::GetCurrentThreadID()
445 // FIXME the implementation is far from complete
446 #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__)
447 return (unsigned int)GetCurrentThreadId();
451 // Doesn't work on fedora, but is in the man page...
452 //return (unsigned int)gettid();
455 return (unsigned int)thr_self();
457 //default implementation
464 unsigned int Util::GetCurrentProcessID()
466 #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__)
467 // NOTE: There is also a _getpid()...
468 return (unsigned int)GetCurrentProcessId();
470 // get process identification, POSIX
471 return (unsigned int)getpid();
476 * \brief tells us whether the processor we are working with is BigEndian or not
478 bool Util::IsCurrentProcessorBigEndian()
480 #if defined(GDCM_WORDS_BIGENDIAN)
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
495 std::string Util::DicomString(const char *s, size_t l)
497 std::string r(s, s+l);
498 gdcmAssertMacro( !(r.size() % 2) ); // == basically 'l' is even
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
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
513 std::string Util::DicomString(const char *s)
515 size_t l = strlen(s);
520 std::string r(s, s+l);
521 gdcmAssertMacro( !(r.size() % 2) );
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
531 bool Util::DicomStringEqual(const std::string &s1, const char *s2)
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] == ' ' )
538 s1_even[s1_even.size()-1] = '\0'; //replace space character by null
540 return s1_even == s2_even;
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
549 bool Util::CompareDicomString(const std::string &s1, const char *s2, int op)
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] == ' ' )
556 s1_even[s1_even.size()-1] = '\0'; //replace space character by null
561 return s1_even == s2_even;
562 case GDCM_DIFFERENT :
563 return s1_even != s2_even;
565 return s1_even > s2_even;
566 case GDCM_GREATEROREQUAL :
567 return s1_even >= s2_even;
569 return s1_even < s2_even;
570 case GDCM_LESSOREQUAL :
571 return s1_even <= s2_even;
573 gdcmDebugMacro(" Wrong operator : " << op);
579 typedef BOOL(WINAPI * pSnmpExtensionInit) (
580 IN DWORD dwTimeZeroReference,
581 OUT HANDLE * hPollForTrapEvent,
582 OUT AsnObjectIdentifier * supportedView);
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);
591 typedef BOOL(WINAPI * pSnmpExtensionQuery) (
593 IN OUT RFC1157VarBindList * variableBindings,
594 OUT AsnInteger * errorStatus,
595 OUT AsnInteger * errorIndex);
597 typedef BOOL(WINAPI * pSnmpExtensionInitEx) (
598 OUT AsnObjectIdentifier * supportedView);
602 static int SGIGetMacAddress(unsigned char *addr)
604 FILE *f = popen("/etc/nvram eaddr","r");
610 if(fscanf(f,"%02x:%02x:%02x:%02x:%02x:%02x",
611 x,x+1,x+2,x+3,x+4,x+5) != 6)
616 for(unsigned int i = 0; i < 6; i++)
618 addr[i] = static_cast<unsigned char>(x[i]);
624 /// \brief gets current M.A.C adress (for internal use only)
625 int GetMacAddrSys ( unsigned char *addr );
626 int GetMacAddrSys ( unsigned char *addr )
630 if ( (WSAStartup(MAKEWORD(2, 0), &WinsockData)) != 0 )
632 std::cerr << "in Get MAC Adress (internal) : This program requires Winsock 2.x!"
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 };
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)
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);
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;
674 // Copy in the OID to find the number of entries in the
676 varBindList.len = 1; // Only retrieving one item
677 SNMP_oidcpy(&varBind[0].name, &MIB_ifEntryNum);
678 m_Query(ASN_RFC1157_GETNEXTREQUEST, &varBindList, &errorStatus,
680 // printf("# of adapters in this system : %i\n",
681 // varBind[0].value.asnValue.number);
684 // Copy in the OID of ifType, the type of interface
685 SNMP_oidcpy(&varBind[0].name, &MIB_ifEntryType);
687 // Copy in the OID of ifPhysAddress, the address
688 SNMP_oidcpy(&varBind[1].name, &MIB_ifMACEntAddr);
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,
703 // Confirm that the proper type has been returned
704 ret = SNMP_oidncmp(&varBind[0].name, &MIB_ifEntryType,
705 MIB_ifEntryType.idLength);
710 dtmp = varBind[0].value.asnValue.number;
712 // Type 6 describes ethernet interfaces
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 )
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) )
726 // Ignore all dial-up networking adapters
727 std::cerr << "in Get MAC Adress (internal) : Interface #"
728 << j << " is a DUN adapter\n";
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) )
738 // Ignore NULL addresses returned by other network
740 std::cerr << "in Get MAC Adress (internal) : Interface #"
741 << j << " is a NULL address\n";
744 memcpy( addr, varBind[1].value.asnValue.address.stream, 6);
751 SNMP_FreeVarBind(&varBind[0]);
752 SNMP_FreeVarBind(&varBind[1]);
754 #endif //Win32 version
757 return SGIGetMacAddress(addr);
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
765 struct arpreq parpreq;
766 struct sockaddr_in *psa;
767 struct hostent *phost;
768 char hostname[MAXHOSTNAMELEN];
772 if (gethostname(hostname, MAXHOSTNAMELEN) != 0 )
774 perror("in Get MAC Adress (internal) : gethostname");
777 phost = gethostbyname(hostname);
778 paddrs = phost->h_addr_list;
780 sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
783 perror("in Get MAC Adress (internal) : sock");
786 memset(&parpreq, 0, sizeof(struct arpreq));
787 psa = (struct sockaddr_in *) &parpreq.arp_pa;
789 memset(psa, 0, sizeof(struct sockaddr_in));
790 psa->sin_family = AF_INET;
791 memcpy(&psa->sin_addr, *paddrs, sizeof(struct in_addr));
793 status = ioctl(sock, SIOCGARP, &parpreq);
796 perror("in Get MAC Adress (internal) : SIOCGARP");
799 memcpy(addr, parpreq.arp_ha.sa_data, 6);
803 #ifdef CMAKE_HAVE_NET_IF_H
805 struct ifreq ifr, *ifrp;
810 #if defined(AF_LINK) && (!defined(SIOCGIFHWADDR) && !defined(SIOCGENADDR))
811 struct sockaddr_dl *sdlp;
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
823 #define max(a,b) ((a) > (b) ? (a) : (b))
825 #define ifreq_size(i) max(sizeof(struct ifreq),\
826 sizeof((i).ifr_name)+(i).ifr_addr.sa_len)
828 #define ifreq_size(i) sizeof(struct ifreq)
829 #endif // HAVE_SA_LEN
831 if ( (sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0 )
835 memset(buf, 0, sizeof(buf));
836 ifc.ifc_len = sizeof(buf);
838 if (ioctl (sd, SIOCGIFCONF, (char *)&ifc) < 0)
844 for (i = 0; i < n; i+= ifreq_size(*ifrp) )
846 ifrp = (struct ifreq *)((char *) ifc.ifc_buf+i);
847 strncpy(ifr.ifr_name, ifrp->ifr_name, IFNAMSIZ);
849 if (ioctl(sd, SIOCGIFHWADDR, &ifr) < 0)
851 a = (unsigned char *) &ifr.ifr_hwaddr.sa_data;
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)
861 a = (unsigned char *) ifr.ifr_enaddr;
864 sdlp = (struct sockaddr_dl *) &ifrp->ifr_addr;
865 if ((sdlp->sdl_family != AF_LINK) || (sdlp->sdl_alen != 6))
867 a = (unsigned char *) &sdlp->sdl_data[sdlp->sdl_nlen];
869 perror("in Get MAC Adress (internal) : No way to access hardware");
873 #endif // SIOCGENADDR
874 #endif // SIOCGIFHWADDR
875 if (!a[0] && !a[1] && !a[2] && !a[3] && !a[4] && !a[5]) continue;
886 // Not implemented platforms (or no Ethernet cable !)
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)");
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)");
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
904 inline int getlastdigit(unsigned char *data)
906 int extended, carry = 0;
909 extended = (carry << 8) + data[i];
910 data[i] = extended / 10;
911 carry = extended % 10;
917 * \brief Encode the mac address on a fixed length string of 15 characters.
918 * we save space this way.
920 std::string Util::GetMACAddress()
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];
929 int stat = GetMacAddrSys(addr);
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
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);
950 gdcmStaticWarningMacro("Problem in finding the MAC Address");
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
961 std::string Util::CreateUniqueUID(const std::string &root)
967 // gdcm UID prefix, as supplied by http://www.medicalconnections.co.uk
975 // A root was specified use it to forge our new UID:
977 //append += Util::GetMACAddress(); // to save CPU time
978 append += Util::GDCM_MAC_ADRESS;
980 append += Util::GetCurrentDateTime();
982 //Also add a mini random number just in case:
984 int r = (int) (100.0*rand()/RAND_MAX);
985 // Don't use Util::Format to accelerate the execution
986 sprintf(tmp,"%02d", r);
989 // If append is too long we need to rehash it
990 if ( (prefix + append).size() > 64 )
992 gdcmStaticErrorMacro( "Size of UID is too long." );
993 // we need a hash function to truncate this number
994 // if only md5 was cross plateform
998 return prefix + append;
1001 void Util::SetRootUID(const std::string &root)
1009 const std::string &Util::GetRootUID()
1014 //-------------------------------------------------------------------------
1016 * \brief binary_write binary_write
1017 * @param os ostream to write to
1018 * @param val 16 bits value to write
1020 std::ostream &binary_write(std::ostream &os, const uint16_t &val)
1022 #if defined(GDCM_WORDS_BIGENDIAN) || defined(GDCM_FORCE_BIGENDIAN_EMULATION)
1024 swap = ( val << 8 | val >> 8 );
1026 return os.write(reinterpret_cast<const char*>(&swap), 2);
1028 return os.write(reinterpret_cast<const char*>(&val), 2);
1029 #endif //GDCM_WORDS_BIGENDIAN
1033 * \brief binary_write binary_write
1034 * @param os ostream to write to
1035 * @param val 32 bits value to write
1037 std::ostream &binary_write(std::ostream &os, const uint32_t &val)
1039 #if defined(GDCM_WORDS_BIGENDIAN) || defined(GDCM_FORCE_BIGENDIAN_EMULATION)
1041 swap = ( (val<<24) | ((val<<8) & 0x00ff0000) |
1042 ((val>>8) & 0x0000ff00) | (val>>24) );
1043 return os.write(reinterpret_cast<const char*>(&swap), 4);
1045 return os.write(reinterpret_cast<const char*>(&val), 4);
1046 #endif //GDCM_WORDS_BIGENDIAN
1050 * \brief binary_write binary_write
1051 * @param os ostream to write to
1052 * @param val double (64 bits) value to write
1054 std::ostream &binary_write(std::ostream &os, const double &val)
1056 #if defined(GDCM_WORDS_BIGENDIAN) || defined(GDCM_FORCE_BIGENDIAN_EMULATION)
1059 char *beg = (char *)&swap;
1060 char *end = beg + 7;
1062 for (unsigned int i = 0; i<7; i++)
1070 return os.write(reinterpret_cast<const char*>(&swap), 8);
1072 return os.write(reinterpret_cast<const char*>(&val), 8);
1073 #endif //GDCM_WORDS_BIGENDIAN
1077 * \brief binary_write binary_write
1078 * @param os ostream to write to
1079 * @param val 8 bits characters aray to write
1081 std::ostream &binary_write(std::ostream &os, const char *val)
1083 return os.write(val, strlen(val));
1087 * \brief binary_write binary_write
1088 * @param os ostream to write to
1089 * @param val std::string value to write
1091 std::ostream &binary_write(std::ostream &os, std::string const &val)
1093 return os.write(val.c_str(), val.size());
1097 * \brief binary_write binary_write
1098 * @param os ostream to write to
1099 * @param val 8 bits 'characters' aray to write
1100 * @param len length of the 'value' to be written
1102 std::ostream &binary_write(std::ostream &os, const uint8_t *val, size_t len)
1104 // We are writting sizeof(char) thus no need to swap bytes
1105 return os.write(reinterpret_cast<const char*>(val), len);
1109 * \brief binary_write binary_write
1110 * @param os ostream to write to
1111 * @param val 16 bits words aray to write
1112 * @param len length (in bytes) of the 'value' to be written
1114 std::ostream &binary_write(std::ostream &os, const uint16_t *val, size_t len)
1116 // This is tricky since we are writting two bytes buffer.
1117 // Be carefull with little endian vs big endian.
1118 // Also this other trick is to allocate a small (efficient) buffer that store
1119 // intermediate result before writting it.
1120 #if defined(GDCM_WORDS_BIGENDIAN) || defined(GDCM_FORCE_BIGENDIAN_EMULATION)
1121 const int BUFFER_SIZE = 4096;
1122 static char buffer[BUFFER_SIZE];
1123 uint16_t *binArea16 = (uint16_t*)val; //for the const
1125 // how many BUFFER_SIZE long pieces in binArea ?
1126 int nbPieces = len/BUFFER_SIZE; //(16 bits = 2 Bytes)
1127 int remainingSize = len%BUFFER_SIZE;
1129 for (int j=0;j<nbPieces;j++)
1131 uint16_t *pbuffer = (uint16_t*)buffer; //reinitialize pbuffer
1132 for (int i = 0; i < BUFFER_SIZE/2; i++)
1134 *pbuffer = *binArea16 >> 8 | *binArea16 << 8;
1138 os.write ( buffer, BUFFER_SIZE );
1140 if ( remainingSize > 0)
1142 uint16_t *pbuffer = (uint16_t*)buffer; //reinitialize pbuffer
1143 for (int i = 0; i < remainingSize/2; i++)
1145 *pbuffer = *binArea16 >> 8 | *binArea16 << 8;
1149 os.write ( buffer, remainingSize );
1153 return os.write(reinterpret_cast<const char*>(val), len);
1157 std::string Util::ConvertToMD5 (std::string &inPszToCrypt)
1159 char *szChar = new char[ inPszToCrypt.size()+1 ];
1160 char *szHexOutput = new char[ 16 * 2 + 1 ];
1162 strcpy( szChar, inPszToCrypt.c_str() );
1163 // création du code md5
1164 nLen = strlen( szChar );
1166 uint8_t digest[ 16 ];
1167 md5_init ( &state );
1168 md5_append ( &state, (const uint8_t *)szChar, nLen);
1169 md5_finish ( &state, digest );
1170 for ( nDi = 0; nDi < 16; nDi++)
1171 sprintf( szHexOutput + nDi * 2, "%02x", digest[ nDi ] );
1172 szHexOutput[16 * 2]=0;
1174 std::string md5String=szHexOutput;
1175 delete [] szHexOutput;
1179 //-------------------------------------------------------------------------
1182 //-------------------------------------------------------------------------
1185 * \brief Return the IP adress of the machine writting the DICOM image
1187 std::string Util::GetIPAddress()
1189 // This is a rip from
1190 // http://www.codeguru.com/Cpp/I-N/internet/network/article.php/c3445/
1191 #ifndef HOST_NAME_MAX
1192 // SUSv2 guarantees that `Host names are limited to 255 bytes'.
1193 // POSIX 1003.1-2001 guarantees that `Host names (not including the
1194 // terminating NUL) are limited to HOST_NAME_MAX bytes'.
1195 #define HOST_NAME_MAX 255
1196 // In this case we should maybe check the string was not truncated.
1197 // But I don't known how to check that...
1198 #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__)
1199 // with WinSock DLL we need to initialize the WinSock before using gethostname
1200 WORD wVersionRequested = MAKEWORD(1,0);
1202 int err = WSAStartup(wVersionRequested,&WSAData);
1205 // Tell the user that we could not find a usable
1212 #endif //HOST_NAME_MAX
1215 char szHostName[HOST_NAME_MAX+1];
1216 int r = gethostname(szHostName, HOST_NAME_MAX);
1220 // Get host adresses
1221 struct hostent *pHost = gethostbyname(szHostName);
1223 for( int i = 0; pHost!= NULL && pHost->h_addr_list[i]!= NULL; i++ )
1225 for( int j = 0; j<pHost->h_length; j++ )
1227 if ( j > 0 ) str += ".";
1229 str += Util::Format("%u",
1230 (unsigned int)((unsigned char*)pHost->h_addr_list[i])[j]);
1232 // str now contains one local IP address
1234 #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__)
1240 // If an error occur r == -1
1241 // Most of the time it will return 127.0.0.1...
1245 void Util::hfpswap(double *a, double *b)
1255 Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved.
1257 This software is provided 'as-is', without any express or implied
1258 warranty. In no event will the authors be held liable for any damages
1259 arising from the use of this software.
1261 Permission is granted to anyone to use this software for any purpose,
1262 including commercial applications, and to alter it and redistribute it
1263 freely, subject to the following restrictions:
1265 1. The origin of this software must not be misrepresented; you must not
1266 claim that you wrote the original software. If you use this software
1267 in a product, an acknowledgment in the product documentation would be
1268 appreciated but is not required.
1269 2. Altered source versions must be plainly marked as such, and must not be
1270 misrepresented as being the original software.
1271 3. This notice may not be removed or altered from any source distribution.
1278 /* $Id: gdcmUtil.cxx,v 1.189 2007/10/17 08:57:55 jpr Exp $ */
1281 Independent implementation of MD5 (RFC 1321).
1282 This code implements the MD5 Algorithm defined in RFC 1321, whose
1283 text is available at
1285 http://www.ietf.org/rfc/rfc1321.txt
1287 The code is derived from the text of the RFC, including the test suite
1288 (section A.5) but excluding the rest of Appendix A. It does not include
1289 any code or documentation that is identified in the RFC as being
1292 The original and principal author of md5.c is L. Peter Deutsch
1293 <ghost@aladdin.com>. Other authors are noted in the change history
1294 that follows (in reverse chronological order):
1296 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
1297 either statically or dynamically; added missing #include <string.h>
1299 2002-03-11 lpd Corrected argument list for main(), and added int return
1300 type, in test program and T value program.
1301 2002-02-21 lpd Added missing #include <stdio.h> in test program.
1302 2000-07-03 lpd Patched to eliminate warnings about "constant is
1303 unsigned in ANSI C, signed in traditional"; made test program
1305 1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
1306 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
1307 1999-05-03 lpd Original version.
1311 //#include <string.h>
1313 #undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */
1314 #ifdef ARCH_IS_BIG_ENDIAN
1315 # define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
1317 # define BYTE_ORDER 0
1321 #define T_MASK ((uint16_t)~0)
1322 #define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
1323 #define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
1324 #define T3 0x242070db
1325 #define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
1326 #define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
1327 #define T6 0x4787c62a
1328 #define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
1329 #define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
1330 #define T9 0x698098d8
1331 #define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
1332 #define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
1333 #define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
1334 #define T13 0x6b901122
1335 #define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
1336 #define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
1337 #define T16 0x49b40821
1338 #define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
1339 #define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
1340 #define T19 0x265e5a51
1341 #define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
1342 #define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
1343 #define T22 0x02441453
1344 #define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
1345 #define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
1346 #define T25 0x21e1cde6
1347 #define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
1348 #define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
1349 #define T28 0x455a14ed
1350 #define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
1351 #define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
1352 #define T31 0x676f02d9
1353 #define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
1354 #define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
1355 #define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
1356 #define T35 0x6d9d6122
1357 #define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
1358 #define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
1359 #define T38 0x4bdecfa9
1360 #define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
1361 #define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
1362 #define T41 0x289b7ec6
1363 #define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
1364 #define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
1365 #define T44 0x04881d05
1366 #define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
1367 #define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
1368 #define T47 0x1fa27cf8
1369 #define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
1370 #define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
1371 #define T50 0x432aff97
1372 #define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
1373 #define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
1374 #define T53 0x655b59c3
1375 #define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
1376 #define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
1377 #define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
1378 #define T57 0x6fa87e4f
1379 #define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
1380 #define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
1381 #define T60 0x4e0811a1
1382 #define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
1383 #define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
1384 #define T63 0x2ad7d2bb
1385 #define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
1389 Util::md5_process(md5_state_t *pms, const uint8_t *data /*[64]*/)
1392 a = pms->abcd[0], b = pms->abcd[1],
1393 c = pms->abcd[2], d = pms->abcd[3];
1397 /* Define storage only for big-endian CPUs. */
1400 /* Define storage for little-endian or both types of CPUs. */
1407 * Determine dynamically whether this is a big-endian or
1408 * little-endian machine, since we can use a more efficient
1409 * algorithm on the latter.
1411 static const int w = 1;
1413 if (*((const uint8_t *)&w)) /* dynamic little-endian */
1415 #if BYTE_ORDER <= 0 /* little-endian */
1418 * On little-endian machines, we can process properly aligned
1419 * data without copying it.
1421 if (!((data - (const uint8_t *)0) & 3)) {
1422 /* data are properly aligned */
1423 X = (const uint16_t *)data;
1426 memcpy(xbuf, data, 64);
1432 else /* dynamic big-endian */
1434 #if BYTE_ORDER >= 0 /* big-endian */
1437 * On big-endian machines, we must arrange the bytes in the
1440 const uint8_t *xp = data;
1443 # if BYTE_ORDER == 0
1444 X = xbuf; /* (dynamic only) */
1446 # define xbuf /* (static only) */
1448 for (i = 0; i < 16; ++i, xp += 4)
1449 xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
1454 #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
1457 /* Let [abcd k s i] denote the operation
1458 a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
1460 #define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
1461 #define SET(a, b, c, d, k, s, Ti) \
1462 t = a + F(b,c,d) + X[k] + Ti;\
1463 a = ROTATE_LEFT(t, s) + b
1464 /* Do the following 16 operations. */
1465 SET(a, b, c, d, 0, 7, T1);
1466 SET(d, a, b, c, 1, 12, T2);
1467 SET(c, d, a, b, 2, 17, T3);
1468 SET(b, c, d, a, 3, 22, T4);
1469 SET(a, b, c, d, 4, 7, T5);
1470 SET(d, a, b, c, 5, 12, T6);
1471 SET(c, d, a, b, 6, 17, T7);
1472 SET(b, c, d, a, 7, 22, T8);
1473 SET(a, b, c, d, 8, 7, T9);
1474 SET(d, a, b, c, 9, 12, T10);
1475 SET(c, d, a, b, 10, 17, T11);
1476 SET(b, c, d, a, 11, 22, T12);
1477 SET(a, b, c, d, 12, 7, T13);
1478 SET(d, a, b, c, 13, 12, T14);
1479 SET(c, d, a, b, 14, 17, T15);
1480 SET(b, c, d, a, 15, 22, T16);
1483 /* Let [abcd k s i] denote the operation
1484 a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
1486 #define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
1487 #define SET(a, b, c, d, k, s, Ti)\
1488 t = a + G(b,c,d) + X[k] + Ti; \
1489 a = ROTATE_LEFT(t, s) + b
1490 /* Do the following 16 operations. */
1491 SET(a, b, c, d, 1, 5, T17);
1492 SET(d, a, b, c, 6, 9, T18);
1493 SET(c, d, a, b, 11, 14, T19);
1494 SET(b, c, d, a, 0, 20, T20);
1495 SET(a, b, c, d, 5, 5, T21);
1496 SET(d, a, b, c, 10, 9, T22);
1497 SET(c, d, a, b, 15, 14, T23);
1498 SET(b, c, d, a, 4, 20, T24);
1499 SET(a, b, c, d, 9, 5, T25);
1500 SET(d, a, b, c, 14, 9, T26);
1501 SET(c, d, a, b, 3, 14, T27);
1502 SET(b, c, d, a, 8, 20, T28);
1503 SET(a, b, c, d, 13, 5, T29);
1504 SET(d, a, b, c, 2, 9, T30);
1505 SET(c, d, a, b, 7, 14, T31);
1506 SET(b, c, d, a, 12, 20, T32);
1509 /* Let [abcd k s t] denote the operation
1510 a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
1511 #define H(x, y, z) ((x) ^ (y) ^ (z))
1512 #define SET(a, b, c, d, k, s, Ti)\
1513 t = a + H(b,c,d) + X[k] + Ti; \
1514 a = ROTATE_LEFT(t, s) + b
1516 /* Do the following 16 operations. */
1517 SET(a, b, c, d, 5, 4, T33);
1518 SET(d, a, b, c, 8, 11, T34);
1519 SET(c, d, a, b, 11, 16, T35);
1520 SET(b, c, d, a, 14, 23, T36);
1521 SET(a, b, c, d, 1, 4, T37);
1522 SET(d, a, b, c, 4, 11, T38);
1523 SET(c, d, a, b, 7, 16, T39);
1524 SET(b, c, d, a, 10, 23, T40);
1525 SET(a, b, c, d, 13, 4, T41);
1526 SET(d, a, b, c, 0, 11, T42);
1527 SET(c, d, a, b, 3, 16, T43);
1528 SET(b, c, d, a, 6, 23, T44);
1529 SET(a, b, c, d, 9, 4, T45);
1530 SET(d, a, b, c, 12, 11, T46);
1531 SET(c, d, a, b, 15, 16, T47);
1532 SET(b, c, d, a, 2, 23, T48);
1535 /* Let [abcd k s t] denote the operation
1536 a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
1537 #define I(x, y, z) ((y) ^ ((x) | ~(z)))
1538 #define SET(a, b, c, d, k, s, Ti)\
1539 t = a + I(b,c,d) + X[k] + Ti; \
1540 a = ROTATE_LEFT(t, s) + b
1542 /* Do the following 16 operations. */
1543 SET(a, b, c, d, 0, 6, T49);
1544 SET(d, a, b, c, 7, 10, T50);
1545 SET(c, d, a, b, 14, 15, T51);
1546 SET(b, c, d, a, 5, 21, T52);
1547 SET(a, b, c, d, 12, 6, T53);
1548 SET(d, a, b, c, 3, 10, T54);
1549 SET(c, d, a, b, 10, 15, T55);
1550 SET(b, c, d, a, 1, 21, T56);
1551 SET(a, b, c, d, 8, 6, T57);
1552 SET(d, a, b, c, 15, 10, T58);
1553 SET(c, d, a, b, 6, 15, T59);
1554 SET(b, c, d, a, 13, 21, T60);
1555 SET(a, b, c, d, 4, 6, T61);
1556 SET(d, a, b, c, 11, 10, T62);
1557 SET(c, d, a, b, 2, 15, T63);
1558 SET(b, c, d, a, 9, 21, T64);
1561 /* Then perform the following additions. (That is increment each
1562 of the four registers by the value it had before this block
1570 Util::md5_init(md5_state_t *pms)
1572 pms->count[0] = pms->count[1] = 0;
1573 pms->abcd[0] = 0x67452301;
1574 pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
1575 pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
1576 pms->abcd[3] = 0x10325476;
1581 Util::md5_append(md5_state_t *pms, const uint8_t *data, int nbytes)
1583 const uint8_t *p = data;
1585 int offset = (pms->count[0] >> 3) & 63;
1586 uint16_t nbits = (uint16_t)(nbytes << 3);
1589 /* Update the message length. */
1590 pms->count[1] += nbytes >> 29;
1591 pms->count[0] += nbits;
1592 if (pms->count[0] < nbits)
1594 /* Process an initial partial block. */
1596 int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
1597 memcpy(pms->buf + offset, p, copy);
1598 if (offset + copy < 64)
1602 md5_process(pms, pms->buf);
1604 /* Process full blocks. */
1605 for (; left >= 64; p += 64, left -= 64)
1606 md5_process(pms, p);
1607 /* Process a final partial block. */
1609 memcpy(pms->buf, p, left);
1612 Util::md5_finish(md5_state_t *pms, uint8_t digest[16])
1614 static const uint8_t pad[64] = {
1615 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1616 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1617 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1618 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
1623 /* Save the length before padding. */
1624 for (i = 0; i < 8; ++i)
1625 data[i] = (uint8_t)(pms->count[i >> 2] >> ((i & 3) << 3));
1626 /* Pad to 56 bytes mod 64. */
1627 md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
1628 /* Append the length. */
1629 md5_append(pms, data, 8);
1630 for (i = 0; i < 16; ++i)
1631 digest[i] = (uint8_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
1634 //-------------------------------------------------------------------------
1635 } // end namespace gdcm