1 /*=========================================================================
4 Module: $RCSfile: gdcmUtil.cxx,v $
6 Date: $Date: 2006/05/31 16:09:29 $
7 Version: $Revision: 1.184 $
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>
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]) )
243 if (!isprint((unsigned char)s[str.size()-1]) )
245 if (s[str.size()-1] == 0 )
247 str[str.size()-1] = ' ';
256 * \brief Weed out a string from the non-printable characters (in order
257 * to avoid corrupting the terminal of invocation when printing)
258 * @param s area to process (uint8_t is just for prototyping. feel free to cast)
259 * @param l area length to check
261 std::string Util::CreateCleanString(uint8_t *s, int l)
265 for( int i=0; i<l; i++)
267 if (!isprint((unsigned char)s[i]) )
273 str = str + (char )s[i];
280 * \brief Add a SEPARATOR to the end of the name if necessary
281 * @param pathname file/directory name to normalize
283 std::string Util::NormalizePath(std::string const &pathname)
286 const char SEPARATOR_X = '/';
287 const char SEPARATOR_WIN = '\\';
289 const std::string SEPARATOR = "\\";
291 const std::string SEPARATOR = "/";
294 std::string name = pathname;
295 int size = name.size();
297 // if ( name[size-1] != SEPARATOR_X && name[size-1] != SEPARATOR_WIN )
298 if ( name[size-1] != GDCM_FILESEPARATOR )
300 name += GDCM_FILESEPARATOR;
306 * \brief Get the (directory) path from a full path file name
307 * @param fullName file/directory name to extract Path from
309 std::string Util::GetPath(std::string const &fullName)
311 std::string res = fullName;
314 int pos1 = res.rfind("/");
315 int pos2 = res.rfind("\\");
325 int pos = res.rfind(GDCM_FILESEPARATOR);
331 * \brief Get the (last) name of a full path file name
332 * @param fullName file/directory name to extract end name from
334 std::string Util::GetName(std::string const &fullName)
336 std::string filename = fullName;
338 std::string::size_type slash_pos = filename.rfind("/");
339 std::string::size_type backslash_pos = filename.rfind("\\");
340 // At least with my gcc4.0.1, unfound char results in pos =4294967295 ...
341 //slash_pos = slash_pos > backslash_pos ? slash_pos : backslash_pos;
342 slash_pos = slash_pos < backslash_pos ? slash_pos : backslash_pos;
344 std::string::size_type slash_pos = filename.rfind(GDCM_FILESEPARATOR);
345 if (slash_pos != std::string::npos )
347 return filename.substr(slash_pos + 1);
356 * \brief Get the current date of the system in a dicom string
358 std::string Util::GetCurrentDate()
363 strftime(tmp,512,"%Y%m%d", localtime(&tloc) );
368 * \brief Get the current time of the system in a dicom string
370 std::string Util::GetCurrentTime()
375 strftime(tmp,512,"%H%M%S", localtime(&tloc) );
380 * \brief Get both the date and time at the same time to avoid problem
381 * around midnight where the two calls could be before and after midnight
383 std::string Util::GetCurrentDateTime()
389 // We need implementation specific functions to obtain millisecond precision
390 #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__)
394 milliseconds = tb.millitm;
397 gettimeofday (&tv, NULL);
399 // Compute milliseconds from microseconds.
400 milliseconds = tv.tv_usec / 1000;
402 // Obtain the time of day, and convert it to a tm struct.
403 struct tm *ptm = localtime (&timep);
404 // Format the date and time, down to a single second.
405 strftime (tmp, sizeof (tmp), "%Y%m%d%H%M%S", ptm);
408 // Don't use Util::Format to accelerate execution of code
410 sprintf(tmpAll,"%s%03ld",tmp,milliseconds);
415 unsigned int Util::GetCurrentThreadID()
417 // FIXME the implementation is far from complete
418 #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__)
419 return (unsigned int)GetCurrentThreadId();
423 // Doesn't work on fedora, but is in the man page...
424 //return (unsigned int)gettid();
427 return (unsigned int)thr_self();
429 //default implementation
436 unsigned int Util::GetCurrentProcessID()
438 #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__)
439 // NOTE: There is also a _getpid()...
440 return (unsigned int)GetCurrentProcessId();
442 // get process identification, POSIX
443 return (unsigned int)getpid();
448 * \brief tells us whether the processor we are working with is BigEndian or not
450 bool Util::IsCurrentProcessorBigEndian()
452 #if defined(GDCM_WORDS_BIGENDIAN)
460 * \brief Create a /DICOM/ string:
461 * It should a of even length (no odd length ever)
462 * It can contain as many (if you are reading this from your
463 * editor the following character is backslash followed by zero
464 * that needed to be escaped with an extra backslash for doxygen) \\0
467 std::string Util::DicomString(const char *s, size_t l)
469 std::string r(s, s+l);
470 gdcmAssertMacro( !(r.size() % 2) ); // == basically 'l' is even
475 * \brief Create a /DICOM/ string:
476 * It should a of even length (no odd length ever)
477 * It can contain as many (if you are reading this from your
478 * editor the following character is backslash followed by zero
479 * that needed to be escaped with an extra backslash for doxygen) \\0
481 * This function is similar to DicomString(const char*),
482 * except it doesn't take a length.
483 * It only pad with a null character if length is odd
485 std::string Util::DicomString(const char *s)
487 size_t l = strlen(s);
492 std::string r(s, s+l);
493 gdcmAssertMacro( !(r.size() % 2) );
498 * \brief Safely check the equality of two Dicom String:
499 * - Both strings should be of even length
500 * - We allow padding of even length string by either
501 * a null character of a space
503 bool Util::DicomStringEqual(const std::string &s1, const char *s2)
505 // s2 is the string from the DICOM reference e.g. : 'MONOCHROME1'
506 std::string s1_even = s1; //Never change input parameter
507 std::string s2_even = DicomString( s2 );
508 if ( s1_even[s1_even.size()-1] == ' ' )
510 s1_even[s1_even.size()-1] = '\0'; //replace space character by null
512 return s1_even == s2_even;
516 * \brief Safely compare two Dicom String:
517 * - Both strings should be of even length
518 * - We allow padding of even length string by either
519 * a null character of a space
521 bool Util::CompareDicomString(const std::string &s1, const char *s2, int op)
523 // s2 is the string from the DICOM reference e.g. : 'MONOCHROME1'
524 std::string s1_even = s1; //Never change input parameter
525 std::string s2_even = DicomString( s2 );
526 if ( s1_even[s1_even.size()-1] == ' ' )
528 s1_even[s1_even.size()-1] = '\0'; //replace space character by null
533 return s1_even == s2_even;
534 case GDCM_DIFFERENT :
535 return s1_even != s2_even;
537 return s1_even > s2_even;
538 case GDCM_GREATEROREQUAL :
539 return s1_even >= s2_even;
541 return s1_even < s2_even;
542 case GDCM_LESSOREQUAL :
543 return s1_even <= s2_even;
545 gdcmDebugMacro(" Wrong operator : " << op);
551 typedef BOOL(WINAPI * pSnmpExtensionInit) (
552 IN DWORD dwTimeZeroReference,
553 OUT HANDLE * hPollForTrapEvent,
554 OUT AsnObjectIdentifier * supportedView);
556 typedef BOOL(WINAPI * pSnmpExtensionTrap) (
557 OUT AsnObjectIdentifier * enterprise,
558 OUT AsnInteger * genericTrap,
559 OUT AsnInteger * specificTrap,
560 OUT AsnTimeticks * timeStamp,
561 OUT RFC1157VarBindList * variableBindings);
563 typedef BOOL(WINAPI * pSnmpExtensionQuery) (
565 IN OUT RFC1157VarBindList * variableBindings,
566 OUT AsnInteger * errorStatus,
567 OUT AsnInteger * errorIndex);
569 typedef BOOL(WINAPI * pSnmpExtensionInitEx) (
570 OUT AsnObjectIdentifier * supportedView);
574 static int SGIGetMacAddress(unsigned char *addr)
576 FILE *f = popen("/etc/nvram eaddr","r");
582 if(fscanf(f,"%02x:%02x:%02x:%02x:%02x:%02x",
583 x,x+1,x+2,x+3,x+4,x+5) != 6)
588 for(unsigned int i = 0; i < 6; i++)
590 addr[i] = static_cast<unsigned char>(x[i]);
596 /// \brief gets current M.A.C adress (for internal use only)
597 int GetMacAddrSys ( unsigned char *addr );
598 int GetMacAddrSys ( unsigned char *addr )
602 if ( (WSAStartup(MAKEWORD(2, 0), &WinsockData)) != 0 )
604 std::cerr << "in Get MAC Adress (internal) : This program requires Winsock 2.x!"
609 HANDLE PollForTrapEvent;
610 AsnObjectIdentifier SupportedView;
611 UINT OID_ifEntryType[] = { 1, 3, 6, 1, 2, 1, 2, 2, 1, 3 };
612 UINT OID_ifEntryNum[] = { 1, 3, 6, 1, 2, 1, 2, 1 };
613 UINT OID_ipMACEntAddr[] = { 1, 3, 6, 1, 2, 1, 2, 2, 1, 6 };
614 AsnObjectIdentifier MIB_ifMACEntAddr = {
615 sizeof(OID_ipMACEntAddr) / sizeof(UINT), OID_ipMACEntAddr };
616 AsnObjectIdentifier MIB_ifEntryType = {
617 sizeof(OID_ifEntryType) / sizeof(UINT), OID_ifEntryType };
618 AsnObjectIdentifier MIB_ifEntryNum = {
619 sizeof(OID_ifEntryNum) / sizeof(UINT), OID_ifEntryNum };
620 RFC1157VarBindList varBindList;
621 RFC1157VarBind varBind[2];
622 AsnInteger errorStatus;
623 AsnInteger errorIndex;
624 AsnObjectIdentifier MIB_NULL = { 0, 0 };
629 // Load the SNMP dll and get the addresses of the functions necessary
630 HINSTANCE m_hInst = LoadLibrary("inetmib1.dll");
631 if (m_hInst < (HINSTANCE) HINSTANCE_ERROR)
635 pSnmpExtensionInit m_Init =
636 (pSnmpExtensionInit) GetProcAddress(m_hInst, "SnmpExtensionInit");
637 pSnmpExtensionQuery m_Query =
638 (pSnmpExtensionQuery) GetProcAddress(m_hInst, "SnmpExtensionQuery");
639 m_Init(GetTickCount(), &PollForTrapEvent, &SupportedView);
641 /* Initialize the variable list to be retrieved by m_Query */
642 varBindList.list = varBind;
643 varBind[0].name = MIB_NULL;
644 varBind[1].name = MIB_NULL;
646 // Copy in the OID to find the number of entries in the
648 varBindList.len = 1; // Only retrieving one item
649 SNMP_oidcpy(&varBind[0].name, &MIB_ifEntryNum);
650 m_Query(ASN_RFC1157_GETNEXTREQUEST, &varBindList, &errorStatus,
652 // printf("# of adapters in this system : %i\n",
653 // varBind[0].value.asnValue.number);
656 // Copy in the OID of ifType, the type of interface
657 SNMP_oidcpy(&varBind[0].name, &MIB_ifEntryType);
659 // Copy in the OID of ifPhysAddress, the address
660 SNMP_oidcpy(&varBind[1].name, &MIB_ifMACEntAddr);
664 // Submit the query. Responses will be loaded into varBindList.
665 // We can expect this call to succeed a # of times corresponding
666 // to the # of adapters reported to be in the system
667 ret = m_Query(ASN_RFC1157_GETNEXTREQUEST, &varBindList, &errorStatus,
675 // Confirm that the proper type has been returned
676 ret = SNMP_oidncmp(&varBind[0].name, &MIB_ifEntryType,
677 MIB_ifEntryType.idLength);
682 dtmp = varBind[0].value.asnValue.number;
684 // Type 6 describes ethernet interfaces
687 // Confirm that we have an address here
688 ret = SNMP_oidncmp(&varBind[1].name, &MIB_ifMACEntAddr,
689 MIB_ifMACEntAddr.idLength);
690 if ( !ret && varBind[1].value.asnValue.address.stream != NULL )
692 if ( (varBind[1].value.asnValue.address.stream[0] == 0x44)
693 && (varBind[1].value.asnValue.address.stream[1] == 0x45)
694 && (varBind[1].value.asnValue.address.stream[2] == 0x53)
695 && (varBind[1].value.asnValue.address.stream[3] == 0x54)
696 && (varBind[1].value.asnValue.address.stream[4] == 0x00) )
698 // Ignore all dial-up networking adapters
699 std::cerr << "in Get MAC Adress (internal) : Interface #"
700 << j << " is a DUN adapter\n";
703 if ( (varBind[1].value.asnValue.address.stream[0] == 0x00)
704 && (varBind[1].value.asnValue.address.stream[1] == 0x00)
705 && (varBind[1].value.asnValue.address.stream[2] == 0x00)
706 && (varBind[1].value.asnValue.address.stream[3] == 0x00)
707 && (varBind[1].value.asnValue.address.stream[4] == 0x00)
708 && (varBind[1].value.asnValue.address.stream[5] == 0x00) )
710 // Ignore NULL addresses returned by other network
712 std::cerr << "in Get MAC Adress (internal) : Interface #"
713 << j << " is a NULL address\n";
716 memcpy( addr, varBind[1].value.asnValue.address.stream, 6);
723 SNMP_FreeVarBind(&varBind[0]);
724 SNMP_FreeVarBind(&varBind[1]);
726 #endif //Win32 version
729 return SGIGetMacAddress(addr);
733 // implementation for POSIX system
734 #if defined(CMAKE_HAVE_NET_IF_ARP_H) && defined(__sun)
735 //The POSIX version is broken anyway on Solaris, plus would require full
737 struct arpreq parpreq;
738 struct sockaddr_in *psa;
739 struct hostent *phost;
740 char hostname[MAXHOSTNAMELEN];
744 if (gethostname(hostname, MAXHOSTNAMELEN) != 0 )
746 perror("in Get MAC Adress (internal) : gethostname");
749 phost = gethostbyname(hostname);
750 paddrs = phost->h_addr_list;
752 sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
755 perror("in Get MAC Adress (internal) : sock");
758 memset(&parpreq, 0, sizeof(struct arpreq));
759 psa = (struct sockaddr_in *) &parpreq.arp_pa;
761 memset(psa, 0, sizeof(struct sockaddr_in));
762 psa->sin_family = AF_INET;
763 memcpy(&psa->sin_addr, *paddrs, sizeof(struct in_addr));
765 status = ioctl(sock, SIOCGARP, &parpreq);
768 perror("in Get MAC Adress (internal) : SIOCGARP");
771 memcpy(addr, parpreq.arp_ha.sa_data, 6);
775 #ifdef CMAKE_HAVE_NET_IF_H
777 struct ifreq ifr, *ifrp;
782 #if defined(AF_LINK) && (!defined(SIOCGIFHWADDR) && !defined(SIOCGENADDR))
783 struct sockaddr_dl *sdlp;
787 // BSD 4.4 defines the size of an ifreq to be
788 // max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len
789 // However, under earlier systems, sa_len isn't present, so the size is
790 // just sizeof(struct ifreq)
791 // We should investigate the use of SIZEOF_ADDR_IFREQ
795 #define max(a,b) ((a) > (b) ? (a) : (b))
797 #define ifreq_size(i) max(sizeof(struct ifreq),\
798 sizeof((i).ifr_name)+(i).ifr_addr.sa_len)
800 #define ifreq_size(i) sizeof(struct ifreq)
801 #endif // HAVE_SA_LEN
803 if ( (sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0 )
807 memset(buf, 0, sizeof(buf));
808 ifc.ifc_len = sizeof(buf);
810 if (ioctl (sd, SIOCGIFCONF, (char *)&ifc) < 0)
816 for (i = 0; i < n; i+= ifreq_size(*ifrp) )
818 ifrp = (struct ifreq *)((char *) ifc.ifc_buf+i);
819 strncpy(ifr.ifr_name, ifrp->ifr_name, IFNAMSIZ);
821 if (ioctl(sd, SIOCGIFHWADDR, &ifr) < 0)
823 a = (unsigned char *) &ifr.ifr_hwaddr.sa_data;
826 // In theory this call should also work on Sun Solaris, but apparently
827 // SIOCGENADDR is not implemented properly thus the call
828 // ioctl(sd, SIOCGENADDR, &ifr) always returns errno=2
829 // (No such file or directory)
830 // Furthermore the DLAPI seems to require full root access
831 if (ioctl(sd, SIOCGENADDR, &ifr) < 0)
833 a = (unsigned char *) ifr.ifr_enaddr;
836 sdlp = (struct sockaddr_dl *) &ifrp->ifr_addr;
837 if ((sdlp->sdl_family != AF_LINK) || (sdlp->sdl_alen != 6))
839 a = (unsigned char *) &sdlp->sdl_data[sdlp->sdl_nlen];
841 perror("in Get MAC Adress (internal) : No way to access hardware");
845 #endif // SIOCGENADDR
846 #endif // SIOCGIFHWADDR
847 if (!a[0] && !a[1] && !a[2] && !a[3] && !a[4] && !a[5]) continue;
858 // Not implemented platforms (or no cable !)
859 perror("in Get MAC Adress (internal) : There was a configuration problem (or no cable !) on your plateform");
866 * \brief Mini function to return the last digit from a number express in base 256
867 * pre condition data contain an array of 6 unsigned char
868 * post condition carry contain the last digit
870 inline int getlastdigit(unsigned char *data)
872 int extended, carry = 0;
875 extended = (carry << 8) + data[i];
876 data[i] = extended / 10;
877 carry = extended % 10;
883 * \brief Encode the mac address on a fixed length string of 15 characters.
884 * we save space this way.
886 std::string Util::GetMACAddress()
888 // This code is the result of a long internet search to find something
889 // as compact as possible (not OS independant). We only have to separate
890 // 3 OS: Win32, SunOS and 'real' POSIX
891 // http://groups-beta.google.com/group/comp.unix.solaris/msg/ad36929d783d63be
892 // http://bdn.borland.com/article/0,1410,26040,00.html
893 unsigned char addr[6];
895 int stat = GetMacAddrSys(addr);
898 // We need to convert a 6 digit number from base 256 to base 10, using integer
899 // would requires a 48bits one. To avoid this we have to reimplement the div + modulo
906 res = getlastdigit(addr);
907 sres.insert(sres.begin(), '0' + res);
908 zero = (addr[0] == 0) && (addr[1] == 0) && (addr[2] == 0)
909 && (addr[3] == 0) && (addr[4] == 0) && (addr[5] == 0);
916 gdcmStaticWarningMacro("Problem in finding the MAC Address");
922 * \brief Creates a new UID. As stipulated in the DICOM ref
923 * each time a DICOM image is created it should have
924 * a unique identifier (URI)
925 * @param root is the DICOM prefix assigned by IOS group
927 std::string Util::CreateUniqueUID(const std::string &root)
933 // gdcm UID prefix, as supplied by http://www.medicalconnections.co.uk
941 // A root was specified use it to forge our new UID:
943 //append += Util::GetMACAddress(); // to save CPU time
944 append += Util::GDCM_MAC_ADRESS;
946 append += Util::GetCurrentDateTime();
948 //Also add a mini random number just in case:
950 int r = (int) (100.0*rand()/RAND_MAX);
951 // Don't use Util::Format to accelerate the execution
952 sprintf(tmp,"%02d", r);
955 // If append is too long we need to rehash it
956 if ( (prefix + append).size() > 64 )
958 gdcmStaticErrorMacro( "Size of UID is too long." );
959 // we need a hash function to truncate this number
960 // if only md5 was cross plateform
964 return prefix + append;
967 void Util::SetRootUID(const std::string &root)
975 const std::string &Util::GetRootUID()
980 //-------------------------------------------------------------------------
982 * \brief binary_write binary_write
983 * @param os ostream to write to
984 * @param val 16 bits value to write
986 std::ostream &binary_write(std::ostream &os, const uint16_t &val)
988 #if defined(GDCM_WORDS_BIGENDIAN) || defined(GDCM_FORCE_BIGENDIAN_EMULATION)
990 swap = ( val << 8 | val >> 8 );
992 return os.write(reinterpret_cast<const char*>(&swap), 2);
994 return os.write(reinterpret_cast<const char*>(&val), 2);
995 #endif //GDCM_WORDS_BIGENDIAN
999 * \brief binary_write binary_write
1000 * @param os ostream to write to
1001 * @param val 32 bits value to write
1003 std::ostream &binary_write(std::ostream &os, const uint32_t &val)
1005 #if defined(GDCM_WORDS_BIGENDIAN) || defined(GDCM_FORCE_BIGENDIAN_EMULATION)
1007 swap = ( (val<<24) | ((val<<8) & 0x00ff0000) |
1008 ((val>>8) & 0x0000ff00) | (val>>24) );
1009 return os.write(reinterpret_cast<const char*>(&swap), 4);
1011 return os.write(reinterpret_cast<const char*>(&val), 4);
1012 #endif //GDCM_WORDS_BIGENDIAN
1016 * \brief binary_write binary_write
1017 * @param os ostream to write to
1018 * @param val double (64 bits) value to write
1020 std::ostream &binary_write(std::ostream &os, const double &val)
1022 #if defined(GDCM_WORDS_BIGENDIAN) || defined(GDCM_FORCE_BIGENDIAN_EMULATION)
1025 char *beg = (char *)&swap;
1026 char *end = beg + 7;
1028 for (unsigned int i = 0; i<7; i++)
1036 return os.write(reinterpret_cast<const char*>(&swap), 8);
1038 return os.write(reinterpret_cast<const char*>(&val), 8);
1039 #endif //GDCM_WORDS_BIGENDIAN
1043 * \brief binary_write binary_write
1044 * @param os ostream to write to
1045 * @param val 8 bits characters aray to write
1047 std::ostream &binary_write(std::ostream &os, const char *val)
1049 return os.write(val, strlen(val));
1053 * \brief binary_write binary_write
1054 * @param os ostream to write to
1055 * @param val std::string value to write
1057 std::ostream &binary_write(std::ostream &os, std::string const &val)
1059 return os.write(val.c_str(), val.size());
1063 * \brief binary_write binary_write
1064 * @param os ostream to write to
1065 * @param val 8 bits 'characters' aray to write
1066 * @param len length of the 'value' to be written
1068 std::ostream &binary_write(std::ostream &os, const uint8_t *val, size_t len)
1070 // We are writting sizeof(char) thus no need to swap bytes
1071 return os.write(reinterpret_cast<const char*>(val), len);
1075 * \brief binary_write binary_write
1076 * @param os ostream to write to
1077 * @param val 16 bits words aray to write
1078 * @param len length (in bytes) of the 'value' to be written
1080 std::ostream &binary_write(std::ostream &os, const uint16_t *val, size_t len)
1082 // This is tricky since we are writting two bytes buffer.
1083 // Be carefull with little endian vs big endian.
1084 // Also this other trick is to allocate a small (efficient) buffer that store
1085 // intermediate result before writting it.
1086 #if defined(GDCM_WORDS_BIGENDIAN) || defined(GDCM_FORCE_BIGENDIAN_EMULATION)
1087 const int BUFFER_SIZE = 4096;
1088 static char buffer[BUFFER_SIZE];
1089 uint16_t *binArea16 = (uint16_t*)val; //for the const
1091 // how many BUFFER_SIZE long pieces in binArea ?
1092 int nbPieces = len/BUFFER_SIZE; //(16 bits = 2 Bytes)
1093 int remainingSize = len%BUFFER_SIZE;
1095 for (int j=0;j<nbPieces;j++)
1097 uint16_t *pbuffer = (uint16_t*)buffer; //reinitialize pbuffer
1098 for (int i = 0; i < BUFFER_SIZE/2; i++)
1100 *pbuffer = *binArea16 >> 8 | *binArea16 << 8;
1104 os.write ( buffer, BUFFER_SIZE );
1106 if ( remainingSize > 0)
1108 uint16_t *pbuffer = (uint16_t*)buffer; //reinitialize pbuffer
1109 for (int i = 0; i < remainingSize/2; i++)
1111 *pbuffer = *binArea16 >> 8 | *binArea16 << 8;
1115 os.write ( buffer, remainingSize );
1119 return os.write(reinterpret_cast<const char*>(val), len);
1123 std::string Util::ConvertToMD5 (std::string &inPszToCrypt)
1125 char *szChar = new char[ inPszToCrypt.size()+1 ];
1126 char *szHexOutput = new char[ 16 * 2 + 1 ];
1128 strcpy( szChar, inPszToCrypt.c_str() );
1129 // création du code md5
1130 nLen = strlen( szChar );
1132 uint8_t digest[ 16 ];
1133 md5_init ( &state );
1134 md5_append ( &state, (const uint8_t *)szChar, nLen);
1135 md5_finish ( &state, digest );
1136 for ( nDi = 0; nDi < 16; nDi++)
1137 sprintf( szHexOutput + nDi * 2, "%02x", digest[ nDi ] );
1138 szHexOutput[16 * 2]=0;
1140 std::string md5String=szHexOutput;
1141 delete [] szHexOutput;
1145 //-------------------------------------------------------------------------
1148 //-------------------------------------------------------------------------
1151 * \brief Return the IP adress of the machine writting the DICOM image
1153 std::string Util::GetIPAddress()
1155 // This is a rip from
1156 // http://www.codeguru.com/Cpp/I-N/internet/network/article.php/c3445/
1157 #ifndef HOST_NAME_MAX
1158 // SUSv2 guarantees that `Host names are limited to 255 bytes'.
1159 // POSIX 1003.1-2001 guarantees that `Host names (not including the
1160 // terminating NUL) are limited to HOST_NAME_MAX bytes'.
1161 #define HOST_NAME_MAX 255
1162 // In this case we should maybe check the string was not truncated.
1163 // But I don't known how to check that...
1164 #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__)
1165 // with WinSock DLL we need to initialize the WinSock before using gethostname
1166 WORD wVersionRequested = MAKEWORD(1,0);
1168 int err = WSAStartup(wVersionRequested,&WSAData);
1171 // Tell the user that we could not find a usable
1178 #endif //HOST_NAME_MAX
1181 char szHostName[HOST_NAME_MAX+1];
1182 int r = gethostname(szHostName, HOST_NAME_MAX);
1186 // Get host adresses
1187 struct hostent *pHost = gethostbyname(szHostName);
1189 for( int i = 0; pHost!= NULL && pHost->h_addr_list[i]!= NULL; i++ )
1191 for( int j = 0; j<pHost->h_length; j++ )
1193 if ( j > 0 ) str += ".";
1195 str += Util::Format("%u",
1196 (unsigned int)((unsigned char*)pHost->h_addr_list[i])[j]);
1198 // str now contains one local IP address
1200 #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__)
1206 // If an error occur r == -1
1207 // Most of the time it will return 127.0.0.1...
1211 void Util::hfpswap(double *a, double *b)
1221 Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved.
1223 This software is provided 'as-is', without any express or implied
1224 warranty. In no event will the authors be held liable for any damages
1225 arising from the use of this software.
1227 Permission is granted to anyone to use this software for any purpose,
1228 including commercial applications, and to alter it and redistribute it
1229 freely, subject to the following restrictions:
1231 1. The origin of this software must not be misrepresented; you must not
1232 claim that you wrote the original software. If you use this software
1233 in a product, an acknowledgment in the product documentation would be
1234 appreciated but is not required.
1235 2. Altered source versions must be plainly marked as such, and must not be
1236 misrepresented as being the original software.
1237 3. This notice may not be removed or altered from any source distribution.
1244 /* $Id: gdcmUtil.cxx,v 1.184 2006/05/31 16:09:29 jpr Exp $ */
1247 Independent implementation of MD5 (RFC 1321).
1248 This code implements the MD5 Algorithm defined in RFC 1321, whose
1249 text is available at
1251 http://www.ietf.org/rfc/rfc1321.txt
1253 The code is derived from the text of the RFC, including the test suite
1254 (section A.5) but excluding the rest of Appendix A. It does not include
1255 any code or documentation that is identified in the RFC as being
1258 The original and principal author of md5.c is L. Peter Deutsch
1259 <ghost@aladdin.com>. Other authors are noted in the change history
1260 that follows (in reverse chronological order):
1262 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
1263 either statically or dynamically; added missing #include <string.h>
1265 2002-03-11 lpd Corrected argument list for main(), and added int return
1266 type, in test program and T value program.
1267 2002-02-21 lpd Added missing #include <stdio.h> in test program.
1268 2000-07-03 lpd Patched to eliminate warnings about "constant is
1269 unsigned in ANSI C, signed in traditional"; made test program
1271 1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
1272 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
1273 1999-05-03 lpd Original version.
1277 //#include <string.h>
1279 #undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */
1280 #ifdef ARCH_IS_BIG_ENDIAN
1281 # define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
1283 # define BYTE_ORDER 0
1287 #define T_MASK ((uint16_t)~0)
1288 #define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
1289 #define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
1290 #define T3 0x242070db
1291 #define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
1292 #define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
1293 #define T6 0x4787c62a
1294 #define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
1295 #define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
1296 #define T9 0x698098d8
1297 #define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
1298 #define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
1299 #define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
1300 #define T13 0x6b901122
1301 #define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
1302 #define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
1303 #define T16 0x49b40821
1304 #define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
1305 #define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
1306 #define T19 0x265e5a51
1307 #define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
1308 #define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
1309 #define T22 0x02441453
1310 #define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
1311 #define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
1312 #define T25 0x21e1cde6
1313 #define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
1314 #define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
1315 #define T28 0x455a14ed
1316 #define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
1317 #define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
1318 #define T31 0x676f02d9
1319 #define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
1320 #define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
1321 #define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
1322 #define T35 0x6d9d6122
1323 #define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
1324 #define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
1325 #define T38 0x4bdecfa9
1326 #define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
1327 #define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
1328 #define T41 0x289b7ec6
1329 #define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
1330 #define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
1331 #define T44 0x04881d05
1332 #define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
1333 #define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
1334 #define T47 0x1fa27cf8
1335 #define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
1336 #define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
1337 #define T50 0x432aff97
1338 #define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
1339 #define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
1340 #define T53 0x655b59c3
1341 #define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
1342 #define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
1343 #define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
1344 #define T57 0x6fa87e4f
1345 #define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
1346 #define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
1347 #define T60 0x4e0811a1
1348 #define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
1349 #define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
1350 #define T63 0x2ad7d2bb
1351 #define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
1355 Util::md5_process(md5_state_t *pms, const uint8_t *data /*[64]*/)
1358 a = pms->abcd[0], b = pms->abcd[1],
1359 c = pms->abcd[2], d = pms->abcd[3];
1363 /* Define storage only for big-endian CPUs. */
1366 /* Define storage for little-endian or both types of CPUs. */
1373 * Determine dynamically whether this is a big-endian or
1374 * little-endian machine, since we can use a more efficient
1375 * algorithm on the latter.
1377 static const int w = 1;
1379 if (*((const uint8_t *)&w)) /* dynamic little-endian */
1381 #if BYTE_ORDER <= 0 /* little-endian */
1384 * On little-endian machines, we can process properly aligned
1385 * data without copying it.
1387 if (!((data - (const uint8_t *)0) & 3)) {
1388 /* data are properly aligned */
1389 X = (const uint16_t *)data;
1392 memcpy(xbuf, data, 64);
1398 else /* dynamic big-endian */
1400 #if BYTE_ORDER >= 0 /* big-endian */
1403 * On big-endian machines, we must arrange the bytes in the
1406 const uint8_t *xp = data;
1409 # if BYTE_ORDER == 0
1410 X = xbuf; /* (dynamic only) */
1412 # define xbuf /* (static only) */
1414 for (i = 0; i < 16; ++i, xp += 4)
1415 xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
1420 #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
1423 /* Let [abcd k s i] denote the operation
1424 a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
1426 #define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
1427 #define SET(a, b, c, d, k, s, Ti) \
1428 t = a + F(b,c,d) + X[k] + Ti;\
1429 a = ROTATE_LEFT(t, s) + b
1430 /* Do the following 16 operations. */
1431 SET(a, b, c, d, 0, 7, T1);
1432 SET(d, a, b, c, 1, 12, T2);
1433 SET(c, d, a, b, 2, 17, T3);
1434 SET(b, c, d, a, 3, 22, T4);
1435 SET(a, b, c, d, 4, 7, T5);
1436 SET(d, a, b, c, 5, 12, T6);
1437 SET(c, d, a, b, 6, 17, T7);
1438 SET(b, c, d, a, 7, 22, T8);
1439 SET(a, b, c, d, 8, 7, T9);
1440 SET(d, a, b, c, 9, 12, T10);
1441 SET(c, d, a, b, 10, 17, T11);
1442 SET(b, c, d, a, 11, 22, T12);
1443 SET(a, b, c, d, 12, 7, T13);
1444 SET(d, a, b, c, 13, 12, T14);
1445 SET(c, d, a, b, 14, 17, T15);
1446 SET(b, c, d, a, 15, 22, T16);
1449 /* Let [abcd k s i] denote the operation
1450 a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
1452 #define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
1453 #define SET(a, b, c, d, k, s, Ti)\
1454 t = a + G(b,c,d) + X[k] + Ti; \
1455 a = ROTATE_LEFT(t, s) + b
1456 /* Do the following 16 operations. */
1457 SET(a, b, c, d, 1, 5, T17);
1458 SET(d, a, b, c, 6, 9, T18);
1459 SET(c, d, a, b, 11, 14, T19);
1460 SET(b, c, d, a, 0, 20, T20);
1461 SET(a, b, c, d, 5, 5, T21);
1462 SET(d, a, b, c, 10, 9, T22);
1463 SET(c, d, a, b, 15, 14, T23);
1464 SET(b, c, d, a, 4, 20, T24);
1465 SET(a, b, c, d, 9, 5, T25);
1466 SET(d, a, b, c, 14, 9, T26);
1467 SET(c, d, a, b, 3, 14, T27);
1468 SET(b, c, d, a, 8, 20, T28);
1469 SET(a, b, c, d, 13, 5, T29);
1470 SET(d, a, b, c, 2, 9, T30);
1471 SET(c, d, a, b, 7, 14, T31);
1472 SET(b, c, d, a, 12, 20, T32);
1475 /* Let [abcd k s t] denote the operation
1476 a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
1477 #define H(x, y, z) ((x) ^ (y) ^ (z))
1478 #define SET(a, b, c, d, k, s, Ti)\
1479 t = a + H(b,c,d) + X[k] + Ti; \
1480 a = ROTATE_LEFT(t, s) + b
1482 /* Do the following 16 operations. */
1483 SET(a, b, c, d, 5, 4, T33);
1484 SET(d, a, b, c, 8, 11, T34);
1485 SET(c, d, a, b, 11, 16, T35);
1486 SET(b, c, d, a, 14, 23, T36);
1487 SET(a, b, c, d, 1, 4, T37);
1488 SET(d, a, b, c, 4, 11, T38);
1489 SET(c, d, a, b, 7, 16, T39);
1490 SET(b, c, d, a, 10, 23, T40);
1491 SET(a, b, c, d, 13, 4, T41);
1492 SET(d, a, b, c, 0, 11, T42);
1493 SET(c, d, a, b, 3, 16, T43);
1494 SET(b, c, d, a, 6, 23, T44);
1495 SET(a, b, c, d, 9, 4, T45);
1496 SET(d, a, b, c, 12, 11, T46);
1497 SET(c, d, a, b, 15, 16, T47);
1498 SET(b, c, d, a, 2, 23, T48);
1501 /* Let [abcd k s t] denote the operation
1502 a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
1503 #define I(x, y, z) ((y) ^ ((x) | ~(z)))
1504 #define SET(a, b, c, d, k, s, Ti)\
1505 t = a + I(b,c,d) + X[k] + Ti; \
1506 a = ROTATE_LEFT(t, s) + b
1508 /* Do the following 16 operations. */
1509 SET(a, b, c, d, 0, 6, T49);
1510 SET(d, a, b, c, 7, 10, T50);
1511 SET(c, d, a, b, 14, 15, T51);
1512 SET(b, c, d, a, 5, 21, T52);
1513 SET(a, b, c, d, 12, 6, T53);
1514 SET(d, a, b, c, 3, 10, T54);
1515 SET(c, d, a, b, 10, 15, T55);
1516 SET(b, c, d, a, 1, 21, T56);
1517 SET(a, b, c, d, 8, 6, T57);
1518 SET(d, a, b, c, 15, 10, T58);
1519 SET(c, d, a, b, 6, 15, T59);
1520 SET(b, c, d, a, 13, 21, T60);
1521 SET(a, b, c, d, 4, 6, T61);
1522 SET(d, a, b, c, 11, 10, T62);
1523 SET(c, d, a, b, 2, 15, T63);
1524 SET(b, c, d, a, 9, 21, T64);
1527 /* Then perform the following additions. (That is increment each
1528 of the four registers by the value it had before this block
1536 Util::md5_init(md5_state_t *pms)
1538 pms->count[0] = pms->count[1] = 0;
1539 pms->abcd[0] = 0x67452301;
1540 pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
1541 pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
1542 pms->abcd[3] = 0x10325476;
1547 Util::md5_append(md5_state_t *pms, const uint8_t *data, int nbytes)
1549 const uint8_t *p = data;
1551 int offset = (pms->count[0] >> 3) & 63;
1552 uint16_t nbits = (uint16_t)(nbytes << 3);
1555 /* Update the message length. */
1556 pms->count[1] += nbytes >> 29;
1557 pms->count[0] += nbits;
1558 if (pms->count[0] < nbits)
1560 /* Process an initial partial block. */
1562 int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
1563 memcpy(pms->buf + offset, p, copy);
1564 if (offset + copy < 64)
1568 md5_process(pms, pms->buf);
1570 /* Process full blocks. */
1571 for (; left >= 64; p += 64, left -= 64)
1572 md5_process(pms, p);
1573 /* Process a final partial block. */
1575 memcpy(pms->buf, p, left);
1578 Util::md5_finish(md5_state_t *pms, uint8_t digest[16])
1580 static const uint8_t pad[64] = {
1581 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1582 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1583 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1584 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
1589 /* Save the length before padding. */
1590 for (i = 0; i < 8; ++i)
1591 data[i] = (uint8_t)(pms->count[i >> 2] >> ((i & 3) << 3));
1592 /* Pad to 56 bytes mod 64. */
1593 md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
1594 /* Append the length. */
1595 md5_append(pms, data, 8);
1596 for (i = 0; i < 16; ++i)
1597 digest[i] = (uint8_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
1600 //-------------------------------------------------------------------------
1601 } // end namespace gdcm