# gdcmElement.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 __gdcmElement_h
    00016 #define __gdcmElement_h
    00017
    00018 #include "gdcmTypes.h"
    00019 #include "gdcmVR.h"
    00020 #include "gdcmTag.h"
    00021 #include "gdcmVM.h"
    00022 #include "gdcmByteValue.h"
    00023 #include "gdcmDataElement.h"
    00024 #include "gdcmSwapper.h"
    00025
    00026 #include <string>
    00027 #include <vector>
    00028 #include <sstream>
    00029 #include <limits>
    00030 #include <cmath>
    00031
    00032 namespace gdcm
    00033 {
    00034
    00035 // Forward declaration
    00041 template<int T> class EncodingImplementation;
    00042
    00048 template<int TVR, int TVM>
    00049 class Element
    00050 {
    00051 public:
    00052   typename VRToType<TVR>::Type Internal[VMToLength<TVM>::Length];
    00053   typedef typename VRToType<TVR>::Type Type;
    00054
    00055   unsigned long GetLength() const {
    00056     return VMToLength<TVM>::Length;
    00057   }
    00058   // Implementation of Print is common to all Mode (ASCII/Binary)
    00059   // TODO: Can we print a \ when in ASCII...well I don't think so
    00060   // it would mean we used a bad VM then, right ?
    00061   void Print(std::ostream &_os) const {
    00062     _os << Internal[0]; // VM is at least garantee to be one
    00063     for(int i=1; i<VMToLength<TVM>::Length; ++i)
    00064       _os << "," << Internal[i];
    00065     }
    00066
    00067   const typename VRToType<TVR>::Type *GetValues() const {
    00068     return Internal;
    00069   }
    00070   const typename VRToType<TVR>::Type &GetValue(unsigned int idx = 0) const {
    00071     assert( idx < VMToLength<TVM>::Length );
    00072     return Internal[idx];
    00073   }
    00074   typename VRToType<TVR>::Type &GetValue(unsigned int idx = 0) {
    00075     assert( idx < VMToLength<TVM>::Length );
    00076     return Internal[idx];
    00077   }
    00078   typename VRToType<TVR>::Type operator[] (unsigned int idx) const {
    00079     return GetValue(idx);
    00080   }
    00081   void SetValue(typename VRToType<TVR>::Type v, unsigned int idx = 0) {
    00082     assert( idx < VMToLength<TVM>::Length );
    00083     Internal[idx] = v;
    00084   }
    00085
    00086   void SetFromDataElement(DataElement const &de) {
    00087     const ByteValue *bv = de.GetByteValue();
    00088     assert( bv );
    00089     if( de.GetVR() == VR::UN || de.GetVR() == VR::INVALID )
    00090       {
    00091       Set(de.GetValue());
    00092       }
    00093     else
    00094       {
    00095       SetNoSwap(de.GetValue());
    00096       }
    00097   }
    00098
    00099   void Read(std::istream &_is) {
    00100     return EncodingImplementation<VRToEncoding<TVR>::Mode>::Read(Internal,
    00101       GetLength(),_is);
    00102     }
    00103   void Write(std::ostream &_os) const {
    00104     return EncodingImplementation<VRToEncoding<TVR>::Mode>::Write(Internal,
    00105       GetLength(),_os);
    00106     }
    00107
    00108   // FIXME: remove this function
    00109   // this is only used in gdcm::SplitMosaicFilter / to pass value of a CSAElement
    00110   void Set(Value const &v) {
    00111     const ByteValue *bv = dynamic_cast<const ByteValue*>(&v);
    00112     assert( bv ); // That would be bad...
    00113     //memcpy(Internal, bv->GetPointer(), bv->GetLength());
    00114     std::stringstream ss;
    00115     std::string s = std::string( bv->GetPointer(), bv->GetLength() );
    00116     ss.str( s );
    00117     EncodingImplementation<VRToEncoding<TVR>::Mode>::Read(Internal,
    00118       GetLength(),ss);
    00119   }
    00120 protected:
    00121   void SetNoSwap(Value const &v) {
    00122     const ByteValue *bv = dynamic_cast<const ByteValue*>(&v);
    00123     assert( bv ); // That would be bad...
    00124     //memcpy(Internal, bv->GetPointer(), bv->GetLength());
    00125     std::stringstream ss;
    00126     std::string s = std::string( bv->GetPointer(), bv->GetLength() );
    00127     ss.str( s );
    00128     EncodingImplementation<VRToEncoding<TVR>::Mode>::ReadNoSwap(Internal,
    00129       GetLength(),ss);
    00130   }
    00131 };
    00132
    00133 struct ignore_char {
    00134   ignore_char(char c): m_char(c) {}
    00135   char m_char;
    00136 };
    00137 ignore_char const backslash('\\');
    00138
    00139   inline std::istream& operator>> (std::istream& in, ignore_char const& ic) {
    00140     if (!in.eof())
    00141       in.clear(in.rdstate() & ~std::ios_base::failbit);
    00142     if (in.get() != ic.m_char)
    00143       in.setstate(std::ios_base::failbit);
    00144     return in;
    00145   }
    00146
    00147
    00148 // Implementation to perform formatted read and write
    00149 template<> class EncodingImplementation<VR::VRASCII> {
    00150 public:
    00151   template<typename T> // FIXME this should be VRToType<TVR>::Type
    00152   static inline void ReadComputeLength(T* data, unsigned int &length,
    00153                           std::istream &_is) {
    00154     assert( data );
    00155     //assert( length ); // != 0
    00156     length = 0;
    00157     assert( _is );
    00158 #if 0
    00159     char sep;
    00160     while( _is >> data[length++] )
    00161       {
    00162       // Get the separator in between the values
    00163       assert( _is );
    00164       _is.get(sep);
    00165       assert( sep == '\\' || sep == ' ' ); // FIXME: Bad use of assert
    00166       if( sep == ' ' ) length--; // FIXME
    00167       }
    00168 #else
    00169   while( _is >> std::ws >> data[length++] >> std::ws >> backslash )
    00170     {
    00171     }
    00172 #endif
    00173     }
    00174
    00175   template<typename T> // FIXME this should be VRToType<TVR>::Type
    00176   static inline void Read(T* data, unsigned long length,
    00177                           std::istream &_is) {
    00178     assert( data );
    00179     assert( length ); // != 0
    00180     assert( _is );
    00181     // FIXME BUG: what if >> operation fails ?
    00182     // gdcmData/MR00010001.dcm / SpacingBetweenSlices
    00183     _is >> std::ws >> data[0];
    00184     char sep;
    00185     //std::cout << "GetLength: " << af->GetLength() << std::endl;
    00186     for(unsigned long i=1; i<length;++i) {
    00187       assert( _is );
    00188       // Get the separator in between the values
    00189       _is >> std::ws >> sep; //_is.get(sep);
    00190       assert( sep == '\\' ); // FIXME: Bad use of assert
    00191       _is >> std::ws >> data[i];
    00192       }
    00193     }
    00194
    00195   template<typename T>
    00196   static inline void ReadNoSwap(T* data, unsigned long length,
    00197                           std::istream &_is) {
    00198     Read(data,length,_is);
    00199 }
    00200   template<typename T>
    00201   static inline void Write(const T* data, unsigned long length,
    00202                            std::ostream &_os)  {
    00203     assert( data );
    00204     assert( length );
    00205     assert( _os );
    00206     _os << data[0];
    00207     for(unsigned long i=1; i<length; ++i) {
    00208       assert( _os );
    00209       _os << "\\" << data[i];
    00210       }
    00211     }
    00212 };
    00213
    00214 template < typename Float >
    00215 std::string to_string ( Float data ) {
    00216   std::stringstream in;
    00217   // in.imbue(std::locale::classic()); // This is not required AFAIK
    00218   unsigned long const digits =
    00219     static_cast< unsigned long >(
    00220     - std::log( std::numeric_limits<Float>::epsilon() )
    00221     / std::log( 10.0 ) );
    00222   if ( in << std::dec << std::setprecision(/*2+*/digits) << data ) {
    00223     return ( in.str() );
    00224   } else {
    00225     throw "Impossible Conversion"; // should not happen ...
    00226   }
    00227 }
    00228
    00229 /* Writing VR::DS is not that easy after all */
    00230 // http://groups.google.com/group/comp.lang.c++/browse_thread/thread/69ccd26f000a0802
    00231 template<> inline void EncodingImplementation<VR::VRASCII>::Write(const float * data, unsigned long length, std::ostream &_os)  {
    00232     assert( data );
    00233     assert( length );
    00234     assert( _os );
    00235     _os << to_string(data[0]);
    00236     for(unsigned long i=1; i<length; ++i) {
    00237       assert( _os );
    00238       _os << "\\" << to_string(data[i]);
    00239       }
    00240     }
    00241
    00242 template<> inline void EncodingImplementation<VR::VRASCII>::Write(const double* data, unsigned long length, std::ostream &_os)  {
    00243     assert( data );
    00244     assert( length );
    00245     assert( _os );
    00246     _os << to_string(data[0]);
    00247     for(unsigned long i=1; i<length; ++i) {
    00248       assert( _os );
    00249       _os << "\\" << to_string(data[i]);
    00250       }
    00251     }
    00252
    00253
    00254 // Implementation to perform binary read and write
    00255 // TODO rewrite operation so that either:
    00256 // #1. dummy implementation use a pointer to Internal and do ++p (faster)
    00257 // #2. Actually do some meta programming to unroll the loop
    00258 // (no notion of order in VM ...)
    00259 template<> class EncodingImplementation<VR::VRBINARY> {
    00260 public:
    00261   template<typename T> // FIXME this should be VRToType<TVR>::Type
    00262     static inline void ReadComputeLength(T* data, unsigned int &length,
    00263       std::istream &_is) {
    00264     const unsigned int type_size = sizeof(T);
    00265     assert( data ); // Can we read from pointer ?
    00266     //assert( length );
    00267     length /= type_size;
    00268     assert( _is ); // Is stream valid ?
    00269     _is.read( reinterpret_cast<char*>(data+0), type_size);
    00270     for(unsigned long i=1; i<length; ++i) {
    00271       assert( _is );
    00272       _is.read( reinterpret_cast<char*>(data+i), type_size );
    00273     }
    00274     }
    00275   template<typename T>
    00276   static inline void ReadNoSwap(T* data, unsigned long length,
    00277     std::istream &_is) {
    00278     const unsigned int type_size = sizeof(T);
    00279     assert( data ); // Can we read from pointer ?
    00280     assert( length );
    00281     assert( _is ); // Is stream valid ?
    00282     _is.read( reinterpret_cast<char*>(data+0), type_size);
    00283     for(unsigned long i=1; i<length; ++i) {
    00284       assert( _is );
    00285       _is.read( reinterpret_cast<char*>(data+i), type_size );
    00286     }
    00287     //ByteSwap<T>::SwapRangeFromSwapCodeIntoSystem(data,
    00288     //  _is.GetSwapCode(), length);
    00289     //SwapperNoOp::SwapArray(data,length);
    00290   }
    00291   template<typename T>
    00292   static inline void Read(T* data, unsigned long length,
    00293     std::istream &_is) {
    00294     const unsigned int type_size = sizeof(T);
    00295     assert( data ); // Can we read from pointer ?
    00296     assert( length );
    00297     assert( _is ); // Is stream valid ?
    00298     _is.read( reinterpret_cast<char*>(data+0), type_size);
    00299     for(unsigned long i=1; i<length; ++i) {
    00300       assert( _is );
    00301       _is.read( reinterpret_cast<char*>(data+i), type_size );
    00302     }
    00303     //ByteSwap<T>::SwapRangeFromSwapCodeIntoSystem(data,
    00304     //  _is.GetSwapCode(), length);
    00305     SwapperNoOp::SwapArray(data,length);
    00306   }
    00307   template<typename T>
    00308   static inline void Write(const T* data, unsigned long length,
    00309     std::ostream &_os) {
    00310     const unsigned int type_size = sizeof(T);
    00311     assert( data ); // Can we write into pointer ?
    00312     assert( length );
    00313     assert( _os ); // Is stream valid ?
    00314     //ByteSwap<T>::SwapRangeFromSwapCodeIntoSystem((T*)data,
    00315     //  _os.GetSwapCode(), length);
    00316     T swappedData = SwapperNoOp::Swap(data[0]);
    00317     _os.write( reinterpret_cast<const char*>(&swappedData), type_size);
    00318     for(unsigned long i=1; i<length;++i) {
    00319       assert( _os );
    00320       swappedData = SwapperNoOp::Swap(data[i]);
    00321       _os.write( reinterpret_cast<const char*>(&swappedData), type_size );
    00322     }
    00323     //ByteSwap<T>::SwapRangeFromSwapCodeIntoSystem((T*)data,
    00324     //  _os.GetSwapCode(), length);
    00325   }
    00326 };
    00327
    00328 // For particular case for ASCII string
    00329 // WARNING: This template explicitely instanciates a particular
    00330 // EncodingImplementation THEREFORE it is required to be declared after the
    00331 // EncodingImplementation is needs (doh!)
    00332 #if 0
    00333 template<int TVM>
    00334 class Element<TVM>
    00335 {
    00336 public:
    00337   Element(const char array[])
    00338     {
    00339     unsigned int i = 0;
    00340     const char sep = '\\';
    00341     std::string sarray = array;
    00342     std::string::size_type pos1 = 0;
    00343     std::string::size_type pos2 = sarray.find(sep, pos1+1);
    00344     while(pos2 != std::string::npos)
    00345       {
    00346       Internal[i++] = sarray.substr(pos1, pos2-pos1);
    00347       pos1 = pos2+1;
    00348       pos2 = sarray.find(sep, pos1+1);
    00349       }
    00350     Internal[i] = sarray.substr(pos1, pos2-pos1);
    00351     // Shouldn't we do the contrary, since we know how many separators
    00352     // (and default behavior is to discard anything after the VM declared
    00353     assert( GetLength()-1 == i );
    00354     }
    00355
    00356   unsigned long GetLength() const {
    00357     return VMToLength<TVM>::Length;
    00358   }
    00359   // Implementation of Print is common to all Mode (ASCII/Binary)
    00360   void Print(std::ostream &_os) const {
    00361     _os << Internal[0]; // VM is at least garantee to be one
    00362     for(int i=1; i<VMToLength<TVM>::Length; ++i)
    00363       _os << "," << Internal[i];
    00364     }
    00365
    00366   void Read(std::istream &_is) {
    00367     EncodingImplementation<VR::VRASCII>::Read(Internal, GetLength(),_is);
    00368     }
    00369   void Write(std::ostream &_os) const {
    00370     EncodingImplementation<VR::VRASCII>::Write(Internal, GetLength(),_os);
    00371     }
    00372 private:
    00373   typename String Internal[VMToLength<TVM>::Length];
    00374 };
    00375
    00376 template< int TVM>
    00377 class Element<VR::PN, TVM> : public StringElement<TVM>
    00378 {
    00379 };
    00380 #endif
    00381
    00382 // Implementation for the undefined length (dynamically allocated array)
    00383 template<int TVR>
    00384 class Element<TVR, VM::VM1_n>
    00385 {
    00386 public:
    00387   // This the way to prevent default initialization
    00388   explicit Element() { Internal=0; Length=0; Save = false; }
    00389   ~Element() {
    00390     if( Save ) {
    00391       delete[] Internal;
    00392     }
    00393     Internal = 0;
    00394   }
    00395
    00396   // Length manipulation
    00397   // SetLength should really be protected anyway...all operation
    00398   // should go through SetArray
    00399   unsigned long GetLength() const { return Length; }
    00400   typedef typename VRToType<TVR>::Type Type;
    00401
    00402   void SetLength(unsigned long len) {
    00403     const unsigned int size = sizeof(Type);
    00404     if( len ) {
    00405       if( len > Length ) {
    00406         // perform realloc
    00407         assert( (len / size) * size == len );
    00408         Type *internal = new Type[len / size];
    00409         assert( Save == false );
    00410         Save = true; // ????
    00411         if( Internal )
    00412           {
    00413           memcpy(internal, Internal, len);
    00414           delete[] Internal;
    00415           }
    00416         Internal = internal;
    00417         }
    00418       }
    00419     Length = len / size;
    00420   }
    00421
    00422   // If save is set to zero user should not delete the pointer
    00423   //void SetArray(const typename VRToType<TVR>::Type *array, int len, bool save = false)
    00424   void SetArray(const Type *array, unsigned long len,
    00425     bool save = false) {
    00426     if( save ) {
    00427       SetLength(len); // realloc
    00428       memcpy(Internal, array, len/*/sizeof(Type)*/);
    00429       assert( Save == false );
    00430       }
    00431     else {
    00432       // TODO rewrite this stupid code:
    00433       assert( Length == 0 );
    00434       assert( Internal == 0 );
    00435       assert( Save == false );
    00436       Length = len / sizeof(Type);
    00437       //assert( (len / sizeof(Type)) * sizeof(Type) == len );
    00438       // MR00010001.dcm is a tough kid: 0019,105a is supposed to be VR::FL, VM::VM3 but
    00439       // length is 14 bytes instead of 12 bytes. Simply consider value is total garbage.
    00440       if( (len / sizeof(Type)) * sizeof(Type) != len ) { Internal = 0; Length = 0; }
    00441       else Internal = const_cast<Type*>(array);
    00442       }
    00443       Save = save;
    00444   }
    00445   void SetValue(typename VRToType<TVR>::Type v, unsigned int idx = 0) {
    00446     assert( idx < Length );
    00447     Internal[idx] = v;
    00448   }
    00449   const typename VRToType<TVR>::Type &GetValue(unsigned int idx = 0) const {
    00450     assert( idx < Length );
    00451     return Internal[idx];
    00452   }
    00453   typename VRToType<TVR>::Type &GetValue(unsigned int idx = 0) {
    00454     assert( idx < Length );
    00455     return Internal[idx];
    00456   }
    00457   typename VRToType<TVR>::Type operator[] (unsigned int idx) const {
    00458     return GetValue(idx);
    00459   }
    00460   void Set(Value const &v) {
    00461     const ByteValue *bv = dynamic_cast<const ByteValue*>(&v);
    00462     assert( bv ); // That would be bad...
    00463     if( (VR::VRType)(VRToEncoding<TVR>::Mode) == VR::VRBINARY )
    00464       {
    00465       const Type* array = (Type*)bv->GetPointer();
    00466       if( array ) {
    00467         assert( array ); // That would be bad...
    00468         assert( Internal == 0 );
    00469         SetArray(array, bv->GetLength() ); }
    00470       }
    00471     else
    00472       {
    00473       std::stringstream ss;
    00474       std::string s = std::string( bv->GetPointer(), bv->GetLength() );
    00475       ss.str( s );
    00476       EncodingImplementation<VRToEncoding<TVR>::Mode>::Read(Internal,
    00477         GetLength(),ss);
    00478       }
    00479   }
    00480
    00481   // Need to be placed after definition of EncodingImplementation<VR::VRASCII>
    00482   void WriteASCII(std::ostream &os) const {
    00483     return EncodingImplementation<VR::VRASCII>::Write(Internal, GetLength(), os);
    00484     }
    00485
    00486   // Implementation of Print is common to all Mode (ASCII/Binary)
    00487   void Print(std::ostream &_os) const {
    00488     assert( Length );
    00489     assert( Internal );
    00490     _os << Internal[0]; // VM is at least garantee to be one
    00491     const unsigned long length = GetLength() < 25 ? GetLength() : 25;
    00492     for(unsigned long i=1; i<length; ++i)
    00493       _os << "," << Internal[i];
    00494     }
    00495   void Read(std::istream &_is) {
    00496     if( !Internal ) return;
    00497     EncodingImplementation<VRToEncoding<TVR>::Mode>::Read(Internal,
    00498       GetLength(),_is);
    00499     }
    00500   //void ReadComputeLength(std::istream &_is) {
    00501   //  if( !Internal ) return;
    00502   //  EncodingImplementation<VRToEncoding<TVR>::Mode>::ReadComputeLength(Internal,
    00503   //    Length,_is);
    00504   //  }
    00505   void Write(std::ostream &_os) const {
    00506     EncodingImplementation<VRToEncoding<TVR>::Mode>::Write(Internal,
    00507       GetLength(),_os);
    00508     }
    00509
    00510   DataElement GetAsDataElement() const {
    00511     DataElement ret;
    00512     ret.SetVR( (VR::VRType)TVR );
    00513     if( Internal )
    00514       {
    00515       std::ostringstream os;
    00516       EncodingImplementation<VRToEncoding<TVR>::Mode>::Write(Internal,
    00517         GetLength(),os);
    00518       ret.SetByteValue( os.str().c_str(), os.str().size() );
    00519       }
    00520     return ret;
    00521   }
    00522
    00523   Element(const Element&_val) {
    00524     if( this != &_val) {
    00525       *this = _val;
    00526       }
    00527     }
    00528
    00529   Element &operator=(const Element &_val) {
    00530     Length = 0; // SYITF
    00531     Internal = 0;
    00532     SetArray(_val.Internal, _val.Length, true);
    00533     return *this;
    00534     }
    00535
    00536 private:
    00537   typename VRToType<TVR>::Type *Internal;
    00538   unsigned long Length; // unsigned int ??
    00539   bool Save;
    00540 };
    00541
    00542 //template <int TVM = VM::VM1_n>
    00543 //class Element<VR::OB, TVM > : public Element<VR::OB, VM::VM1_n> {};
    00544
    00545 // Partial specialization for derivatives of 1-n : 2-n, 3-n ...
    00546 template<int TVR>
    00547 class Element<TVR, VM::VM2_n> : public Element<TVR, VM::VM1_n>
    00548 {
    00549 public:
    00550   typedef Element<TVR, VM::VM1_n> Parent;
    00551   void SetLength(int len) {
    00552     if( len <= 1 ) return;
    00553     Parent::SetLength(len);
    00554   }
    00555 };
    00556 template<int TVR>
    00557 class Element<TVR, VM::VM2_2n> : public Element<TVR, VM::VM2_n>
    00558 {
    00559 public:
    00560   typedef Element<TVR, VM::VM2_n> Parent;
    00561   void SetLength(int len) {
    00562     if( len % 2 ) return;
    00563     Parent::SetLength(len);
    00564   }
    00565 };
    00566 template<int TVR>
    00567 class Element<TVR, VM::VM3_n> : public Element<TVR, VM::VM1_n>
    00568 {
    00569 public:
    00570   typedef Element<TVR, VM::VM1_n> Parent;
    00571   void SetLength(int len) {
    00572     if( len <= 2 ) return;
    00573     Parent::SetLength(len);
    00574   }
    00575 };
    00576 template<int TVR>
    00577 class Element<TVR, VM::VM3_3n> : public Element<TVR, VM::VM3_n>
    00578 {
    00579 public:
    00580   typedef Element<TVR, VM::VM3_n> Parent;
    00581   void SetLength(int len) {
    00582     if( len % 3 ) return;
    00583     Parent::SetLength(len);
    00584   }
    00585 };
    00586
    00587
    00588 //template<int T> struct VRToLength;
    00589 //template <> struct VRToLength<VR::AS>
    00590 //{ enum { Length  = VM::VM1 }; }
    00591 //template<>
    00592 //class Element<VR::AS> : public Element<VR::AS, VRToLength<VR::AS>::Length >
    00593
    00594 // only 0010 1010 AS 1 Patient’s Age
    00595 template<>
    00596 class Element<VR::AS, VM::VM5>
    00597 {
    00598 public:
    00599   char Internal[VMToLength<VM::VM5>::Length];
    00600   void Print(std::ostream &_os) const {
    00601     _os << Internal;
    00602     }
    00603   unsigned long GetLength() const {
    00604     return VMToLength<VM::VM5>::Length;
    00605   }
    00606 };
    00607
    00608 template <>
    00609 class Element<VR::OB, VM::VM1> : public Element<VR::OB, VM::VM1_n> {};
    00610 // Make it impossible to compile any other cases:
    00611 template <int TVM> class Element<VR::OB, TVM>;
    00612
    00613 // Same for OW:
    00614 template <>
    00615 class Element<VR::OW, VM::VM1> : public Element<VR::OW, VM::VM1_n> {};
    00616 // Make it impossible to compile any other cases:
    00617 template <int TVM> class Element<VR::OW, TVM>;
    00618
    00619 } // namespace gdcm
    00620
    00621 #endif //__gdcmElement_h