# gdcmItem.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
    00016 #ifndef __gdcmItem_h
    00017 #define __gdcmItem_h
    00018
    00019 #include "gdcmDataElement.h"
    00020 #include "gdcmDataSet.h"
    00021 #include "gdcmParseException.h"
    00022 #include "gdcmSwapper.h"
    00023
    00024 #ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION
    00025 #include "gdcmByteSwapFilter.h"
    00026 #endif
    00027
    00028 namespace gdcm
    00029 {
    00030
    00031 class DataSet;
    00045 class GDCM_EXPORT Item : public DataElement
    00046 {
    00047 public:
    00048   Item() : DataElement(Tag(0xfffe, 0xe000), 0xFFFFFFFF), NestedDataSet() {}
    00049   friend std::ostream& operator<< (std::ostream &os, const Item &val);
    00050
    00051   void Clear() {
    00052     NestedDataSet.Clear();
    00053     }
    00054
    00055   template <typename TDE>
    00056   VL GetLength() const;
    00057
    00058   void InsertDataElement(const DataElement & de) {
    00059     NestedDataSet.Insert(de);
    00060     // Update the length
    00061     if( !IsUndefinedLength() )
    00062       {
    00063       assert( 0 && "InsertDataElement" );
    00064       //ValueLengthField += de.GetLength();
    00065       }
    00066     }
    00067   const DataElement& GetDataElement(const Tag& t) const
    00068     {
    00069     return NestedDataSet.GetDataElement(t);
    00070     }
    00071
    00072   // Completely defines it with the nested dataset
    00073   // destroy anything present
    00074   void SetNestedDataSet(const DataSet& nested)
    00075     {
    00076     NestedDataSet = nested;
    00077     }
    00078   // Return a const ref to the Nested Data Set
    00079   const DataSet &GetNestedDataSet() const
    00080     {
    00081     return NestedDataSet;
    00082     }
    00083   DataSet &GetNestedDataSet()
    00084     {
    00085     return NestedDataSet;
    00086     }
    00087
    00088   //Value const & GetValue() const { return *NestedDataSet; }
    00089
    00090   Item(Item const &val):DataElement(val)
    00091     {
    00092     NestedDataSet = val.NestedDataSet;
    00093     }
    00094
    00095   template <typename TDE, typename TSwap>
    00096   std::istream &Read(std::istream &is) {
    00097     // Superclass
    00098     {
    00099         DataSet &nested = NestedDataSet;
    00100         nested.Clear();
    00101         assert( nested.IsEmpty() );
    00102     }
    00103     if( !TagField.Read<TSwap>(is) )
    00104       {
    00105       throw Exception("Should not happen (item)");
    00106       return is;
    00107       }
    00108 #ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION
    00109     // MR_Philips_Intera_SwitchIndianess_noLgtSQItem_in_trueLgtSeq.dcm
    00110     if( TagField == Tag(0xfeff, 0x00e0)
    00111       || TagField == Tag(0xfeff, 0xdde0) )
    00112       {
    00113       gdcmWarningMacro( "ByteSwaping Private SQ: " << TagField );
    00114       // Invert previously read TagField since wrong endianess:
    00115       TagField = Tag( SwapperDoOp::Swap( TagField.GetGroup() ), SwapperDoOp::Swap( TagField.GetElement() ) );
    00116       assert ( TagField == Tag(0xfffe, 0xe000)
    00117         || TagField == Tag(0xfffe, 0xe0dd) );
    00118
    00119       if( !ValueLengthField.Read<SwapperDoOp>(is) )
    00120         {
    00121         assert(0 && "Should not happen");
    00122         return is;
    00123         }
    00124       // Self
    00125       // Some file written by GDCM 1.0 we writting 0xFFFFFFFF instead of 0x0
    00126       if( TagField == Tag(0xfffe,0xe0dd) )
    00127         {
    00128         if( ValueLengthField )
    00129           {
    00130           gdcmErrorMacro( "ValueLengthField is not 0" );
    00131           }
    00132         }
    00133       //else if( ValueLengthField == 0 )
    00134       //  {
    00135       //  //assert( TagField == Tag( 0xfffe, 0xe0dd) );
    00136       //  if( TagField != Tag( 0xfffe, 0xe0dd) )
    00137       //    {
    00138       //    gdcmErrorMacro( "SQ: " << TagField << " has a length of 0" );
    00139       //    }
    00140       //  }
    00141       else if( ValueLengthField.IsUndefined() )
    00142         {
    00143         DataSet &nested = NestedDataSet;
    00144         nested.Clear();
    00145         assert( nested.IsEmpty() );
    00146         std::streampos start = is.tellg();
    00147         try
    00148           {
    00149           nested.template ReadNested<TDE,SwapperDoOp>(is);
    00150           ByteSwapFilter bsf(nested);
    00151           bsf.ByteSwap();
    00152           }
    00153         catch(ParseException &pe)
    00154           {
    00155           (void)pe;
    00156           // MR_Philips_Intera_PrivateSequenceExplicitVR_in_SQ_2001_e05f_item_wrong_lgt_use_NOSHADOWSEQ.dcm
    00157           // You have to byteswap the length but not the tag...sigh
    00158           gdcmWarningMacro( "Attempt to read nested Item without byteswapping the Value Length." );
    00159           start -= is.tellg();
    00160           assert( start < 0 );
    00161           is.seekg( start, std::ios::cur );
    00162           nested.Clear();
    00163           nested.template ReadNested<TDE,SwapperNoOp>(is);
    00164           ByteSwapFilter bsf(nested);
    00165           // Tag are read in big endian, need to byteswap them back...
    00166           bsf.SetByteSwapTag(true);
    00167           bsf.ByteSwap();
    00168           }
    00169         catch(Exception &e)
    00170           {
    00171           // MR_Philips_Intera_No_PrivateSequenceImplicitVR.dcm
    00172           throw e;
    00173           }
    00174         catch(...)
    00175           {
    00176           assert(0);
    00177           }
    00178         }
    00179       else /* if( ValueLengthField.IsUndefined() ) */
    00180         {
    00181         DataSet &nested = NestedDataSet;
    00182         nested.Clear();
    00183         assert( nested.IsEmpty() );
    00184         nested.template ReadWithLength<TDE,SwapperDoOp>(is, ValueLengthField);
    00185         ByteSwapFilter bsf(nested);
    00186         bsf.ByteSwap();
    00187         }
    00188       return is;
    00189       }
    00190     // http://groups.google.com/group/comp.protocols.dicom/msg/c07efcf5e759fc83
    00191     // Bug_Philips_ItemTag_3F3F.dcm
    00192     if( TagField == Tag(0x3f3f, 0x3f00) )
    00193       {
    00194       //TagField = Tag(0xfffe, 0xe000);
    00195       }
    00196 #endif
    00197     if( TagField != Tag(0xfffe, 0xe000) && TagField != Tag(0xfffe, 0xe0dd) )
    00198       {
    00199       gdcmDebugMacro( "Invalid Item, found tag: " << TagField);
    00200       throw Exception( "Not a valid Item" );
    00201       }
    00202     assert( TagField == Tag(0xfffe, 0xe000) || TagField == Tag(0xfffe, 0xe0dd) );
    00203
    00204     if( !ValueLengthField.Read<TSwap>(is) )
    00205       {
    00206       assert(0 && "Should not happen");
    00207       return is;
    00208       }
    00209     // Self
    00210     if( TagField == Tag(0xfffe,0xe0dd) )
    00211       {
    00212       // Some file written by GDCM 1.0 were written with 0xFFFFFFFF instead of 0x0
    00213       if( ValueLengthField )
    00214         {
    00215         gdcmDebugMacro( "ValueLengthField is not 0 but " << ValueLengthField );
    00216         }
    00217       }
    00218     else if( ValueLengthField.IsUndefined() )
    00219       {
    00220       DataSet &nested = NestedDataSet;
    00221       nested.Clear();
    00222       assert( nested.IsEmpty() );
    00223       nested.template ReadNested<TDE,TSwap>(is);
    00224       }
    00225     else /* if( ValueLengthField.IsUndefined() ) */
    00226       {
    00227       assert( !ValueLengthField.IsUndefined() );
    00228       DataSet &nested = NestedDataSet;
    00229       nested.Clear();
    00230       assert( nested.IsEmpty() );
    00231       nested.template ReadWithLength<TDE,TSwap>(is, ValueLengthField);
    00232       }
    00233
    00234     return is;
    00235   }
    00236
    00237   template <typename TDE, typename TSwap>
    00238   const std::ostream &Write(std::ostream &os) const {
    00239 #ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION
    00240     if( TagField == Tag(0x3f3f,0x3f00) && false )
    00241       {
    00242       Tag t(0xfffe, 0xe000);
    00243       t.Write<TSwap>(os);
    00244       }
    00245     else
    00246 #endif
    00247       {
    00248       assert ( TagField == Tag(0xfffe, 0xe000)
    00249         || TagField == Tag(0xfffe, 0xe0dd) );
    00250       // Not sure how this happen
    00251       if( TagField == Tag(0xfffe, 0xe0dd) )
    00252         {
    00253         gdcmWarningMacro( "SegDelItem found in defined length Sequence" );
    00254         assert( ValueLengthField == 0 );
    00255         assert( NestedDataSet.Size() == 0 );
    00256         }
    00257       if( !TagField.Write<TSwap>(os) )
    00258         {
    00259         assert(0 && "Should not happen");
    00260         return os;
    00261         }
    00262       }
    00263     if( ValueLengthField.IsUndefined() )
    00264       {
    00265       if( !ValueLengthField.Write<TSwap>(os) )
    00266         {
    00267         assert(0 && "Should not happen");
    00268         return os;
    00269         }
    00270       }
    00271     else
    00272       {
    00273       VL dummy = NestedDataSet.GetLength<TDE>();
    00274       //assert( ValueLengthField == dummy );
    00275       if( !dummy.Write<TSwap>(os) )
    00276         {
    00277         assert(0 && "Should not happen");
    00278         return os;
    00279         }
    00280       }
    00281     // Self
    00282     NestedDataSet.Write<TDE,TSwap>(os);
    00283     if( ValueLengthField.IsUndefined() )
    00284       {
    00285       const Tag itemDelItem(0xfffe,0xe00d);
    00286       itemDelItem.Write<TSwap>(os);
    00287       VL zero = 0;
    00288       zero.Write<TSwap>(os);
    00289       }
    00290
    00291     return os;
    00292   }
    00293
    00294 /*
    00295 There are three special SQ related Data Elements that are not ruled by the VR encoding rules conveyed
    00296 by the Transfer Syntax. They shall be encoded as Implicit VR. These special Data Elements are Item
    00297 (FFFE,E000), Item Delimitation Item (FFFE,E00D), and Sequence Delimitation Item (FFFE,E0DD).
    00298 However, the Data Set within the Value Field of the Data Element Item (FFFE,E000) shall be encoded
    00299 according to the rules conveyed by the Transfer Syntax.
    00300 */
    00301   bool FindDataElement(const Tag &t) const {
    00302     return NestedDataSet.FindDataElement( t );
    00303   }
    00304
    00305 private:
    00306   /* NESTED DATA SET  a Data Set contained within a Data Element of an other Data Set.
    00307    * May be nested recursively.
    00308    * Only Data Elements with VR = SQ  may, themselves, contain Data Sets
    00309    */
    00310   DataSet NestedDataSet;
    00311 };
    00312 //-----------------------------------------------------------------------------
    00313 inline std::ostream& operator<<(std::ostream& os, const Item &val)
    00314 {
    00315   os << val.TagField;
    00316   os << "\t" << val.ValueLengthField << "\n";
    00317   val.NestedDataSet.Print( os, "\t" );
    00318
    00319   return os;
    00320 }
    00321
    00322
    00323 } // end namespace gdcm
    00324
    00325 #include "gdcmItem.txx"
    00326
    00327 #endif //__gdcmItem_h