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