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