1 /*=========================================================================
4 Module: $RCSfile: gdcmUtil.cxx,v $
6 Date: $Date: 2008/01/02 14:58:00 $
7 Version: $Revision: 1.190 $
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_ADDRESS = 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
968 assert( !RootUID.empty() );
976 // A root was specified use it to forge our new UID:
978 //append += Util::GetMACAddress(); // to save CPU time
979 if( !Util::GDCM_MAC_ADDRESS.empty() ) // When mac address was empty we would end up with a double . which is illegal
981 append += Util::GDCM_MAC_ADDRESS;
984 append += Util::GetCurrentDateTime();
986 //Also add a mini random number just in case:
988 int r = (int) (100.0*rand()/RAND_MAX);
989 // Don't use Util::Format to accelerate the execution
990 sprintf(tmp,"%02d", r);
993 // If append is too long we need to rehash it
994 if ( (prefix + append).size() > 64 )
996 gdcmStaticErrorMacro( "Size of UID is too long." );
997 // we need a hash function to truncate this number
998 // if only md5 was cross plateform
1002 return prefix + append;
1005 void Util::SetRootUID(const std::string &root)
1013 const std::string &Util::GetRootUID()
1018 //-------------------------------------------------------------------------
1020 * \brief binary_write binary_write
1021 * @param os ostream to write to
1022 * @param val 16 bits value to write
1024 std::ostream &binary_write(std::ostream &os, const uint16_t &val)
1026 #if defined(GDCM_WORDS_BIGENDIAN) || defined(GDCM_FORCE_BIGENDIAN_EMULATION)
1028 swap = ( val << 8 | val >> 8 );
1030 return os.write(reinterpret_cast<const char*>(&swap), 2);
1032 return os.write(reinterpret_cast<const char*>(&val), 2);
1033 #endif //GDCM_WORDS_BIGENDIAN
1037 * \brief binary_write binary_write
1038 * @param os ostream to write to
1039 * @param val 32 bits value to write
1041 std::ostream &binary_write(std::ostream &os, const uint32_t &val)
1043 #if defined(GDCM_WORDS_BIGENDIAN) || defined(GDCM_FORCE_BIGENDIAN_EMULATION)
1045 swap = ( (val<<24) | ((val<<8) & 0x00ff0000) |
1046 ((val>>8) & 0x0000ff00) | (val>>24) );
1047 return os.write(reinterpret_cast<const char*>(&swap), 4);
1049 return os.write(reinterpret_cast<const char*>(&val), 4);
1050 #endif //GDCM_WORDS_BIGENDIAN
1054 * \brief binary_write binary_write
1055 * @param os ostream to write to
1056 * @param val double (64 bits) value to write
1058 std::ostream &binary_write(std::ostream &os, const double &val)
1060 #if defined(GDCM_WORDS_BIGENDIAN) || defined(GDCM_FORCE_BIGENDIAN_EMULATION)
1063 char *beg = (char *)&swap;
1064 char *end = beg + 7;
1066 for (unsigned int i = 0; i<7; i++)
1074 return os.write(reinterpret_cast<const char*>(&swap), 8);
1076 return os.write(reinterpret_cast<const char*>(&val), 8);
1077 #endif //GDCM_WORDS_BIGENDIAN
1081 * \brief binary_write binary_write
1082 * @param os ostream to write to
1083 * @param val 8 bits characters aray to write
1085 std::ostream &binary_write(std::ostream &os, const char *val)
1087 return os.write(val, strlen(val));
1091 * \brief binary_write binary_write
1092 * @param os ostream to write to
1093 * @param val std::string value to write
1095 std::ostream &binary_write(std::ostream &os, std::string const &val)
1097 return os.write(val.c_str(), val.size());
1101 * \brief binary_write binary_write
1102 * @param os ostream to write to
1103 * @param val 8 bits 'characters' aray to write
1104 * @param len length of the 'value' to be written
1106 std::ostream &binary_write(std::ostream &os, const uint8_t *val, size_t len)
1108 // We are writting sizeof(char) thus no need to swap bytes
1109 return os.write(reinterpret_cast<const char*>(val), len);
1113 * \brief binary_write binary_write
1114 * @param os ostream to write to
1115 * @param val 16 bits words aray to write
1116 * @param len length (in bytes) of the 'value' to be written
1118 std::ostream &binary_write(std::ostream &os, const uint16_t *val, size_t len)
1120 // This is tricky since we are writting two bytes buffer.
1121 // Be carefull with little endian vs big endian.
1122 // Also this other trick is to allocate a small (efficient) buffer that store
1123 // intermediate result before writting it.
1124 #if defined(GDCM_WORDS_BIGENDIAN) || defined(GDCM_FORCE_BIGENDIAN_EMULATION)
1125 const int BUFFER_SIZE = 4096;
1126 static char buffer[BUFFER_SIZE];
1127 uint16_t *binArea16 = (uint16_t*)val; //for the const
1129 // how many BUFFER_SIZE long pieces in binArea ?
1130 int nbPieces = len/BUFFER_SIZE; //(16 bits = 2 Bytes)
1131 int remainingSize = len%BUFFER_SIZE;
1133 for (int j=0;j<nbPieces;j++)
1135 uint16_t *pbuffer = (uint16_t*)buffer; //reinitialize pbuffer
1136 for (int i = 0; i < BUFFER_SIZE/2; i++)
1138 *pbuffer = *binArea16 >> 8 | *binArea16 << 8;
1142 os.write ( buffer, BUFFER_SIZE );
1144 if ( remainingSize > 0)
1146 uint16_t *pbuffer = (uint16_t*)buffer; //reinitialize pbuffer
1147 for (int i = 0; i < remainingSize/2; i++)
1149 *pbuffer = *binArea16 >> 8 | *binArea16 << 8;
1153 os.write ( buffer, remainingSize );
1157 return os.write(reinterpret_cast<const char*>(val), len);
1161 std::string Util::ConvertToMD5 (std::string &inPszToCrypt)
1163 char *szChar = new char[ inPszToCrypt.size()+1 ];
1164 char *szHexOutput = new char[ 16 * 2 + 1 ];
1166 strcpy( szChar, inPszToCrypt.c_str() );
1167 // création du code md5
1168 nLen = strlen( szChar );
1170 uint8_t digest[ 16 ];
1171 md5_init ( &state );
1172 md5_append ( &state, (const uint8_t *)szChar, nLen);
1173 md5_finish ( &state, digest );
1174 for ( nDi = 0; nDi < 16; nDi++)
1175 sprintf( szHexOutput + nDi * 2, "%02x", digest[ nDi ] );
1176 szHexOutput[16 * 2]=0;
1178 std::string md5String=szHexOutput;
1179 delete [] szHexOutput;
1183 //-------------------------------------------------------------------------
1186 //-------------------------------------------------------------------------
1189 * \brief Return the IP adress of the machine writting the DICOM image
1191 std::string Util::GetIPAddress()
1193 // This is a rip from
1194 // http://www.codeguru.com/Cpp/I-N/internet/network/article.php/c3445/
1195 #ifndef HOST_NAME_MAX
1196 // SUSv2 guarantees that `Host names are limited to 255 bytes'.
1197 // POSIX 1003.1-2001 guarantees that `Host names (not including the
1198 // terminating NUL) are limited to HOST_NAME_MAX bytes'.
1199 #define HOST_NAME_MAX 255
1200 // In this case we should maybe check the string was not truncated.
1201 // But I don't known how to check that...
1202 #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__)
1203 // with WinSock DLL we need to initialize the WinSock before using gethostname
1204 WORD wVersionRequested = MAKEWORD(1,0);
1206 int err = WSAStartup(wVersionRequested,&WSAData);
1209 // Tell the user that we could not find a usable
1216 #endif //HOST_NAME_MAX
1219 char szHostName[HOST_NAME_MAX+1];
1220 int r = gethostname(szHostName, HOST_NAME_MAX);
1224 // Get host adresses
1225 struct hostent *pHost = gethostbyname(szHostName);
1227 for( int i = 0; pHost!= NULL && pHost->h_addr_list[i]!= NULL; i++ )
1229 for( int j = 0; j<pHost->h_length; j++ )
1231 if ( j > 0 ) str += ".";
1233 str += Util::Format("%u",
1234 (unsigned int)((unsigned char*)pHost->h_addr_list[i])[j]);
1236 // str now contains one local IP address
1238 #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__)
1244 // If an error occur r == -1
1245 // Most of the time it will return 127.0.0.1...
1249 void Util::hfpswap(double *a, double *b)
1259 Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved.
1261 This software is provided 'as-is', without any express or implied
1262 warranty. In no event will the authors be held liable for any damages
1263 arising from the use of this software.
1265 Permission is granted to anyone to use this software for any purpose,
1266 including commercial applications, and to alter it and redistribute it
1267 freely, subject to the following restrictions:
1269 1. The origin of this software must not be misrepresented; you must not
1270 claim that you wrote the original software. If you use this software
1271 in a product, an acknowledgment in the product documentation would be
1272 appreciated but is not required.
1273 2. Altered source versions must be plainly marked as such, and must not be
1274 misrepresented as being the original software.
1275 3. This notice may not be removed or altered from any source distribution.
1282 /* $Id: gdcmUtil.cxx,v 1.190 2008/01/02 14:58:00 malaterre Exp $ */
1285 Independent implementation of MD5 (RFC 1321).
1286 This code implements the MD5 Algorithm defined in RFC 1321, whose
1287 text is available at
1289 http://www.ietf.org/rfc/rfc1321.txt
1291 The code is derived from the text of the RFC, including the test suite
1292 (section A.5) but excluding the rest of Appendix A. It does not include
1293 any code or documentation that is identified in the RFC as being
1296 The original and principal author of md5.c is L. Peter Deutsch
1297 <ghost@aladdin.com>. Other authors are noted in the change history
1298 that follows (in reverse chronological order):
1300 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
1301 either statically or dynamically; added missing #include <string.h>
1303 2002-03-11 lpd Corrected argument list for main(), and added int return
1304 type, in test program and T value program.
1305 2002-02-21 lpd Added missing #include <stdio.h> in test program.
1306 2000-07-03 lpd Patched to eliminate warnings about "constant is
1307 unsigned in ANSI C, signed in traditional"; made test program
1309 1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
1310 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
1311 1999-05-03 lpd Original version.
1315 //#include <string.h>
1317 #undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */
1318 #ifdef ARCH_IS_BIG_ENDIAN
1319 # define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
1321 # define BYTE_ORDER 0
1325 #define T_MASK ((uint16_t)~0)
1326 #define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
1327 #define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
1328 #define T3 0x242070db
1329 #define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
1330 #define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
1331 #define T6 0x4787c62a
1332 #define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
1333 #define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
1334 #define T9 0x698098d8
1335 #define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
1336 #define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
1337 #define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
1338 #define T13 0x6b901122
1339 #define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
1340 #define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
1341 #define T16 0x49b40821
1342 #define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
1343 #define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
1344 #define T19 0x265e5a51
1345 #define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
1346 #define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
1347 #define T22 0x02441453
1348 #define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
1349 #define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
1350 #define T25 0x21e1cde6
1351 #define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
1352 #define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
1353 #define T28 0x455a14ed
1354 #define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
1355 #define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
1356 #define T31 0x676f02d9
1357 #define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
1358 #define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
1359 #define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
1360 #define T35 0x6d9d6122
1361 #define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
1362 #define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
1363 #define T38 0x4bdecfa9
1364 #define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
1365 #define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
1366 #define T41 0x289b7ec6
1367 #define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
1368 #define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
1369 #define T44 0x04881d05
1370 #define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
1371 #define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
1372 #define T47 0x1fa27cf8
1373 #define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
1374 #define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
1375 #define T50 0x432aff97
1376 #define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
1377 #define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
1378 #define T53 0x655b59c3
1379 #define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
1380 #define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
1381 #define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
1382 #define T57 0x6fa87e4f
1383 #define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
1384 #define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
1385 #define T60 0x4e0811a1
1386 #define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
1387 #define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
1388 #define T63 0x2ad7d2bb
1389 #define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
1393 Util::md5_process(md5_state_t *pms, const uint8_t *data /*[64]*/)
1396 a = pms->abcd[0], b = pms->abcd[1],
1397 c = pms->abcd[2], d = pms->abcd[3];
1401 /* Define storage only for big-endian CPUs. */
1404 /* Define storage for little-endian or both types of CPUs. */
1411 * Determine dynamically whether this is a big-endian or
1412 * little-endian machine, since we can use a more efficient
1413 * algorithm on the latter.
1415 static const int w = 1;
1417 if (*((const uint8_t *)&w)) /* dynamic little-endian */
1419 #if BYTE_ORDER <= 0 /* little-endian */
1422 * On little-endian machines, we can process properly aligned
1423 * data without copying it.
1425 if (!((data - (const uint8_t *)0) & 3)) {
1426 /* data are properly aligned */
1427 X = (const uint16_t *)data;
1430 memcpy(xbuf, data, 64);
1436 else /* dynamic big-endian */
1438 #if BYTE_ORDER >= 0 /* big-endian */
1441 * On big-endian machines, we must arrange the bytes in the
1444 const uint8_t *xp = data;
1447 # if BYTE_ORDER == 0
1448 X = xbuf; /* (dynamic only) */
1450 # define xbuf /* (static only) */
1452 for (i = 0; i < 16; ++i, xp += 4)
1453 xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
1458 #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
1461 /* Let [abcd k s i] denote the operation
1462 a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
1464 #define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
1465 #define SET(a, b, c, d, k, s, Ti) \
1466 t = a + F(b,c,d) + X[k] + Ti;\
1467 a = ROTATE_LEFT(t, s) + b
1468 /* Do the following 16 operations. */
1469 SET(a, b, c, d, 0, 7, T1);
1470 SET(d, a, b, c, 1, 12, T2);
1471 SET(c, d, a, b, 2, 17, T3);
1472 SET(b, c, d, a, 3, 22, T4);
1473 SET(a, b, c, d, 4, 7, T5);
1474 SET(d, a, b, c, 5, 12, T6);
1475 SET(c, d, a, b, 6, 17, T7);
1476 SET(b, c, d, a, 7, 22, T8);
1477 SET(a, b, c, d, 8, 7, T9);
1478 SET(d, a, b, c, 9, 12, T10);
1479 SET(c, d, a, b, 10, 17, T11);
1480 SET(b, c, d, a, 11, 22, T12);
1481 SET(a, b, c, d, 12, 7, T13);
1482 SET(d, a, b, c, 13, 12, T14);
1483 SET(c, d, a, b, 14, 17, T15);
1484 SET(b, c, d, a, 15, 22, T16);
1487 /* Let [abcd k s i] denote the operation
1488 a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
1490 #define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
1491 #define SET(a, b, c, d, k, s, Ti)\
1492 t = a + G(b,c,d) + X[k] + Ti; \
1493 a = ROTATE_LEFT(t, s) + b
1494 /* Do the following 16 operations. */
1495 SET(a, b, c, d, 1, 5, T17);
1496 SET(d, a, b, c, 6, 9, T18);
1497 SET(c, d, a, b, 11, 14, T19);
1498 SET(b, c, d, a, 0, 20, T20);
1499 SET(a, b, c, d, 5, 5, T21);
1500 SET(d, a, b, c, 10, 9, T22);
1501 SET(c, d, a, b, 15, 14, T23);
1502 SET(b, c, d, a, 4, 20, T24);
1503 SET(a, b, c, d, 9, 5, T25);
1504 SET(d, a, b, c, 14, 9, T26);
1505 SET(c, d, a, b, 3, 14, T27);
1506 SET(b, c, d, a, 8, 20, T28);
1507 SET(a, b, c, d, 13, 5, T29);
1508 SET(d, a, b, c, 2, 9, T30);
1509 SET(c, d, a, b, 7, 14, T31);
1510 SET(b, c, d, a, 12, 20, T32);
1513 /* Let [abcd k s t] denote the operation
1514 a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
1515 #define H(x, y, z) ((x) ^ (y) ^ (z))
1516 #define SET(a, b, c, d, k, s, Ti)\
1517 t = a + H(b,c,d) + X[k] + Ti; \
1518 a = ROTATE_LEFT(t, s) + b
1520 /* Do the following 16 operations. */
1521 SET(a, b, c, d, 5, 4, T33);
1522 SET(d, a, b, c, 8, 11, T34);
1523 SET(c, d, a, b, 11, 16, T35);
1524 SET(b, c, d, a, 14, 23, T36);
1525 SET(a, b, c, d, 1, 4, T37);
1526 SET(d, a, b, c, 4, 11, T38);
1527 SET(c, d, a, b, 7, 16, T39);
1528 SET(b, c, d, a, 10, 23, T40);
1529 SET(a, b, c, d, 13, 4, T41);
1530 SET(d, a, b, c, 0, 11, T42);
1531 SET(c, d, a, b, 3, 16, T43);
1532 SET(b, c, d, a, 6, 23, T44);
1533 SET(a, b, c, d, 9, 4, T45);
1534 SET(d, a, b, c, 12, 11, T46);
1535 SET(c, d, a, b, 15, 16, T47);
1536 SET(b, c, d, a, 2, 23, T48);
1539 /* Let [abcd k s t] denote the operation
1540 a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
1541 #define I(x, y, z) ((y) ^ ((x) | ~(z)))
1542 #define SET(a, b, c, d, k, s, Ti)\
1543 t = a + I(b,c,d) + X[k] + Ti; \
1544 a = ROTATE_LEFT(t, s) + b
1546 /* Do the following 16 operations. */
1547 SET(a, b, c, d, 0, 6, T49);
1548 SET(d, a, b, c, 7, 10, T50);
1549 SET(c, d, a, b, 14, 15, T51);
1550 SET(b, c, d, a, 5, 21, T52);
1551 SET(a, b, c, d, 12, 6, T53);
1552 SET(d, a, b, c, 3, 10, T54);
1553 SET(c, d, a, b, 10, 15, T55);
1554 SET(b, c, d, a, 1, 21, T56);
1555 SET(a, b, c, d, 8, 6, T57);
1556 SET(d, a, b, c, 15, 10, T58);
1557 SET(c, d, a, b, 6, 15, T59);
1558 SET(b, c, d, a, 13, 21, T60);
1559 SET(a, b, c, d, 4, 6, T61);
1560 SET(d, a, b, c, 11, 10, T62);
1561 SET(c, d, a, b, 2, 15, T63);
1562 SET(b, c, d, a, 9, 21, T64);
1565 /* Then perform the following additions. (That is increment each
1566 of the four registers by the value it had before this block
1574 Util::md5_init(md5_state_t *pms)
1576 pms->count[0] = pms->count[1] = 0;
1577 pms->abcd[0] = 0x67452301;
1578 pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
1579 pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
1580 pms->abcd[3] = 0x10325476;
1585 Util::md5_append(md5_state_t *pms, const uint8_t *data, int nbytes)
1587 const uint8_t *p = data;
1589 int offset = (pms->count[0] >> 3) & 63;
1590 uint16_t nbits = (uint16_t)(nbytes << 3);
1593 /* Update the message length. */
1594 pms->count[1] += nbytes >> 29;
1595 pms->count[0] += nbits;
1596 if (pms->count[0] < nbits)
1598 /* Process an initial partial block. */
1600 int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
1601 memcpy(pms->buf + offset, p, copy);
1602 if (offset + copy < 64)
1606 md5_process(pms, pms->buf);
1608 /* Process full blocks. */
1609 for (; left >= 64; p += 64, left -= 64)
1610 md5_process(pms, p);
1611 /* Process a final partial block. */
1613 memcpy(pms->buf, p, left);
1616 Util::md5_finish(md5_state_t *pms, uint8_t digest[16])
1618 static const uint8_t pad[64] = {
1619 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1620 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1621 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1622 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
1627 /* Save the length before padding. */
1628 for (i = 0; i < 8; ++i)
1629 data[i] = (uint8_t)(pms->count[i >> 2] >> ((i & 3) << 3));
1630 /* Pad to 56 bytes mod 64. */
1631 md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
1632 /* Append the length. */
1633 md5_append(pms, data, 8);
1634 for (i = 0; i < 16; ++i)
1635 digest[i] = (uint8_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
1638 //-------------------------------------------------------------------------
1639 } // end namespace gdcm