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