]> Creatis software - gdcm.git/blobdiff - src/gdcmUtil.cxx
Track troubles on Big endian processors
[gdcm.git] / src / gdcmUtil.cxx
index b78ddcb3feef2e156593d21706894bdb0bf78241..d351e406d85edccebf9b5d6249dabb08c6b94f28 100644 (file)
@@ -3,8 +3,8 @@
   Program:   gdcm
   Module:    $RCSfile: gdcmUtil.cxx,v $
   Language:  C++
-  Date:      $Date: 2005/07/05 23:50:19 $
-  Version:   $Revision: 1.156 $
+  Date:      $Date: 2005/11/28 15:20:34 $
+  Version:   $Revision: 1.177 $
                                                                                 
   Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
   l'Image). All rights reserved. See Doc/License.txt or
@@ -18,7 +18,9 @@
 
 #include "gdcmUtil.h"
 #include "gdcmDebug.h"
+
 #include <iostream>
+#include <stdarg.h> // for va_list
 
 // For GetCurrentDate, GetCurrentTime
 #include <time.h>
@@ -95,7 +97,13 @@ namespace gdcm
 //-------------------------------------------------------------------------
 const std::string Util::GDCM_UID = "1.2.826.0.1.3680043.2.1143";
 std::string Util::RootUID        = GDCM_UID;
-const uint16_t Util::FMIV = 0x0001;
+/*
+ * File Meta Information Version (0002,0001) shall contain a two byte OB 
+ * value consisting of a 0x00 byte, followed by 0x01 byte, and not the 
+ * value 0x0001 encoded as a little endian 16 bit short value, 
+ * which would be the other way around...
+ */
+const uint16_t Util::FMIV = 0x0100;
 uint8_t *Util::FileMetaInformationVersion = (uint8_t *)&FMIV;
 std::string Util::GDCM_MAC_ADRESS = GetMACAddress();
 
@@ -104,7 +112,7 @@ std::string Util::GDCM_MAC_ADRESS = GetMACAddress();
 /**
  * \brief Provide a better 'c++' approach for sprintf
  * For example c code is:
- * char result[200]; // hope 200 is enough
+ * char result[2048]; // hope 2048 is enough
  * sprintf(result, "%04x|%04x", group , elem);
  *
  * c++ code is 
@@ -120,7 +128,7 @@ std::string Util::GDCM_MAC_ADRESS = GetMACAddress();
  */
 std::string Util::Format(const char *format, ...)
 {
-   char buffer[2048];
+   char buffer[2048]; // hope 2048 is enough
    va_list args;
    va_start(args, format);
    vsprintf(buffer, format, args);  //might be a security flaw
@@ -179,10 +187,45 @@ int Util::CountSubstring (const std::string &str,
    return count;
 }
 
+/**
+ * \brief  Checks whether a 'string' is printable or not (in order
+ *         to avoid corrupting the terminal of invocation when printing)
+ * @param s string to check
+ */
+bool Util::IsCleanString(std::string const &s)
+{
+   //std::cout<< std::endl << s << std::endl;
+   for(unsigned int i=0; i<s.size(); i++)
+   {
+      if (!isprint((unsigned char)s[i]) )
+      {
+         return false;
+      }
+   }
+   return true;   
+}
+
+/**
+ * \brief  Checks whether an 'area' is printable or not (in order
+ *         to avoid corrupting the terminal of invocation when printing)
+ * @param s area to check (uint8_t is just for prototyping. feel free to cast)
+ * @param l area length to check
+ */
+bool Util::IsCleanArea(uint8_t *s, int l)
+{
+   for( int i=0; i<l; i++)
+   {
+      if (!isprint((unsigned char)s[i]) )
+      {
+         return false;
+      }
+   }
+   return true;   
+}
 /**
  * \brief  Weed out a string from the non-printable characters (in order
  *         to avoid corrupting the terminal of invocation when printing)
- * @param s string to remove non printable characters from
+ * @param s string to check (uint8_t is just for prototyping. feel free to cast)
  */
 std::string Util::CreateCleanString(std::string const &s)
 {
@@ -210,6 +253,30 @@ std::string Util::CreateCleanString(std::string const &s)
    return str;
 }
 
+/**
+ * \brief  Weed out a string from the non-printable characters (in order
+ *         to avoid corrupting the terminal of invocation when printing)
+ * @param s area to process (uint8_t is just for prototyping. feel free to cast)
+ * @param l area length to check
+ */
+std::string Util::CreateCleanString(uint8_t *s, int l)
+{
+   std::string str;
+
+   for( int i=0; i<l; i++)
+   {
+      if (!isprint((unsigned char)s[i]) )
+      {
+         str = str + '.';
+      }
+   else
+      {
+         str = str + (char )s[i];
+      }
+   }
+
+   return str;
+}
 /**
  * \brief   Add a SEPARATOR to the end of the name is necessary
  * @param   pathname file/directory name to normalize 
@@ -297,7 +364,7 @@ std::string Util::GetCurrentTime()
 
 /**
  * \brief  Get both the date and time at the same time to avoid problem 
- * around midnight where two call could be before and after midnight
+ * around midnight where the two calls could be before and after midnight
  */
 std::string Util::GetCurrentDateTime()
 {
@@ -364,7 +431,7 @@ unsigned int Util::GetCurrentProcessID()
 }
 
 /**
- * \brief   tells us if the processor we are working with is BigEndian or not
+ * \brief   tells us whether the processor we are working with is BigEndian or not
  */
 bool Util::IsCurrentProcessorBigEndian()
 {
@@ -379,14 +446,14 @@ bool Util::IsCurrentProcessorBigEndian()
  * \brief Create a /DICOM/ string:
  * It should a of even length (no odd length ever)
  * It can contain as many (if you are reading this from your
- * editor the following character is is backslash followed by zero
+ * editor the following character is backslash followed by zero
  * that needed to be escaped with an extra backslash for doxygen) \\0
  * as you want.
  */
 std::string Util::DicomString(const char *s, size_t l)
 {
    std::string r(s, s+l);
-   gdcmAssertMacro( !(r.size() % 2) ); // == basically 'l' is even
+   gdcmStaticAssertMacro( !(r.size() % 2) ); // == basically 'l' is even
    return r;
 }
 
@@ -409,19 +476,19 @@ std::string Util::DicomString(const char *s)
       l++;
    }
    std::string r(s, s+l);
-   gdcmAssertMacro( !(r.size() % 2) );
+   gdcmStaticAssertMacro( !(r.size() % 2) );
    return r;
 }
 
 /**
- * \brief Safely compare two Dicom String:
- *        - Both string should be of even length
+ * \brief Safely check the equality of two Dicom String:
+ *        - Both strings should be of even length
  *        - We allow padding of even length string by either a null 
  *          character of a space
  */
 bool Util::DicomStringEqual(const std::string &s1, const char *s2)
 {
-  // s2 is the string from the DICOM reference: 'MONOCHROME1'
+  // s2 is the string from the DICOM reference e.g. : 'MONOCHROME1'
   std::string s1_even = s1; //Never change input parameter
   std::string s2_even = DicomString( s2 );
   if ( s1_even[s1_even.size()-1] == ' ' )
@@ -431,6 +498,41 @@ bool Util::DicomStringEqual(const std::string &s1, const char *s2)
   return s1_even == s2_even;
 }
 
+/**
+ * \brief Safely compare two Dicom String:
+ *        - Both strings should be of even length
+ *        - We allow padding of even length string by either a null 
+ *          character of a space
+ */
+bool Util::CompareDicomString(const std::string &s1, const char *s2, int op)
+{
+  // s2 is the string from the DICOM reference e.g. : 'MONOCHROME1'
+  std::string s1_even = s1; //Never change input parameter
+  std::string s2_even = DicomString( s2 );
+  if ( s1_even[s1_even.size()-1] == ' ' )
+  {
+    s1_even[s1_even.size()-1] = '\0'; //replace space character by null
+  }
+  switch (op)
+  {
+     case GDCM_EQUAL :
+        return s1_even == s2_even;
+     case GDCM_DIFFERENT :  
+        return s1_even != s2_even;
+     case GDCM_GREATER :  
+        return s1_even >  s2_even;  
+     case GDCM_GREATEROREQUAL :  
+        return s1_even >= s2_even;
+     case GDCM_LESS :
+        return s1_even <  s2_even;
+     case GDCM_LESSOREQUAL :
+        return s1_even <= s2_even;
+     default :
+        gdcmStaticDebugMacro(" Wrong operator : " << op);
+        return false;
+  }
+}
+
 #ifdef _WIN32
    typedef BOOL(WINAPI * pSnmpExtensionInit) (
            IN DWORD dwTimeZeroReference,
@@ -460,9 +562,10 @@ int GetMacAddrSys ( unsigned char *addr )
 {
 #ifdef _WIN32
    WSADATA WinsockData;
-   if ( (WSAStartup(MAKEWORD(2, 0), &WinsockData)) != 0) 
+   if ( (WSAStartup(MAKEWORD(2, 0), &WinsockData)) != 0 
    {
-      std::cerr << "This program requires Winsock 2.x!" << std::endl;
+      std::cerr << "in Get MAC Adress (internal) : This program requires Winsock 2.x!" 
+             << std::endl;
       return -1;
    }
 
@@ -556,7 +659,8 @@ int GetMacAddrSys ( unsigned char *addr )
                  && (varBind[1].value.asnValue.address.stream[4] == 0x00) )
                {
                    // Ignore all dial-up networking adapters
-                   std::cerr << "Interface #" << j << " is a DUN adapter\n";
+                   std::cerr << "in Get MAC Adress (internal) : Interface #" 
+                             << j << " is a DUN adapter\n";
                    continue;
                }
                if ( (varBind[1].value.asnValue.address.stream[0] == 0x00)
@@ -568,7 +672,8 @@ int GetMacAddrSys ( unsigned char *addr )
                {
                   // Ignore NULL addresses returned by other network
                   // interfaces
-                  std::cerr << "Interface #" << j << " is a NULL address\n";
+                  std::cerr << "in Get MAC Adress (internal) :  Interface #" 
+                            << j << " is a NULL address\n";
                   continue;
                }
                memcpy( addr, varBind[1].value.asnValue.address.stream, 6);
@@ -597,7 +702,7 @@ int GetMacAddrSys ( unsigned char *addr )
 
    if (gethostname(hostname,  MAXHOSTNAMELEN) != 0 )
    {
-      perror("gethostname");
+      perror("in Get MAC Adress (internal) : gethostname");
       return -1;
    }
    phost = gethostbyname(hostname);
@@ -606,7 +711,7 @@ int GetMacAddrSys ( unsigned char *addr )
    sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (sock == -1 )
    {
-      perror("sock");
+      perror("in Get MAC Adress (internal) : sock");
       return -1;
    }
    memset(&parpreq, 0, sizeof(struct arpreq));
@@ -619,7 +724,7 @@ int GetMacAddrSys ( unsigned char *addr )
    status = ioctl(sock, SIOCGARP, &parpreq);
    if (status == -1 )
    {
-      perror("SIOCGARP");
+      perror("in Get MAC Adress (internal) : SIOCGARP");
       return -1;
    }
    memcpy(addr, parpreq.arp_ha.sa_data, 6);
@@ -642,7 +747,7 @@ int GetMacAddrSys ( unsigned char *addr )
 // max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len
 // However, under earlier systems, sa_len isn't present, so the size is 
 // just sizeof(struct ifreq)
-// We should investiage the use of SIZEOF_ADDR_IFREQ
+// We should investigate the use of SIZEOF_ADDR_IFREQ
 //
 #ifdef HAVE_SA_LEN
    #ifndef max
@@ -692,7 +797,7 @@ int GetMacAddrSys ( unsigned char *addr )
          continue;
       a = (unsigned char *) &sdlp->sdl_data[sdlp->sdl_nlen];
 #else
-      perror("No way to access hardware");
+      perror("in Get MAC Adress (internal) : No way to access hardware");
       close(sd);
       return -1;
 #endif // AF_LINK
@@ -709,8 +814,8 @@ int GetMacAddrSys ( unsigned char *addr )
    }
    close(sd);
 #endif
-   // Not implemented platforms
-   perror("There was a configuration problem on your plateform");
+   // Not implemented platforms (or no cable !)
+   perror("in Get MAC Adress (internal) : There was a configuration problem (or no cable !) on your plateform");
    memset(addr,0,6);
    return -1;
 #endif //__sun
@@ -734,7 +839,7 @@ inline int getlastdigit(unsigned char *data)
 }
 
 /**
- * \brief Encode the mac address on a fixed lenght string of 15 characters.
+ * \brief Encode the mac address on a fixed length string of 15 characters.
  * we save space this way.
  */
 std::string Util::GetMACAddress()
@@ -767,14 +872,14 @@ std::string Util::GetMACAddress()
    }
    else
    {
-      gdcmWarningMacro("Problem in finding the MAC Address");
+      gdcmStaticWarningMacro("Problem in finding the MAC Address");
       return "";
    }
 }
 
 /**
- * \brief Creates a new UID. As stipulate in the DICOM ref
- *        each time a DICOM image is create it should have 
+ * \brief Creates a new UID. As stipulated in the DICOM ref
+ *        each time a DICOM image is created it should have 
  *        a unique identifier (URI)
  * @param root is the DICOM prefix assigned by IOS group
  */
@@ -798,7 +903,7 @@ std::string Util::CreateUniqueUID(const std::string &root)
    append += Util::GDCM_MAC_ADRESS;
    append += ".";
    append += Util::GetCurrentDateTime();
-
+   append += ".";
    //Also add a mini random number just in case:
    char tmp[10];
    int r = (int) (100.0*rand()/RAND_MAX);
@@ -809,7 +914,7 @@ std::string Util::CreateUniqueUID(const std::string &root)
    // If append is too long we need to rehash it
    if ( (prefix + append).size() > 64 )
    {
-      gdcmErrorMacro( "Size of UID is too long." );
+      gdcmStaticErrorMacro( "Size of UID is too long." );
       // we need a hash function to truncate this number
       // if only md5 was cross plateform
       // MD5(append);
@@ -835,15 +940,13 @@ const std::string &Util::GetRootUID()
 /**
  * \brief binary_write binary_write
  * @param os ostream to write to 
- * @param val val
+ * @param val 16 bits value to write
  */ 
 std::ostream &binary_write(std::ostream &os, const uint16_t &val)
 {
 #if defined(GDCM_WORDS_BIGENDIAN) || defined(GDCM_FORCE_BIGENDIAN_EMULATION)
    uint16_t swap;
-   //swap = ((( val << 8 ) & 0xff00 ) | (( val >> 8 ) & 0x00ff ) );
-   //save CPU time
-   swap = ( val << 8 |  val >> 8  );
+   swap = ( val << 8 | val >> 8 );
 
    return os.write(reinterpret_cast<const char*>(&swap), 2);
 #else
@@ -854,15 +957,12 @@ std::ostream &binary_write(std::ostream &os, const uint16_t &val)
 /**
  * \brief binary_write binary_write
  * @param os ostream to write to
- * @param val val
+ * @param val 32 bits value to write
  */ 
 std::ostream &binary_write(std::ostream &os, const uint32_t &val)
 {
 #if defined(GDCM_WORDS_BIGENDIAN) || defined(GDCM_FORCE_BIGENDIAN_EMULATION)
    uint32_t swap;
-//   swap = ( ((val<<24) & 0xff000000) | ((val<<8)  & 0x00ff0000) | 
-//            ((val>>8)  & 0x0000ff00) | ((val>>24) & 0x000000ff) );
-// save CPU time
    swap = (  (val<<24)               | ((val<<8)  & 0x00ff0000) | 
             ((val>>8)  & 0x0000ff00) |  (val>>24)               );
    return os.write(reinterpret_cast<const char*>(&swap), 4);
@@ -871,10 +971,39 @@ std::ostream &binary_write(std::ostream &os, const uint32_t &val)
 #endif //GDCM_WORDS_BIGENDIAN
 }
 
+
+/**
+ * \brief binary_write binary_write
+ * @param os ostream to write to
+ * @param val double (64 bits) value to write
+ */ 
+std::ostream &binary_write(std::ostream &os, const double &val)
+{
+#if defined(GDCM_WORDS_BIGENDIAN) || defined(GDCM_FORCE_BIGENDIAN_EMULATION)    
+   double swap = val;
+   
+   char *beg = (char *)&swap;
+   char *end = beg + 7;
+   char t;
+   for (unsigned int i = 0; i<7; i++)
+   {
+      t    = *beg;
+      *beg = *end;
+      *end = t;
+      beg++,
+      end--;  
+   }  
+   return os.write(reinterpret_cast<const char*>(&swap), 8);
+#else
+   return os.write(reinterpret_cast<const char*>(&val), 8);
+#endif //GDCM_WORDS_BIGENDIAN
+}
+
+
 /**
  * \brief  binary_write binary_write
  * @param os ostream to write to
- * @param val val
+ * @param val 8 bits characters aray to write
  */ 
 std::ostream &binary_write(std::ostream &os, const char *val)
 {
@@ -882,9 +1011,9 @@ std::ostream &binary_write(std::ostream &os, const char *val)
 }
 
 /**
- * \brief
+ * \brief  binary_write binary_write
  * @param os ostream to write to
- * @param val val
+ * @param val std::string value to write
  */ 
 std::ostream &binary_write(std::ostream &os, std::string const &val)
 {
@@ -894,7 +1023,7 @@ std::ostream &binary_write(std::ostream &os, std::string const &val)
 /**
  * \brief  binary_write binary_write
  * @param os ostream to write to
- * @param val value
+ * @param val 8 bits 'characters' aray to write
  * @param len length of the 'value' to be written
  */ 
 std::ostream &binary_write(std::ostream &os, const uint8_t *val, size_t len)
@@ -906,8 +1035,8 @@ std::ostream &binary_write(std::ostream &os, const uint8_t *val, size_t len)
 /**
  * \brief  binary_write binary_write
  * @param os ostream to write to
- * @param val val
- * @param len length of the 'value' to be written 
+ * @param val 16 bits words aray to write
+ * @param len length (in bytes) of the 'value' to be written 
  */ 
 std::ostream &binary_write(std::ostream &os, const uint16_t *val, size_t len)
 {