# gdcmSequenceOfFragments.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 GDCMSEQUENCEOFFRAGMENTS_H
    00016 #define GDCMSEQUENCEOFFRAGMENTS_H
    00017
    00018 #include "gdcmValue.h"
    00019 #include "gdcmVL.h"
    00020 #include "gdcmFragment.h"
    00021 #include "gdcmBasicOffsetTable.h"
    00022
    00023 namespace gdcm
    00024 {
    00025
    00026   // FIXME gdcmSequenceOfItems qnd gdcmSequenceOfFragments
    00027   // should be rethink (duplicate code)
    00032 class GDCM_EXPORT SequenceOfFragments : public Value
    00033 {
    00034 public:
    00035   // Typdefs:
    00036   typedef std::vector<Fragment> FragmentVector;
    00037
    00039   SequenceOfFragments():Table(),SequenceLengthField(0xFFFFFFFF) { }
    00040
    00042   VL GetLength() const {
    00043     return SequenceLengthField; }
    00045   void SetLength(VL length) {
    00046     SequenceLengthField = length;
    00047   }
    00048   void Clear();
    00049
    00051   void AddFragment(Fragment const &item);
    00052
    00053   // Compute the length of all fragments (and framents only!).
    00054   // Basically the size of the PixelData as stored (in bytes).
    00055   unsigned long ComputeByteLength() const;
    00056
    00057   // Compute the length of fragments (in bytes)+ length of tag...
    00058   // to be used for computation of Group Length
    00059   VL ComputeLength() const;
    00060
    00061   // Get the buffer
    00062   bool GetBuffer(char *buffer, unsigned long length) const;
    00063   bool GetFragBuffer(unsigned int fragNb, char *buffer, unsigned long &length) const;
    00064   unsigned int GetNumberOfFragments() const;
    00065   const Fragment& GetFragment(unsigned int num) const;
    00066
    00067   // Write the buffer of each fragment (call WriteBuffer on all Fragments, which are
    00068   // ByteValue). No Table information is written.
    00069   bool WriteBuffer(std::ostream &os) const;
    00070
    00071   const BasicOffsetTable &GetTable() const { return Table; }
    00072   BasicOffsetTable &GetTable() { return Table; }
    00073
    00074
    00075 template <typename TSwap>
    00076 std::istream& Read(std::istream &is)
    00077 {
    00078   assert( SequenceLengthField.IsUndefined() );
    00079   //if( SequenceLengthField.IsUndefined() )
    00080     {
    00081     const Tag seqDelItem(0xfffe,0xe0dd);
    00082     // First item is the basic offset table:
    00083     try
    00084       {
    00085       Table.Read<TSwap>(is);
    00086       gdcmDebugMacro( "Table: " << Table );
    00087       }
    00088     catch(...)
    00089       {
    00090       // Bug_Siemens_PrivateIconNoItem.dcm
    00091       // First thing first let's rewind
    00092       is.seekg(-4, std::ios::cur);
    00093       if ( Table.GetTag() == Tag(0xd8ff,0xe0ff) )
    00094         {
    00095         Fragment frag;
    00096         is.seekg( 8340, std::ios::cur );
    00097         char dummy[8340];
    00098         frag.SetByteValue( dummy, 8340 - Table.GetLength() - 16 );
    00099         Fragments.push_back( frag );
    00100         return is;
    00101         }
    00102       else
    00103         {
    00104         throw "Catch me if you can";
    00105         //assert(0);
    00106         }
    00107       }
    00108     // not used for now...
    00109     Fragment frag;
    00110     try
    00111       {
    00112       while( frag.Read<TSwap>(is) && frag.GetTag() != seqDelItem )
    00113         {
    00114         gdcmDebugMacro( "Frag: " << frag );
    00115         Fragments.push_back( frag );
    00116         }
    00117       assert( frag.GetTag() == seqDelItem && frag.GetVL() == 0 );
    00118       }
    00119     catch(Exception &ex)
    00120       {
    00121 #ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION
    00122       // that's ok ! In all cases the whole file was read, because Fragment::Read only fail on eof() reached
    00123       // 1. SIEMENS-JPEG-CorruptFrag.dcm is more difficult to deal with, we have a partial fragment, read
    00124       // we decide to add it anyway to the stack of fragments (eof was reached so we need to clear error bit)
    00125       if( frag.GetTag() == Tag(0xfffe,0xe000)  )
    00126         {
    00127         gdcmWarningMacro( "Pixel Data Fragment could be corrupted. Use file at own risk" );
    00128         Fragments.push_back( frag );
    00129         is.clear(); // clear the error bit
    00130         }
    00131       // 2. GENESIS_SIGNA-JPEG-CorruptFrag.dcm
    00132       else if ( frag.GetTag() == Tag(0xddff,0x00e0) )
    00133         {
    00134         assert( Fragments.size() == 1 );
    00135         const ByteValue *bv = Fragments[0].GetByteValue();
    00136         assert( (unsigned char)bv->GetPointer()[ bv->GetLength() - 1 ] == 0xfe );
    00137         // Yes this is an extra copy, this is a bug anyway, go fix YOUR code
    00138         Fragments[0].SetByteValue( bv->GetPointer(), bv->GetLength() - 1 );
    00139         gdcmWarningMacro( "JPEG Fragment length was declared with an extra byte at the end: stripped !" );
    00140         is.clear(); // clear the error bit
    00141         }
    00142       else
    00143         {
    00144         // 3. gdcm-JPEG-LossLess3a.dcm: easy case, an extra tag was found instead of terminator (eof is the next char)
    00145         gdcmWarningMacro( "Reading failed at Tag:" << frag.GetTag() << ". Use file at own risk." << ex.what() );
    00146         }
    00147 #else
    00148       (void)ex;
    00149 #endif /* GDCM_SUPPORT_BROKEN_IMPLEMENTATION */
    00150       }
    00151     }
    00152
    00153   return is;
    00154 }
    00155
    00156 template <typename TSwap>
    00157 std::ostream const &Write(std::ostream &os) const
    00158 {
    00159   if( !Table.Write<TSwap>(os) )
    00160     {
    00161     assert(0 && "Should not happen");
    00162     return os;
    00163     }
    00164   SequenceOfFragments::FragmentVector::const_iterator it = Fragments.begin();
    00165   for(;it != Fragments.end(); ++it)
    00166     {
    00167     it->Write<TSwap>(os);
    00168     }
    00169   // seq del item is not stored, write it !
    00170   const Tag seqDelItem(0xfffe,0xe0dd);
    00171   seqDelItem.Write<TSwap>(os);
    00172   VL zero = 0;
    00173   zero.Write<TSwap>(os);
    00174
    00175   return os;
    00176 }
    00177
    00178 //#if defined(SWIGPYTHON) || defined(SWIGCSHARP) || defined(SWIGJAVA)
    00179   // For now leave it there, this does not make sense in the C++ layer
    00180   // Create a new object
    00181   static SmartPointer<SequenceOfFragments> New()
    00182   {
    00183      return new SequenceOfFragments();
    00184   }
    00185 //#endif
    00186
    00187 protected:
    00188 public:
    00189   void Print(std::ostream &os) const {
    00190     os << "SQ L= " << SequenceLengthField << "\n";
    00191     os << "Table:" << Table << "\n";
    00192     FragmentVector::const_iterator it =
    00193       Fragments.begin();
    00194     for(;it != Fragments.end(); ++it)
    00195       {
    00196       os << "  " << *it << "\n";
    00197       }
    00198     assert( SequenceLengthField.IsUndefined() );
    00199       {
    00200       const Tag seqDelItem(0xfffe,0xe0dd);
    00201       VL zero = 0;
    00202       os << seqDelItem;
    00203       os << "\t" << zero;
    00204       }
    00205   }
    00206   bool operator==(const Value &val) const
    00207     {
    00208     const SequenceOfFragments &sqf = dynamic_cast<const SequenceOfFragments&>(val);
    00209     return Table == sqf.Table &&
    00210       SequenceLengthField == sqf.SequenceLengthField &&
    00211       Fragments == sqf.Fragments;
    00212     }
    00213
    00214 private:
    00215 public:
    00216   BasicOffsetTable Table;
    00217   VL SequenceLengthField;
    00219   FragmentVector Fragments;
    00220 };
    00221
    00227 } // end namespace gdcm
    00228
    00229 #endif //GDCMSEQUENCEOFFRAGMENTS_H