# gdcmByteValue.h

Go to the documentation of this file.

    00001 /*=========================================================================
    00002
    00003   Program: GDCM (Grassroots DICOM). A DICOM library
    00004   Module:  $URL$
    00005
    00006   Copyright (c) 2006-2009 Mathieu Malaterre
    00007   All rights reserved.
    00008   See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details.
    00009
    00010      This software is distributed WITHOUT ANY WARRANTY; without even
    00011      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
    00012      PURPOSE.  See the above copyright notice for more information.
    00013
    00014 =========================================================================*/
    00015 #ifndef __gdcmByteValue_h
    00016 #define __gdcmByteValue_h
    00017
    00018 #include "gdcmValue.h"
    00019 #include "gdcmTrace.h"
    00020 #include "gdcmVL.h"
    00021
    00022 #include <vector>
    00023 #include <iterator>
    00024 #include <iomanip>
    00025
    00026 //#include <stdlib.h> // abort
    00027
    00028 namespace gdcm
    00029 {
    00034 class GDCM_EXPORT ByteValue : public Value
    00035 {
    00036 public:
    00037   ByteValue(const char* array = 0, VL const &vl = 0):
    00038     Internal(array, array+vl),Length(vl) {
    00039       if( vl.IsOdd() )
    00040         {
    00041         gdcmDebugMacro( "Odd length" );
    00042         Internal.resize(vl+1);
    00043         Length++;
    00044         }
    00045   }
    00046   ByteValue(std::vector<char> &v):Internal(v),Length(v.size()) {}
    00047   //ByteValue(std::ostringstream const &os) {
    00048   //  (void)os;
    00049   //   assert(0); // TODO
    00050   //}
    00051   ~ByteValue() {
    00052     Internal.clear();
    00053   }
    00054
    00055   // When 'dumping' dicom file we still have some information from
    00056   // Either the VR: eg LO (private tag)
    00057   void PrintASCII(std::ostream &os, VL maxlength ) const;
    00058
    00059   void PrintHex(std::ostream &os, VL maxlength) const;
    00060
    00061   // Either from Element Number (== 0x0000)
    00062   void PrintGroupLength(std::ostream &os) {
    00063     assert( Length == 2 );
    00064     (void)os;
    00065   }
    00066
    00067   bool IsEmpty() const {
    00068     if( Internal.empty() ) assert( Length == 0 );
    00069     return Internal.empty();
    00070   }
    00071   VL GetLength() const { return Length; }
    00072   // Does a reallocation
    00073   void SetLength(VL vl) {
    00074     VL l(vl);
    00075 #ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION
    00076     // CompressedLossy.dcm
    00077     if( l.IsUndefined() ) throw Exception( "Impossible" );
    00078     if ( l.IsOdd() ) {
    00079       gdcmDebugMacro(
    00080         "BUGGY HEADER: Your dicom contain odd length value field." );
    00081       ++l;
    00082       }
    00083 #else
    00084     assert( !l.IsUndefined() && !l.IsOdd() );
    00085 #endif
    00086     // I cannot use reserve for now. I need to implement:
    00087     // STL - vector<> and istream
    00088     // http://groups.google.com/group/comp.lang.c++/msg/37ec052ed8283e74
    00089 //#define SHORT_READ_HACK
    00090     try
    00091       {
    00092 #ifdef SHORT_READ_HACK
    00093     if( l <= 0xff )
    00094 #endif
    00095       Internal.resize(l);
    00096       //Internal.reserve(l);
    00097       }
    00098     catch(...)
    00099       {
    00100       //throw Exception("Impossible to allocate: " << l << " bytes." );
    00101       throw Exception("Impossible to allocate" );
    00102       }
    00103     // Keep the exact length
    00104     Length = vl;
    00105   }
    00106
    00107   operator const std::vector<char>& () const { return Internal; }
    00108
    00109   ByteValue &operator=(const ByteValue &val) {
    00110     Internal = val.Internal;
    00111     Length = val.Length;
    00112     return *this;
    00113     }
    00114
    00115   bool operator==(const ByteValue &val) const {
    00116     if( Length != val.Length )
    00117       return false;
    00118     if( Internal == val.Internal )
    00119       return true;
    00120     return false;
    00121     }
    00122
    00123   void Clear() {
    00124     Internal.clear();
    00125   }
    00126   // Use that only if you understand what you are doing
    00127   const char *GetPointer() const {
    00128     if(!Internal.empty()) return &Internal[0];
    00129     return 0;
    00130   }
    00131   void Fill(char c) {
    00132     //if( Internal.empty() ) return;
    00133     std::vector<char>::iterator it = Internal.begin();
    00134     for(; it != Internal.end(); ++it) *it = c;
    00135   }
    00136   bool GetBuffer(char *buffer, unsigned long length) const {
    00137     // SIEMENS_GBS_III-16-ACR_NEMA_1.acr has a weird pixel length
    00138     // so we need an inequality
    00139     if( length <= Internal.size() )
    00140       {
    00141       memcpy(buffer, &Internal[0], length);
    00142       return true;
    00143       }
    00144     gdcmDebugMacro( "Could not handle length= " << length );
    00145     return false;
    00146     }
    00147   bool WriteBuffer(std::ostream &os) const {
    00148     if( Length ) {
    00149       //assert( Internal.size() <= Length );
    00150       assert( !(Internal.size() % 2) );
    00151       os.write(&Internal[0], Internal.size() );
    00152       }
    00153     return true;
    00154   }
    00155
    00156   template <typename TSwap, typename TType>
    00157   std::istream &Read(std::istream &is) {
    00158     // If Length is odd we have detected that in SetLength
    00159     // and calling std::vector::resize make sure to allocate *AND*
    00160     // initialize values to 0 so we are sure to have a \0 at the end
    00161     // even in this case
    00162     if(Length)
    00163       {
    00164       is.read(&Internal[0], Length);
    00165       assert( Internal.size() == Length || Internal.size() == Length + 1 );
    00166       TSwap::SwapArray((TType*)&Internal[0], Internal.size() / sizeof(TType) );
    00167       }
    00168     return is;
    00169   }
    00170
    00171   template <typename TSwap>
    00172   std::istream &Read(std::istream &is) {
    00173     return Read<TSwap,uint8_t>(is);
    00174   }
    00175
    00176
    00177   template <typename TSwap, typename TType>
    00178   std::ostream const &Write(std::ostream &os) const {
    00179     assert( !(Internal.size() % 2) );
    00180     if( !Internal.empty() ) {
    00181       //os.write(&Internal[0], Internal.size());
    00182       std::vector<char> copy = Internal;
    00183       TSwap::SwapArray((TType*)&copy[0], Internal.size() / sizeof(TType) );
    00184       os.write(&copy[0], copy.size());
    00185       }
    00186     return os;
    00187   }
    00188
    00189   template <typename TSwap>
    00190   std::ostream const &Write(std::ostream &os) const {
    00191     return Write<TSwap,uint8_t>(os);
    00192   }
    00193
    00200   bool IsPrintable(VL length) const {
    00201     assert( length <= Length );
    00202     for(unsigned int i=0; i<length; i++)
    00203       {
    00204       if ( i == (length-1) && Internal[i] == '\0') continue;
    00205       if ( !( isprint((unsigned char)Internal[i]) || isspace((unsigned char)Internal[i]) ) )
    00206         {
    00207         //gdcmWarningMacro( "Cannot print :" << i );
    00208         return false;
    00209         }
    00210       }
    00211     return true;
    00212     }
    00213
    00214 protected:
    00215   void Print(std::ostream &os) const {
    00216   // This is perfectly valid to have a Length = 0 , so we cannot check
    00217   // the length for printing
    00218   if( !Internal.empty() )
    00219     {
    00220     if( IsPrintable(Length) )
    00221       {
    00222       // WARNING: Internal.end() != Internal.begin()+Length
    00223       std::vector<char>::size_type length = Length;
    00224       if( Internal.back() == 0 ) --length;
    00225       std::copy(Internal.begin(), Internal.begin()+length,
    00226         std::ostream_iterator<char>(os));
    00227       }
    00228     else
    00229       os << "Loaded:" << Internal.size();
    00230     }
    00231   else
    00232     {
    00233     //os << "Not Loaded";
    00234     os << "(no value available)";
    00235     }
    00236   }
    00237
    00238
    00239 private:
    00240   std::vector<char> Internal;
    00241
    00242   // WARNING Length IS NOT Internal.size() some *featured* DICOM
    00243   // implementation define odd length, we always load them as even number
    00244   // of byte, so we need to keep the right Length
    00245   VL Length;
    00246 };
    00247
    00248 } // end namespace gdcm
    00249
    00250 #endif //__gdcmByteValue_h
    00251