# 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-2010 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
    00048   ByteValue(std::vector<char> &v):Internal(v),Length((uint32_t)v.size()) {}
    00049   //ByteValue(std::ostringstream const &os) {
    00050   //  (void)os;
    00051   //   assert(0); // TODO
    00052   //}
    00053   ~ByteValue() {
    00054     Internal.clear();
    00055   }
    00056
    00057   // When 'dumping' dicom file we still have some information from
    00058   // Either the VR: eg LO (private tag)
    00059   void PrintASCII(std::ostream &os, VL maxlength ) const;
    00060
    00061   void PrintHex(std::ostream &os, VL maxlength) const;
    00062
    00063   // Either from Element Number (== 0x0000)
    00064   void PrintGroupLength(std::ostream &os) {
    00065     assert( Length == 2 );
    00066     (void)os;
    00067   }
    00068
    00069   bool IsEmpty() const {
    00070     if( Internal.empty() ) assert( Length == 0 );
    00071     return Internal.empty();
    00072   }
    00073   VL GetLength() const { return Length; }
    00074   // Does a reallocation
    00075   void SetLength(VL vl) {
    00076     VL l(vl);
    00077 #ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION
    00078     // CompressedLossy.dcm
    00079     if( l.IsUndefined() ) throw Exception( "Impossible" );
    00080     if ( l.IsOdd() ) {
    00081       gdcmDebugMacro(
    00082         "BUGGY HEADER: Your dicom contain odd length value field." );
    00083       ++l;
    00084       }
    00085 #else
    00086     assert( !l.IsUndefined() && !l.IsOdd() );
    00087 #endif
    00088     // I cannot use reserve for now. I need to implement:
    00089     // STL - vector<> and istream
    00090     // http://groups.google.com/group/comp.lang.c++/msg/37ec052ed8283e74
    00091 //#define SHORT_READ_HACK
    00092     try
    00093       {
    00094 #ifdef SHORT_READ_HACK
    00095     if( l <= 0xff )
    00096 #endif
    00097       Internal.resize(l);
    00098       //Internal.reserve(l);
    00099       }
    00100     catch(...)
    00101       {
    00102       //throw Exception("Impossible to allocate: " << l << " bytes." );
    00103       throw Exception("Impossible to allocate" );
    00104       }
    00105     // Keep the exact length
    00106     Length = vl;
    00107   }
    00108
    00109   operator const std::vector<char>& () const { return Internal; }
    00110
    00111   ByteValue &operator=(const ByteValue &val) {
    00112     Internal = val.Internal;
    00113     Length = val.Length;
    00114     return *this;
    00115     }
    00116
    00117   bool operator==(const ByteValue &val) const {
    00118     if( Length != val.Length )
    00119       return false;
    00120     if( Internal == val.Internal )
    00121       return true;
    00122     return false;
    00123     }
    00124   bool operator==(const Value &val) const
    00125     {
    00126     const ByteValue &bv = dynamic_cast<const ByteValue&>(val);
    00127     return Length == bv.Length && Internal == bv.Internal;
    00128     }
    00129
    00130
    00131   void Clear() {
    00132     Internal.clear();
    00133   }
    00134   // Use that only if you understand what you are doing
    00135   const char *GetPointer() const {
    00136     if(!Internal.empty()) return &Internal[0];
    00137     return 0;
    00138   }
    00139   void Fill(char c) {
    00140     //if( Internal.empty() ) return;
    00141     std::vector<char>::iterator it = Internal.begin();
    00142     for(; it != Internal.end(); ++it) *it = c;
    00143   }
    00144   bool GetBuffer(char *buffer, unsigned long length) const {
    00145     // SIEMENS_GBS_III-16-ACR_NEMA_1.acr has a weird pixel length
    00146     // so we need an inequality
    00147     if( length <= Internal.size() )
    00148       {
    00149       memcpy(buffer, &Internal[0], length);
    00150       return true;
    00151       }
    00152     gdcmDebugMacro( "Could not handle length= " << length );
    00153     return false;
    00154     }
    00155   bool WriteBuffer(std::ostream &os) const {
    00156     if( Length ) {
    00157       //assert( Internal.size() <= Length );
    00158       assert( !(Internal.size() % 2) );
    00159       os.write(&Internal[0], Internal.size() );
    00160       }
    00161     return true;
    00162   }
    00163
    00164   template <typename TSwap, typename TType>
    00165   std::istream &Read(std::istream &is) {
    00166     // If Length is odd we have detected that in SetLength
    00167     // and calling std::vector::resize make sure to allocate *AND*
    00168     // initialize values to 0 so we are sure to have a \0 at the end
    00169     // even in this case
    00170     if(Length)
    00171       {
    00172       is.read(&Internal[0], Length);
    00173       assert( Internal.size() == Length || Internal.size() == Length + 1 );
    00174       TSwap::SwapArray((TType*)&Internal[0], Internal.size() / sizeof(TType) );
    00175       }
    00176     return is;
    00177   }
    00178
    00179   template <typename TSwap>
    00180   std::istream &Read(std::istream &is) {
    00181     return Read<TSwap,uint8_t>(is);
    00182   }
    00183
    00184
    00185   template <typename TSwap, typename TType>
    00186   std::ostream const &Write(std::ostream &os) const {
    00187     assert( !(Internal.size() % 2) );
    00188     if( !Internal.empty() ) {
    00189       //os.write(&Internal[0], Internal.size());
    00190       std::vector<char> copy = Internal;
    00191       TSwap::SwapArray((TType*)&copy[0], Internal.size() / sizeof(TType) );
    00192       os.write(&copy[0], copy.size());
    00193       }
    00194     return os;
    00195   }
    00196
    00197   template <typename TSwap>
    00198   std::ostream const &Write(std::ostream &os) const {
    00199     return Write<TSwap,uint8_t>(os);
    00200   }
    00201
    00208   bool IsPrintable(VL length) const {
    00209     assert( length <= Length );
    00210     for(unsigned int i=0; i<length; i++)
    00211       {
    00212       if ( i == (length-1) && Internal[i] == '\0') continue;
    00213       if ( !( isprint((unsigned char)Internal[i]) || isspace((unsigned char)Internal[i]) ) )
    00214         {
    00215         //gdcmWarningMacro( "Cannot print :" << i );
    00216         return false;
    00217         }
    00218       }
    00219     return true;
    00220     }
    00221
    00222 protected:
    00223   void Print(std::ostream &os) const {
    00224   // This is perfectly valid to have a Length = 0 , so we cannot check
    00225   // the length for printing
    00226   if( !Internal.empty() )
    00227     {
    00228     if( IsPrintable(Length) )
    00229       {
    00230       // WARNING: Internal.end() != Internal.begin()+Length
    00231       std::vector<char>::size_type length = Length;
    00232       if( Internal.back() == 0 ) --length;
    00233       std::copy(Internal.begin(), Internal.begin()+length,
    00234         std::ostream_iterator<char>(os));
    00235       }
    00236     else
    00237       os << "Loaded:" << Internal.size();
    00238     }
    00239   else
    00240     {
    00241     //os << "Not Loaded";
    00242     os << "(no value available)";
    00243     }
    00244   }
    00245
    00246
    00247 private:
    00248   std::vector<char> Internal;
    00249
    00250   // WARNING Length IS NOT Internal.size() some *featured* DICOM
    00251   // implementation define odd length, we always load them as even number
    00252   // of byte, so we need to keep the right Length
    00253   VL Length;
    00254 };
    00255
    00256 } // end namespace gdcm
    00257
    00258 #endif //GDCMBYTEVALUE_H