1 /*=========================================================================
4 Module: $RCSfile: gdcmUtil.cxx,v $
6 Date: $Date: 2007/10/01 09:25:06 $
7 Version: $Revision: 1.188 $
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...
106 const uint16_t Util::FMIV = 0x0100;
107 uint8_t *Util::FileMetaInformationVersion = (uint8_t *)&FMIV;
108 std::string Util::GDCM_MAC_ADRESS = GetMACAddress();
110 //-------------------------------------------------------------------------
113 * \brief Provide a better 'c++' approach for sprintf
114 * For example c code is:
115 * char result[2048]; // hope 2048 is enough
116 * sprintf(result, "%04x|%04x", group , elem);
119 * std::ostringstream buf;
120 * buf << std::right << std::setw(4) << std::setfill('0') << std::hex
121 * << group << "|" << std::right << std::setw(4) << std::setfill('0')
122 * << std::hex << elem;
127 * result = gdcm::Util::Format("%04x|%04x", group , elem);
129 std::string Util::Format(const char *format, ...)
131 char buffer[2048]; // hope 2048 is enough
133 va_start(args, format);
134 vsprintf(buffer, format, args); //might be a security flaw
135 va_end(args); // Each invocation of va_start should be matched
136 // by a corresponding invocation of va_end
137 // args is then 'undefined'
143 * \brief Because not available in C++ (?)
144 * @param str string to check
145 * @param tokens std::vector to receive the tokenized substrings
146 * @param delimiters string containing the character delimitors
149 void Util::Tokenize (const std::string &str,
150 std::vector<std::string> &tokens,
151 const std::string &delimiters)
153 std::string::size_type lastPos = str.find_first_not_of(delimiters,0);
154 std::string::size_type pos = str.find_first_of (delimiters,lastPos);
155 while (std::string::npos != pos || std::string::npos != lastPos)
157 tokens.push_back(str.substr(lastPos, pos - lastPos));
158 lastPos = str.find_first_not_of(delimiters, pos);
159 pos = str.find_first_of (delimiters, lastPos);
164 * \brief Because not available in C++ (?)
165 * Counts the number of occurences of a substring within a string
166 * @param str string to check
167 * @param subStr substring to count
170 int Util::CountSubstring (const std::string &str,
171 const std::string &subStr)
173 int count = 0; // counts how many times it appears
174 std::string::size_type x = 0; // The index position in the string
178 x = str.find(subStr,x); // Find the substring
179 if (x != std::string::npos) // If present
181 count++; // increase the count
182 x += subStr.length(); // Skip this word
185 while (x != std::string::npos);// Carry on until not present
191 * \brief Checks whether a 'string' is printable or not (in order
192 * to avoid corrupting the terminal of invocation when printing)
193 * @param s string to check
195 bool Util::IsCleanString(std::string const &s)
197 for(unsigned int i=0; i<s.size(); i++)
199 if (!isprint((unsigned char)s[i]) )
208 * \brief Checks whether an 'area' is printable or not (in order
209 * to avoid corrupting the terminal of invocation when printing)
210 * @param s area to check (uint8_t is just for prototyping. feel free to cast)
211 * @param l area length to check
213 bool Util::IsCleanArea(uint8_t *s, int l)
215 for( int i=0; i<l; i++)
217 if (!isprint((unsigned char)s[i]) )
225 * \brief Weed out a string from the non-printable characters (in order
226 * to avoid corrupting the terminal of invocation when printing)
227 * @param s string to check (uint8_t is just for prototyping. feel free to cast)
229 std::string Util::CreateCleanString(std::string const &s)
233 for(unsigned int i=0; i<str.size(); i++)
235 if (!isprint((unsigned char)str[i]) )
242 if (!isprint((unsigned char)s[str.size()-1]) )
244 if (s[str.size()-1] == 0 )
246 str[str.size()-1] = ' ';
253 * \brief Replaces all special characters
254 * @param s string to modify
255 * @param rep replacement char
257 void Util::ReplaceSpecChar(std::string &s, std::string &rep)
259 unsigned int s_size = s.size();
260 for(unsigned int i=0; i<s_size; i++)
262 if (! ( s[i] == '.' || s[i] == '%' || s[i] == '_'
263 || (s[i] >= '+' && s[i] <= '-')
264 || (s[i] >= 'a' && s[i] <= 'z')
265 || (s[i] >= '0' && s[i] <= '9')
266 || (s[i] >= 'A' && s[i] <= 'Z')))
268 s.replace(i, 1, rep);
271 // deal with Dicom strings trailing '\0'
272 if(s[s_size-1] == rep.c_str()[0])
273 s.erase(s_size-1, 1);
278 * \brief Weed out a string from the non-printable characters (in order
279 * to avoid corrupting the terminal of invocation when printing)
280 * @param s area to process (uint8_t is just for prototyping. feel free to cast)
281 * @param l area length to check
283 std::string Util::CreateCleanString(uint8_t *s, int l)
287 for( int i=0; i<l; i++)
289 if (!isprint((unsigned char)s[i]) )
295 str = str + (char )s[i];
302 * \brief Add a SEPARATOR to the end of the name if necessary
303 * @param pathname file/directory name to normalize
305 std::string Util::NormalizePath(std::string const &pathname)
308 const char SEPARATOR_X = '/';
309 const char SEPARATOR_WIN = '\\';
311 const std::string SEPARATOR = "\\";
313 const std::string SEPARATOR = "/";
316 std::string name = pathname;
317 int size = name.size();
319 // if ( name[size-1] != SEPARATOR_X && name[size-1] != SEPARATOR_WIN )
320 if ( name[size-1] != GDCM_FILESEPARATOR )
322 name += GDCM_FILESEPARATOR;
328 * \brief Get the (directory) path from a full path file name
329 * @param fullName file/directory name to extract Path from
331 std::string Util::GetPath(std::string const &fullName)
333 std::string res = fullName;
336 int pos1 = res.rfind("/");
337 int pos2 = res.rfind("\\");
347 int pos = res.rfind(GDCM_FILESEPARATOR);
353 * \brief Get the (last) name of a full path file name
354 * @param fullName file/directory name to extract end name from
356 std::string Util::GetName(std::string const &fullName)
358 std::string filename = fullName;
360 std::string::size_type slash_pos = filename.rfind("/");
361 std::string::size_type backslash_pos = filename.rfind("\\");
362 // At least with my gcc4.0.1, unfound char results in pos =4294967295 ...
363 //slash_pos = slash_pos > backslash_pos ? slash_pos : backslash_pos;
364 slash_pos = slash_pos < backslash_pos ? slash_pos : backslash_pos;
366 std::string::size_type slash_pos = filename.rfind(GDCM_FILESEPARATOR);
367 if (slash_pos != std::string::npos )
369 return filename.substr(slash_pos + 1);
378 * \brief Get the current date of the system in a dicom string
380 std::string Util::GetCurrentDate()
385 strftime(tmp,512,"%Y%m%d", localtime(&tloc) );
390 * \brief Get the current time of the system in a dicom string
392 std::string Util::GetCurrentTime()
397 strftime(tmp,512,"%H%M%S", localtime(&tloc) );
402 * \brief Get both the date and time at the same time to avoid problem
403 * around midnight where the two calls could be before and after midnight
405 std::string Util::GetCurrentDateTime()
411 // We need implementation specific functions to obtain millisecond precision
412 #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__)
416 milliseconds = tb.millitm;
419 gettimeofday (&tv, NULL);
421 // Compute milliseconds from microseconds.
422 milliseconds = tv.tv_usec / 1000;
424 // Obtain the time of day, and convert it to a tm struct.
425 struct tm *ptm = localtime (&timep);
426 // Format the date and time, down to a single second.
427 strftime (tmp, sizeof (tmp), "%Y%m%d%H%M%S", ptm);
430 // Don't use Util::Format to accelerate execution of code
432 sprintf(tmpAll,"%s%03ld",tmp,milliseconds);
437 unsigned int Util::GetCurrentThreadID()
439 // FIXME the implementation is far from complete
440 #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__)
441 return (unsigned int)GetCurrentThreadId();
445 // Doesn't work on fedora, but is in the man page...
446 //return (unsigned int)gettid();
449 return (unsigned int)thr_self();
451 //default implementation
458 unsigned int Util::GetCurrentProcessID()
460 #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__)
461 // NOTE: There is also a _getpid()...
462 return (unsigned int)GetCurrentProcessId();
464 // get process identification, POSIX
465 return (unsigned int)getpid();
470 * \brief tells us whether the processor we are working with is BigEndian or not
472 bool Util::IsCurrentProcessorBigEndian()
474 #if defined(GDCM_WORDS_BIGENDIAN)
482 * \brief Create a /DICOM/ string:
483 * It should a of even length (no odd length ever)
484 * It can contain as many (if you are reading this from your
485 * editor the following character is backslash followed by zero
486 * that needed to be escaped with an extra backslash for doxygen) \\0
489 std::string Util::DicomString(const char *s, size_t l)
491 std::string r(s, s+l);
492 gdcmAssertMacro( !(r.size() % 2) ); // == basically 'l' is even
497 * \brief Create a /DICOM/ string:
498 * It should a of even length (no odd length ever)
499 * It can contain as many (if you are reading this from your
500 * editor the following character is backslash followed by zero
501 * that needed to be escaped with an extra backslash for doxygen) \\0
503 * This function is similar to DicomString(const char*),
504 * except it doesn't take a length.
505 * It only pad with a null character if length is odd
507 std::string Util::DicomString(const char *s)
509 size_t l = strlen(s);
514 std::string r(s, s+l);
515 gdcmAssertMacro( !(r.size() % 2) );
520 * \brief Safely check the equality of two Dicom String:
521 * - Both strings should be of even length
522 * - We allow padding of even length string by either
523 * a null character of a space
525 bool Util::DicomStringEqual(const std::string &s1, const char *s2)
527 // s2 is the string from the DICOM reference e.g. : 'MONOCHROME1'
528 std::string s1_even = s1; //Never change input parameter
529 std::string s2_even = DicomString( s2 );
530 if ( s1_even[s1_even.size()-1] == ' ' )
532 s1_even[s1_even.size()-1] = '\0'; //replace space character by null
534 return s1_even == s2_even;
538 * \brief Safely compare two Dicom String:
539 * - Both strings should be of even length
540 * - We allow padding of even length string by either
541 * a null character of a space
543 bool Util::CompareDicomString(const std::string &s1, const char *s2, int op)
545 // s2 is the string from the DICOM reference e.g. : 'MONOCHROME1'
546 std::string s1_even = s1; //Never change input parameter
547 std::string s2_even = DicomString( s2 );
548 if ( s1_even[s1_even.size()-1] == ' ' )
550 s1_even[s1_even.size()-1] = '\0'; //replace space character by null
555 return s1_even == s2_even;
556 case GDCM_DIFFERENT :
557 return s1_even != s2_even;
559 return s1_even > s2_even;
560 case GDCM_GREATEROREQUAL :
561 return s1_even >= s2_even;
563 return s1_even < s2_even;
564 case GDCM_LESSOREQUAL :
565 return s1_even <= s2_even;
567 gdcmDebugMacro(" Wrong operator : " << op);
573 typedef BOOL(WINAPI * pSnmpExtensionInit) (
574 IN DWORD dwTimeZeroReference,
575 OUT HANDLE * hPollForTrapEvent,
576 OUT AsnObjectIdentifier * supportedView);
578 typedef BOOL(WINAPI * pSnmpExtensionTrap) (
579 OUT AsnObjectIdentifier * enterprise,
580 OUT AsnInteger * genericTrap,
581 OUT AsnInteger * specificTrap,
582 OUT AsnTimeticks * timeStamp,
583 OUT RFC1157VarBindList * variableBindings);
585 typedef BOOL(WINAPI * pSnmpExtensionQuery) (
587 IN OUT RFC1157VarBindList * variableBindings,
588 OUT AsnInteger * errorStatus,
589 OUT AsnInteger * errorIndex);
591 typedef BOOL(WINAPI * pSnmpExtensionInitEx) (
592 OUT AsnObjectIdentifier * supportedView);
596 static int SGIGetMacAddress(unsigned char *addr)
598 FILE *f = popen("/etc/nvram eaddr","r");
604 if(fscanf(f,"%02x:%02x:%02x:%02x:%02x:%02x",
605 x,x+1,x+2,x+3,x+4,x+5) != 6)
610 for(unsigned int i = 0; i < 6; i++)
612 addr[i] = static_cast<unsigned char>(x[i]);
618 /// \brief gets current M.A.C adress (for internal use only)
619 int GetMacAddrSys ( unsigned char *addr );
620 int GetMacAddrSys ( unsigned char *addr )
624 if ( (WSAStartup(MAKEWORD(2, 0), &WinsockData)) != 0 )
626 std::cerr << "in Get MAC Adress (internal) : This program requires Winsock 2.x!"
631 HANDLE PollForTrapEvent;
632 AsnObjectIdentifier SupportedView;
633 UINT OID_ifEntryType[] = { 1, 3, 6, 1, 2, 1, 2, 2, 1, 3 };
634 UINT OID_ifEntryNum[] = { 1, 3, 6, 1, 2, 1, 2, 1 };
635 UINT OID_ipMACEntAddr[] = { 1, 3, 6, 1, 2, 1, 2, 2, 1, 6 };
636 AsnObjectIdentifier MIB_ifMACEntAddr = {
637 sizeof(OID_ipMACEntAddr) / sizeof(UINT), OID_ipMACEntAddr };
638 AsnObjectIdentifier MIB_ifEntryType = {
639 sizeof(OID_ifEntryType) / sizeof(UINT), OID_ifEntryType };
640 AsnObjectIdentifier MIB_ifEntryNum = {
641 sizeof(OID_ifEntryNum) / sizeof(UINT), OID_ifEntryNum };
642 RFC1157VarBindList varBindList;
643 RFC1157VarBind varBind[2];
644 AsnInteger errorStatus;
645 AsnInteger errorIndex;
646 AsnObjectIdentifier MIB_NULL = { 0, 0 };
651 // Load the SNMP dll and get the addresses of the functions necessary
652 HINSTANCE m_hInst = LoadLibrary("inetmib1.dll");
653 if (m_hInst < (HINSTANCE) HINSTANCE_ERROR)
657 pSnmpExtensionInit m_Init =
658 (pSnmpExtensionInit) GetProcAddress(m_hInst, "SnmpExtensionInit");
659 pSnmpExtensionQuery m_Query =
660 (pSnmpExtensionQuery) GetProcAddress(m_hInst, "SnmpExtensionQuery");
661 m_Init(GetTickCount(), &PollForTrapEvent, &SupportedView);
663 /* Initialize the variable list to be retrieved by m_Query */
664 varBindList.list = varBind;
665 varBind[0].name = MIB_NULL;
666 varBind[1].name = MIB_NULL;
668 // Copy in the OID to find the number of entries in the
670 varBindList.len = 1; // Only retrieving one item
671 SNMP_oidcpy(&varBind[0].name, &MIB_ifEntryNum);
672 m_Query(ASN_RFC1157_GETNEXTREQUEST, &varBindList, &errorStatus,
674 // printf("# of adapters in this system : %i\n",
675 // varBind[0].value.asnValue.number);
678 // Copy in the OID of ifType, the type of interface
679 SNMP_oidcpy(&varBind[0].name, &MIB_ifEntryType);
681 // Copy in the OID of ifPhysAddress, the address
682 SNMP_oidcpy(&varBind[1].name, &MIB_ifMACEntAddr);
686 // Submit the query. Responses will be loaded into varBindList.
687 // We can expect this call to succeed a # of times corresponding
688 // to the # of adapters reported to be in the system
689 ret = m_Query(ASN_RFC1157_GETNEXTREQUEST, &varBindList, &errorStatus,
697 // Confirm that the proper type has been returned
698 ret = SNMP_oidncmp(&varBind[0].name, &MIB_ifEntryType,
699 MIB_ifEntryType.idLength);
704 dtmp = varBind[0].value.asnValue.number;
706 // Type 6 describes ethernet interfaces
709 // Confirm that we have an address here
710 ret = SNMP_oidncmp(&varBind[1].name, &MIB_ifMACEntAddr,
711 MIB_ifMACEntAddr.idLength);
712 if ( !ret && varBind[1].value.asnValue.address.stream != NULL )
714 if ( (varBind[1].value.asnValue.address.stream[0] == 0x44)
715 && (varBind[1].value.asnValue.address.stream[1] == 0x45)
716 && (varBind[1].value.asnValue.address.stream[2] == 0x53)
717 && (varBind[1].value.asnValue.address.stream[3] == 0x54)
718 && (varBind[1].value.asnValue.address.stream[4] == 0x00) )
720 // Ignore all dial-up networking adapters
721 std::cerr << "in Get MAC Adress (internal) : Interface #"
722 << j << " is a DUN adapter\n";
725 if ( (varBind[1].value.asnValue.address.stream[0] == 0x00)
726 && (varBind[1].value.asnValue.address.stream[1] == 0x00)
727 && (varBind[1].value.asnValue.address.stream[2] == 0x00)
728 && (varBind[1].value.asnValue.address.stream[3] == 0x00)
729 && (varBind[1].value.asnValue.address.stream[4] == 0x00)
730 && (varBind[1].value.asnValue.address.stream[5] == 0x00) )
732 // Ignore NULL addresses returned by other network
734 std::cerr << "in Get MAC Adress (internal) : Interface #"
735 << j << " is a NULL address\n";
738 memcpy( addr, varBind[1].value.asnValue.address.stream, 6);
745 SNMP_FreeVarBind(&varBind[0]);
746 SNMP_FreeVarBind(&varBind[1]);
748 #endif //Win32 version
751 return SGIGetMacAddress(addr);
755 // implementation for POSIX system
756 #if defined(CMAKE_HAVE_NET_IF_ARP_H) && defined(__sun)
757 //The POSIX version is broken anyway on Solaris, plus would require full
759 struct arpreq parpreq;
760 struct sockaddr_in *psa;
761 struct hostent *phost;
762 char hostname[MAXHOSTNAMELEN];
766 if (gethostname(hostname, MAXHOSTNAMELEN) != 0 )
768 perror("in Get MAC Adress (internal) : gethostname");
771 phost = gethostbyname(hostname);
772 paddrs = phost->h_addr_list;
774 sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
777 perror("in Get MAC Adress (internal) : sock");
780 memset(&parpreq, 0, sizeof(struct arpreq));
781 psa = (struct sockaddr_in *) &parpreq.arp_pa;
783 memset(psa, 0, sizeof(struct sockaddr_in));
784 psa->sin_family = AF_INET;
785 memcpy(&psa->sin_addr, *paddrs, sizeof(struct in_addr));
787 status = ioctl(sock, SIOCGARP, &parpreq);
790 perror("in Get MAC Adress (internal) : SIOCGARP");
793 memcpy(addr, parpreq.arp_ha.sa_data, 6);
797 #ifdef CMAKE_HAVE_NET_IF_H
799 struct ifreq ifr, *ifrp;
804 #if defined(AF_LINK) && (!defined(SIOCGIFHWADDR) && !defined(SIOCGENADDR))
805 struct sockaddr_dl *sdlp;
809 // BSD 4.4 defines the size of an ifreq to be
810 // max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len
811 // However, under earlier systems, sa_len isn't present, so the size is
812 // just sizeof(struct ifreq)
813 // We should investigate the use of SIZEOF_ADDR_IFREQ
817 #define max(a,b) ((a) > (b) ? (a) : (b))
819 #define ifreq_size(i) max(sizeof(struct ifreq),\
820 sizeof((i).ifr_name)+(i).ifr_addr.sa_len)
822 #define ifreq_size(i) sizeof(struct ifreq)
823 #endif // HAVE_SA_LEN
825 if ( (sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0 )
829 memset(buf, 0, sizeof(buf));
830 ifc.ifc_len = sizeof(buf);
832 if (ioctl (sd, SIOCGIFCONF, (char *)&ifc) < 0)
838 for (i = 0; i < n; i+= ifreq_size(*ifrp) )
840 ifrp = (struct ifreq *)((char *) ifc.ifc_buf+i);
841 strncpy(ifr.ifr_name, ifrp->ifr_name, IFNAMSIZ);
843 if (ioctl(sd, SIOCGIFHWADDR, &ifr) < 0)
845 a = (unsigned char *) &ifr.ifr_hwaddr.sa_data;
848 // In theory this call should also work on Sun Solaris, but apparently
849 // SIOCGENADDR is not implemented properly thus the call
850 // ioctl(sd, SIOCGENADDR, &ifr) always returns errno=2
851 // (No such file or directory)
852 // Furthermore the DLAPI seems to require full root access
853 if (ioctl(sd, SIOCGENADDR, &ifr) < 0)
855 a = (unsigned char *) ifr.ifr_enaddr;
858 sdlp = (struct sockaddr_dl *) &ifrp->ifr_addr;
859 if ((sdlp->sdl_family != AF_LINK) || (sdlp->sdl_alen != 6))
861 a = (unsigned char *) &sdlp->sdl_data[sdlp->sdl_nlen];
863 perror("in Get MAC Adress (internal) : No way to access hardware");
867 #endif // SIOCGENADDR
868 #endif // SIOCGIFHWADDR
869 if (!a[0] && !a[1] && !a[2] && !a[3] && !a[4] && !a[5]) continue;
880 // Not implemented platforms (or no Ethernet cable !)
882 /// \todo FIXME I wish we don't pollute command line applications when no Ethernet cable !
883 //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)");
885 // But the following -> error: invalid use of 'this' in non-member function
886 //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)");
894 * \brief Mini function to return the last digit from a number express in base 256
895 * pre condition data contain an array of 6 unsigned char
896 * post condition carry contain the last digit
898 inline int getlastdigit(unsigned char *data)
900 int extended, carry = 0;
903 extended = (carry << 8) + data[i];
904 data[i] = extended / 10;
905 carry = extended % 10;
911 * \brief Encode the mac address on a fixed length string of 15 characters.
912 * we save space this way.
914 std::string Util::GetMACAddress()
916 // This code is the result of a long internet search to find something
917 // as compact as possible (not OS independant). We only have to separate
918 // 3 OS: Win32, SunOS and 'real' POSIX
919 // http://groups-beta.google.com/group/comp.unix.solaris/msg/ad36929d783d63be
920 // http://bdn.borland.com/article/0,1410,26040,00.html
921 unsigned char addr[6];
923 int stat = GetMacAddrSys(addr);
926 // We need to convert a 6 digit number from base 256 to base 10, using integer
927 // would requires a 48bits one. To avoid this we have to reimplement the div + modulo
934 res = getlastdigit(addr);
935 sres.insert(sres.begin(), '0' + res);
936 zero = (addr[0] == 0) && (addr[1] == 0) && (addr[2] == 0)
937 && (addr[3] == 0) && (addr[4] == 0) && (addr[5] == 0);
944 gdcmStaticWarningMacro("Problem in finding the MAC Address");
950 * \brief Creates a new UID. As stipulated in the DICOM ref
951 * each time a DICOM image is created it should have
952 * a unique identifier (URI)
953 * @param root is the DICOM prefix assigned by IOS group
955 std::string Util::CreateUniqueUID(const std::string &root)
961 // gdcm UID prefix, as supplied by http://www.medicalconnections.co.uk
969 // A root was specified use it to forge our new UID:
971 //append += Util::GetMACAddress(); // to save CPU time
972 append += Util::GDCM_MAC_ADRESS;
974 append += Util::GetCurrentDateTime();
976 //Also add a mini random number just in case:
978 int r = (int) (100.0*rand()/RAND_MAX);
979 // Don't use Util::Format to accelerate the execution
980 sprintf(tmp,"%02d", r);
983 // If append is too long we need to rehash it
984 if ( (prefix + append).size() > 64 )
986 gdcmStaticErrorMacro( "Size of UID is too long." );
987 // we need a hash function to truncate this number
988 // if only md5 was cross plateform
992 return prefix + append;
995 void Util::SetRootUID(const std::string &root)
1003 const std::string &Util::GetRootUID()
1008 //-------------------------------------------------------------------------
1010 * \brief binary_write binary_write
1011 * @param os ostream to write to
1012 * @param val 16 bits value to write
1014 std::ostream &binary_write(std::ostream &os, const uint16_t &val)
1016 #if defined(GDCM_WORDS_BIGENDIAN) || defined(GDCM_FORCE_BIGENDIAN_EMULATION)
1018 swap = ( val << 8 | val >> 8 );
1020 return os.write(reinterpret_cast<const char*>(&swap), 2);
1022 return os.write(reinterpret_cast<const char*>(&val), 2);
1023 #endif //GDCM_WORDS_BIGENDIAN
1027 * \brief binary_write binary_write
1028 * @param os ostream to write to
1029 * @param val 32 bits value to write
1031 std::ostream &binary_write(std::ostream &os, const uint32_t &val)
1033 #if defined(GDCM_WORDS_BIGENDIAN) || defined(GDCM_FORCE_BIGENDIAN_EMULATION)
1035 swap = ( (val<<24) | ((val<<8) & 0x00ff0000) |
1036 ((val>>8) & 0x0000ff00) | (val>>24) );
1037 return os.write(reinterpret_cast<const char*>(&swap), 4);
1039 return os.write(reinterpret_cast<const char*>(&val), 4);
1040 #endif //GDCM_WORDS_BIGENDIAN
1044 * \brief binary_write binary_write
1045 * @param os ostream to write to
1046 * @param val double (64 bits) value to write
1048 std::ostream &binary_write(std::ostream &os, const double &val)
1050 #if defined(GDCM_WORDS_BIGENDIAN) || defined(GDCM_FORCE_BIGENDIAN_EMULATION)
1053 char *beg = (char *)&swap;
1054 char *end = beg + 7;
1056 for (unsigned int i = 0; i<7; i++)
1064 return os.write(reinterpret_cast<const char*>(&swap), 8);
1066 return os.write(reinterpret_cast<const char*>(&val), 8);
1067 #endif //GDCM_WORDS_BIGENDIAN
1071 * \brief binary_write binary_write
1072 * @param os ostream to write to
1073 * @param val 8 bits characters aray to write
1075 std::ostream &binary_write(std::ostream &os, const char *val)
1077 return os.write(val, strlen(val));
1081 * \brief binary_write binary_write
1082 * @param os ostream to write to
1083 * @param val std::string value to write
1085 std::ostream &binary_write(std::ostream &os, std::string const &val)
1087 return os.write(val.c_str(), val.size());
1091 * \brief binary_write binary_write
1092 * @param os ostream to write to
1093 * @param val 8 bits 'characters' aray to write
1094 * @param len length of the 'value' to be written
1096 std::ostream &binary_write(std::ostream &os, const uint8_t *val, size_t len)
1098 // We are writting sizeof(char) thus no need to swap bytes
1099 return os.write(reinterpret_cast<const char*>(val), len);
1103 * \brief binary_write binary_write
1104 * @param os ostream to write to
1105 * @param val 16 bits words aray to write
1106 * @param len length (in bytes) of the 'value' to be written
1108 std::ostream &binary_write(std::ostream &os, const uint16_t *val, size_t len)
1110 // This is tricky since we are writting two bytes buffer.
1111 // Be carefull with little endian vs big endian.
1112 // Also this other trick is to allocate a small (efficient) buffer that store
1113 // intermediate result before writting it.
1114 #if defined(GDCM_WORDS_BIGENDIAN) || defined(GDCM_FORCE_BIGENDIAN_EMULATION)
1115 const int BUFFER_SIZE = 4096;
1116 static char buffer[BUFFER_SIZE];
1117 uint16_t *binArea16 = (uint16_t*)val; //for the const
1119 // how many BUFFER_SIZE long pieces in binArea ?
1120 int nbPieces = len/BUFFER_SIZE; //(16 bits = 2 Bytes)
1121 int remainingSize = len%BUFFER_SIZE;
1123 for (int j=0;j<nbPieces;j++)
1125 uint16_t *pbuffer = (uint16_t*)buffer; //reinitialize pbuffer
1126 for (int i = 0; i < BUFFER_SIZE/2; i++)
1128 *pbuffer = *binArea16 >> 8 | *binArea16 << 8;
1132 os.write ( buffer, BUFFER_SIZE );
1134 if ( remainingSize > 0)
1136 uint16_t *pbuffer = (uint16_t*)buffer; //reinitialize pbuffer
1137 for (int i = 0; i < remainingSize/2; i++)
1139 *pbuffer = *binArea16 >> 8 | *binArea16 << 8;
1143 os.write ( buffer, remainingSize );
1147 return os.write(reinterpret_cast<const char*>(val), len);
1151 std::string Util::ConvertToMD5 (std::string &inPszToCrypt)
1153 char *szChar = new char[ inPszToCrypt.size()+1 ];
1154 char *szHexOutput = new char[ 16 * 2 + 1 ];
1156 strcpy( szChar, inPszToCrypt.c_str() );
1157 // création du code md5
1158 nLen = strlen( szChar );
1160 uint8_t digest[ 16 ];
1161 md5_init ( &state );
1162 md5_append ( &state, (const uint8_t *)szChar, nLen);
1163 md5_finish ( &state, digest );
1164 for ( nDi = 0; nDi < 16; nDi++)
1165 sprintf( szHexOutput + nDi * 2, "%02x", digest[ nDi ] );
1166 szHexOutput[16 * 2]=0;
1168 std::string md5String=szHexOutput;
1169 delete [] szHexOutput;
1173 //-------------------------------------------------------------------------
1176 //-------------------------------------------------------------------------
1179 * \brief Return the IP adress of the machine writting the DICOM image
1181 std::string Util::GetIPAddress()
1183 // This is a rip from
1184 // http://www.codeguru.com/Cpp/I-N/internet/network/article.php/c3445/
1185 #ifndef HOST_NAME_MAX
1186 // SUSv2 guarantees that `Host names are limited to 255 bytes'.
1187 // POSIX 1003.1-2001 guarantees that `Host names (not including the
1188 // terminating NUL) are limited to HOST_NAME_MAX bytes'.
1189 #define HOST_NAME_MAX 255
1190 // In this case we should maybe check the string was not truncated.
1191 // But I don't known how to check that...
1192 #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__)
1193 // with WinSock DLL we need to initialize the WinSock before using gethostname
1194 WORD wVersionRequested = MAKEWORD(1,0);
1196 int err = WSAStartup(wVersionRequested,&WSAData);
1199 // Tell the user that we could not find a usable
1206 #endif //HOST_NAME_MAX
1209 char szHostName[HOST_NAME_MAX+1];
1210 int r = gethostname(szHostName, HOST_NAME_MAX);
1214 // Get host adresses
1215 struct hostent *pHost = gethostbyname(szHostName);
1217 for( int i = 0; pHost!= NULL && pHost->h_addr_list[i]!= NULL; i++ )
1219 for( int j = 0; j<pHost->h_length; j++ )
1221 if ( j > 0 ) str += ".";
1223 str += Util::Format("%u",
1224 (unsigned int)((unsigned char*)pHost->h_addr_list[i])[j]);
1226 // str now contains one local IP address
1228 #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__)
1234 // If an error occur r == -1
1235 // Most of the time it will return 127.0.0.1...
1239 void Util::hfpswap(double *a, double *b)
1249 Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved.
1251 This software is provided 'as-is', without any express or implied
1252 warranty. In no event will the authors be held liable for any damages
1253 arising from the use of this software.
1255 Permission is granted to anyone to use this software for any purpose,
1256 including commercial applications, and to alter it and redistribute it
1257 freely, subject to the following restrictions:
1259 1. The origin of this software must not be misrepresented; you must not
1260 claim that you wrote the original software. If you use this software
1261 in a product, an acknowledgment in the product documentation would be
1262 appreciated but is not required.
1263 2. Altered source versions must be plainly marked as such, and must not be
1264 misrepresented as being the original software.
1265 3. This notice may not be removed or altered from any source distribution.
1272 /* $Id: gdcmUtil.cxx,v 1.188 2007/10/01 09:25:06 jpr Exp $ */
1275 Independent implementation of MD5 (RFC 1321).
1276 This code implements the MD5 Algorithm defined in RFC 1321, whose
1277 text is available at
1279 http://www.ietf.org/rfc/rfc1321.txt
1281 The code is derived from the text of the RFC, including the test suite
1282 (section A.5) but excluding the rest of Appendix A. It does not include
1283 any code or documentation that is identified in the RFC as being
1286 The original and principal author of md5.c is L. Peter Deutsch
1287 <ghost@aladdin.com>. Other authors are noted in the change history
1288 that follows (in reverse chronological order):
1290 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
1291 either statically or dynamically; added missing #include <string.h>
1293 2002-03-11 lpd Corrected argument list for main(), and added int return
1294 type, in test program and T value program.
1295 2002-02-21 lpd Added missing #include <stdio.h> in test program.
1296 2000-07-03 lpd Patched to eliminate warnings about "constant is
1297 unsigned in ANSI C, signed in traditional"; made test program
1299 1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
1300 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
1301 1999-05-03 lpd Original version.
1305 //#include <string.h>
1307 #undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */
1308 #ifdef ARCH_IS_BIG_ENDIAN
1309 # define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
1311 # define BYTE_ORDER 0
1315 #define T_MASK ((uint16_t)~0)
1316 #define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
1317 #define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
1318 #define T3 0x242070db
1319 #define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
1320 #define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
1321 #define T6 0x4787c62a
1322 #define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
1323 #define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
1324 #define T9 0x698098d8
1325 #define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
1326 #define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
1327 #define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
1328 #define T13 0x6b901122
1329 #define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
1330 #define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
1331 #define T16 0x49b40821
1332 #define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
1333 #define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
1334 #define T19 0x265e5a51
1335 #define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
1336 #define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
1337 #define T22 0x02441453
1338 #define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
1339 #define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
1340 #define T25 0x21e1cde6
1341 #define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
1342 #define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
1343 #define T28 0x455a14ed
1344 #define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
1345 #define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
1346 #define T31 0x676f02d9
1347 #define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
1348 #define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
1349 #define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
1350 #define T35 0x6d9d6122
1351 #define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
1352 #define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
1353 #define T38 0x4bdecfa9
1354 #define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
1355 #define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
1356 #define T41 0x289b7ec6
1357 #define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
1358 #define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
1359 #define T44 0x04881d05
1360 #define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
1361 #define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
1362 #define T47 0x1fa27cf8
1363 #define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
1364 #define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
1365 #define T50 0x432aff97
1366 #define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
1367 #define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
1368 #define T53 0x655b59c3
1369 #define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
1370 #define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
1371 #define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
1372 #define T57 0x6fa87e4f
1373 #define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
1374 #define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
1375 #define T60 0x4e0811a1
1376 #define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
1377 #define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
1378 #define T63 0x2ad7d2bb
1379 #define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
1383 Util::md5_process(md5_state_t *pms, const uint8_t *data /*[64]*/)
1386 a = pms->abcd[0], b = pms->abcd[1],
1387 c = pms->abcd[2], d = pms->abcd[3];
1391 /* Define storage only for big-endian CPUs. */
1394 /* Define storage for little-endian or both types of CPUs. */
1401 * Determine dynamically whether this is a big-endian or
1402 * little-endian machine, since we can use a more efficient
1403 * algorithm on the latter.
1405 static const int w = 1;
1407 if (*((const uint8_t *)&w)) /* dynamic little-endian */
1409 #if BYTE_ORDER <= 0 /* little-endian */
1412 * On little-endian machines, we can process properly aligned
1413 * data without copying it.
1415 if (!((data - (const uint8_t *)0) & 3)) {
1416 /* data are properly aligned */
1417 X = (const uint16_t *)data;
1420 memcpy(xbuf, data, 64);
1426 else /* dynamic big-endian */
1428 #if BYTE_ORDER >= 0 /* big-endian */
1431 * On big-endian machines, we must arrange the bytes in the
1434 const uint8_t *xp = data;
1437 # if BYTE_ORDER == 0
1438 X = xbuf; /* (dynamic only) */
1440 # define xbuf /* (static only) */
1442 for (i = 0; i < 16; ++i, xp += 4)
1443 xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
1448 #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
1451 /* Let [abcd k s i] denote the operation
1452 a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
1454 #define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
1455 #define SET(a, b, c, d, k, s, Ti) \
1456 t = a + F(b,c,d) + X[k] + Ti;\
1457 a = ROTATE_LEFT(t, s) + b
1458 /* Do the following 16 operations. */
1459 SET(a, b, c, d, 0, 7, T1);
1460 SET(d, a, b, c, 1, 12, T2);
1461 SET(c, d, a, b, 2, 17, T3);
1462 SET(b, c, d, a, 3, 22, T4);
1463 SET(a, b, c, d, 4, 7, T5);
1464 SET(d, a, b, c, 5, 12, T6);
1465 SET(c, d, a, b, 6, 17, T7);
1466 SET(b, c, d, a, 7, 22, T8);
1467 SET(a, b, c, d, 8, 7, T9);
1468 SET(d, a, b, c, 9, 12, T10);
1469 SET(c, d, a, b, 10, 17, T11);
1470 SET(b, c, d, a, 11, 22, T12);
1471 SET(a, b, c, d, 12, 7, T13);
1472 SET(d, a, b, c, 13, 12, T14);
1473 SET(c, d, a, b, 14, 17, T15);
1474 SET(b, c, d, a, 15, 22, T16);
1477 /* Let [abcd k s i] denote the operation
1478 a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
1480 #define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
1481 #define SET(a, b, c, d, k, s, Ti)\
1482 t = a + G(b,c,d) + X[k] + Ti; \
1483 a = ROTATE_LEFT(t, s) + b
1484 /* Do the following 16 operations. */
1485 SET(a, b, c, d, 1, 5, T17);
1486 SET(d, a, b, c, 6, 9, T18);
1487 SET(c, d, a, b, 11, 14, T19);
1488 SET(b, c, d, a, 0, 20, T20);
1489 SET(a, b, c, d, 5, 5, T21);
1490 SET(d, a, b, c, 10, 9, T22);
1491 SET(c, d, a, b, 15, 14, T23);
1492 SET(b, c, d, a, 4, 20, T24);
1493 SET(a, b, c, d, 9, 5, T25);
1494 SET(d, a, b, c, 14, 9, T26);
1495 SET(c, d, a, b, 3, 14, T27);
1496 SET(b, c, d, a, 8, 20, T28);
1497 SET(a, b, c, d, 13, 5, T29);
1498 SET(d, a, b, c, 2, 9, T30);
1499 SET(c, d, a, b, 7, 14, T31);
1500 SET(b, c, d, a, 12, 20, T32);
1503 /* Let [abcd k s t] denote the operation
1504 a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
1505 #define H(x, y, z) ((x) ^ (y) ^ (z))
1506 #define SET(a, b, c, d, k, s, Ti)\
1507 t = a + H(b,c,d) + X[k] + Ti; \
1508 a = ROTATE_LEFT(t, s) + b
1510 /* Do the following 16 operations. */
1511 SET(a, b, c, d, 5, 4, T33);
1512 SET(d, a, b, c, 8, 11, T34);
1513 SET(c, d, a, b, 11, 16, T35);
1514 SET(b, c, d, a, 14, 23, T36);
1515 SET(a, b, c, d, 1, 4, T37);
1516 SET(d, a, b, c, 4, 11, T38);
1517 SET(c, d, a, b, 7, 16, T39);
1518 SET(b, c, d, a, 10, 23, T40);
1519 SET(a, b, c, d, 13, 4, T41);
1520 SET(d, a, b, c, 0, 11, T42);
1521 SET(c, d, a, b, 3, 16, T43);
1522 SET(b, c, d, a, 6, 23, T44);
1523 SET(a, b, c, d, 9, 4, T45);
1524 SET(d, a, b, c, 12, 11, T46);
1525 SET(c, d, a, b, 15, 16, T47);
1526 SET(b, c, d, a, 2, 23, T48);
1529 /* Let [abcd k s t] denote the operation
1530 a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
1531 #define I(x, y, z) ((y) ^ ((x) | ~(z)))
1532 #define SET(a, b, c, d, k, s, Ti)\
1533 t = a + I(b,c,d) + X[k] + Ti; \
1534 a = ROTATE_LEFT(t, s) + b
1536 /* Do the following 16 operations. */
1537 SET(a, b, c, d, 0, 6, T49);
1538 SET(d, a, b, c, 7, 10, T50);
1539 SET(c, d, a, b, 14, 15, T51);
1540 SET(b, c, d, a, 5, 21, T52);
1541 SET(a, b, c, d, 12, 6, T53);
1542 SET(d, a, b, c, 3, 10, T54);
1543 SET(c, d, a, b, 10, 15, T55);
1544 SET(b, c, d, a, 1, 21, T56);
1545 SET(a, b, c, d, 8, 6, T57);
1546 SET(d, a, b, c, 15, 10, T58);
1547 SET(c, d, a, b, 6, 15, T59);
1548 SET(b, c, d, a, 13, 21, T60);
1549 SET(a, b, c, d, 4, 6, T61);
1550 SET(d, a, b, c, 11, 10, T62);
1551 SET(c, d, a, b, 2, 15, T63);
1552 SET(b, c, d, a, 9, 21, T64);
1555 /* Then perform the following additions. (That is increment each
1556 of the four registers by the value it had before this block
1564 Util::md5_init(md5_state_t *pms)
1566 pms->count[0] = pms->count[1] = 0;
1567 pms->abcd[0] = 0x67452301;
1568 pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
1569 pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
1570 pms->abcd[3] = 0x10325476;
1575 Util::md5_append(md5_state_t *pms, const uint8_t *data, int nbytes)
1577 const uint8_t *p = data;
1579 int offset = (pms->count[0] >> 3) & 63;
1580 uint16_t nbits = (uint16_t)(nbytes << 3);
1583 /* Update the message length. */
1584 pms->count[1] += nbytes >> 29;
1585 pms->count[0] += nbits;
1586 if (pms->count[0] < nbits)
1588 /* Process an initial partial block. */
1590 int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
1591 memcpy(pms->buf + offset, p, copy);
1592 if (offset + copy < 64)
1596 md5_process(pms, pms->buf);
1598 /* Process full blocks. */
1599 for (; left >= 64; p += 64, left -= 64)
1600 md5_process(pms, p);
1601 /* Process a final partial block. */
1603 memcpy(pms->buf, p, left);
1606 Util::md5_finish(md5_state_t *pms, uint8_t digest[16])
1608 static const uint8_t pad[64] = {
1609 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1610 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1611 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1612 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
1617 /* Save the length before padding. */
1618 for (i = 0; i < 8; ++i)
1619 data[i] = (uint8_t)(pms->count[i >> 2] >> ((i & 3) << 3));
1620 /* Pad to 56 bytes mod 64. */
1621 md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
1622 /* Append the length. */
1623 md5_append(pms, data, 8);
1624 for (i = 0; i < 16; ++i)
1625 digest[i] = (uint8_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
1628 //-------------------------------------------------------------------------
1629 } // end namespace gdcm