]> Creatis software - gdcm.git/blob - src/gdcmHeader2.cxx
* removal of class gdcmHeaderEntrySet
[gdcm.git] / src / gdcmHeader2.cxx
1 // gdcmHeader2.cxx
2 //-----------------------------------------------------------------------------
3 #include "gdcmUtil.h"
4 #include "gdcmHeader.h"
5 #include "gdcmTS.h"
6 #ifdef GDCM_NO_ANSI_STRING_STREAM
7 #  include <strstream>
8 #  define  ostringstream ostrstream
9 # else
10 #  include <sstream>
11 #endif
12
13 #include <iomanip> // for std::ios::left, ...
14
15 //-----------------------------------------------------------------------------
16 // Print
17 /**
18  * \ingroup gdcmHeader
19  * \brief prints the Dicom Elements of the gdcmHeader
20  *        using both H table and Chained List
21  * @param   os The output stream to be written to.  
22  */
23 void gdcmHeader::Print(std::ostream & os) {
24
25    size_t o;
26    unsigned short int g, e;
27    TSKey v;
28    std::string d2;
29    gdcmTS * ts = gdcmGlobal::GetTS();
30    std::ostringstream s;
31 /*
32 // DO NOT remove this code right now.
33    
34    // Tag HT
35    s << "------------- using tagHT ---------------------" << std::endl; 
36    for (TagHeaderEntryHT::iterator tag = tagHT.begin();
37            tag != tagHT.end();
38            ++tag){
39       g = tag->second->GetGroup();
40       e = tag->second->GetElement();
41       v = tag->second->GetValue();
42       o = tag->second->GetOffset();
43       d2 = _CreateCleanString(v);  // replace non printable characters by '.'
44
45       s << tag->first << ": ";
46       s << " lgr : " <<tag->second->GetLength();
47       s << ",\t Offset : " << o;
48       s << " x(" << std::hex << o << std::dec << ") ";
49       s << "\t[" << tag->second->GetVR()    << "]";
50       s << "\t[" << tag->second->GetName()  << "]";       
51       s << "\t[" << d2 << "]";
52
53       // Display the UID value (instead of displaying the rough code)  
54       if (g == 0x0002) {  // Some more to be displayed ?
55          if ( (e == 0x0010) || (e == 0x0002) )     
56             s << "  ==>\t[" << ts->GetValue(v) << "]";   
57       } else {
58          if (g == 0x0008) {
59             if ( (e == 0x0016) || (e == 0x1150)  )         
60                s << "  ==>\t[" << ts->GetValue(v) << "]"; 
61          }
62       }              
63       s << std::endl;
64    }
65 */         
66            
67    // List element
68    guint32 lgth;
69    char greltag[10];  //group element tag
70  
71    s << "------------ using listEntries ----------------" << std::endl; 
72
73    char st[11];
74    for (ListTag::iterator i = listEntries.begin();  
75            i != listEntries.end();
76            ++i){
77       g = (*i)->GetGroup();
78       e = (*i)->GetElement();
79       v = (*i)->GetValue();
80       o = (*i)->GetOffset();
81       sprintf(greltag,"%04x|%04x ",g,e);           
82       d2 = _CreateCleanString(v);  // replace non printable characters by '.'
83       s << greltag ;
84           
85       if (printLevel>=2) { 
86          s << "lg : ";
87          lgth = (*i)->GetReadLength();
88          if (lgth == 0xffffffff) {
89             sprintf(st,"x(%ff)");
90             s.setf(std::ios::left);
91             s << std::setw(10-strlen(st)) << " ";  
92             s << st << " ";
93             s.setf(std::ios::left);
94             s << std::setw(8) << "-1";      
95          } else {
96             sprintf(st,"x(%x)",lgth);
97             s.setf(std::ios::left);
98             s << std::setw(10-strlen(st)) << " ";  
99             s << st << " ";
100             s.setf(std::ios::left);
101             s << std::setw(8) << lgth; 
102          }
103          s << " Off.: ";
104          sprintf(st,"x(%x)",o); 
105          s << std::setw(10-strlen(st)) << " ";       
106          s << st << " ";
107          s << std::setw(8) << o; 
108       }
109       if (printLevel>=1) {      
110          s << "[" << (*i)->GetVR()  << "] ";
111          s.setf(std::ios::left);
112          s << std::setw(66-(*i)->GetName().length()) << " ";             
113       } 
114         
115       s << "[" << (*i)->GetName()<< "]";       
116       s << " [" << d2 << "]";
117        // Display the UID value (instead of displaying the rough code)  
118       if (g == 0x0002) {  // Any more to be displayed ?
119          if ( (e == 0x0010) || (e == 0x0002) )     
120             s << "  ==>\t[" << ts->GetValue(v) << "]";   
121       } else {
122          if (g == 0x0008) {
123             if ( (e == 0x0016) || (e == 0x1150)  )         
124                s << "  ==>\t[" << ts->GetValue(v) << "]"; 
125          }
126       } 
127       if (e == 0x0000) {        // elem 0x0000 --> group length 
128          if (v == "4294967295") // to avoid troubles in convertion 
129             sprintf (st," x(ffffffff)");
130          else   
131             sprintf(st," x(%08x)",atoi(v.c_str()));
132          s << st;
133       }                     
134       s << std::endl;
135    } 
136    os<<s.str();
137
138
139 //-----------------------------------------------------------------------------
140 // Public
141 /**
142  * \ingroup gdcmHeader
143  * \brief  add a new Dicom Element pointer to 
144  *         the H Table and to the chained List
145  * \warning  push_bash in listEntries ONLY during ParseHeader
146  * \todo  something to allow further Elements addition,
147  * \      when position to be taken care of     
148  * @param   newHeaderEntry
149  */
150 void gdcmHeader::Add(gdcmHeaderEntry * newHeaderEntry) {
151
152 // tagHT [newHeaderEntry->GetKey()]  = newHeaderEntry;
153    tagHT.insert( PairHT( newHeaderEntry->GetKey(),newHeaderEntry) );
154    listEntries.push_back(newHeaderEntry); 
155    wasUpdated = 1;
156 }
157
158
159 /**
160  * \ingroup gdcmHeader
161  * \brief   Sets a 'non string' value to a given Dicom Element
162  * @param   area
163  * @param   group Group number of the searched Dicom Element 
164  * @param   element Element number of the searched Dicom Element 
165  * @return  
166  */
167 bool gdcmHeader::SetVoidAreaByNumber(void * area,
168                                       guint16 group, guint16 element) {
169    TagKey key = gdcmDictEntry::TranslateToKey(group, element);
170    if ( ! tagHT.count(key))
171       return false;
172    //tagHT[key]->SetVoidArea(area);
173    ( ((tagHT.equal_range(key)).first)->second )->SetVoidArea(area);      
174    return true ;                
175 }
176
177 /**
178  * \ingroup gdcmHeader
179  * \brief   Generate a free TagKey i.e. a TagKey that is not present
180  *          in the TagHt dictionary.
181  * @param   group The generated tag must belong to this group.  
182  * @return  The element of tag with given group which is fee.
183  */
184 guint32 gdcmHeader::GenerateFreeTagKeyInGroup(guint16 group) {
185    for (guint32 elem = 0; elem < UINT32_MAX; elem++) {
186       TagKey key = gdcmDictEntry::TranslateToKey(group, elem);
187       if (tagHT.count(key) == 0)
188          return elem;
189    }
190    return UINT32_MAX;
191 }
192
193 //-----------------------------------------------------------------------------
194 // Protected
195
196 //-----------------------------------------------------------------------------
197 // Private
198 /**
199  * \ingroup gdcmHeader
200  * \brief   Re-computes the length of a ACR-NEMA/Dicom group from a DcmHeader
201  * \warning : to be re-written using the chained list instead of the H table.
202  * \warning : DO NOT use (doesn't work any longer because of the multimap)
203  * \todo : to be re-written using the chained list instead of the H table
204  * @param   SkipSequence TRUE if we don't want to write Sequences (ACR-NEMA Files)
205  * @param   type Type of the File (ExplicitVR,ImplicitVR, ACR, ...) 
206  */
207 void gdcmHeader::UpdateGroupLength(bool SkipSequence, FileType type) {
208    guint16 gr, el;
209    std::string vr;
210    
211    gdcmHeaderEntry *elem;
212    char trash[10];
213    std::string str_trash;
214    
215    GroupKey key;
216    GroupHT groupHt;  // to hold the length of each group
217    TagKey tk;
218    // remember :
219    // typedef std::map<GroupKey, int> GroupHT;
220    
221    gdcmHeaderEntry *elemZ;
222   
223    // for each Tag in the DCM Header
224    
225    for (TagHeaderEntryHT::iterator tag2 = tagHT.begin(); 
226         tag2 != tagHT.end();
227         ++tag2){
228
229       elem  = tag2->second;
230       gr = elem->GetGroup();
231       el = elem->GetElement();
232       vr = elem->GetVR(); 
233                  
234       sprintf(trash, "%04x", gr);
235       key = trash;              // generate 'group tag'
236       
237       // if the caller decided not to take SEQUENCEs into account 
238       // e.g : he wants to write an ACR-NEMA File 
239                 
240       if (SkipSequence && vr == "SQ") continue;
241       
242          // Still unsolved problem :
243          // we cannot find the 'Sequence Delimitation Item'
244          // since it's at the end of the Hash Table
245          // (fffe,e0dd) 
246              
247          // pas SEQUENCE en ACR-NEMA
248          // WARNING : 
249          // --> la descente a l'interieur' des SQ 
250          // devrait etre faite avec une liste chainee, pas avec une HTable...
251             
252       if ( groupHt.count(key) == 0) { // we just read the first elem of a given group
253          if (el == 0x0000) {          // the first elem is 0x0000
254             groupHt[key] = 0;         // initialize group length 
255          } else {
256             groupHt[key] = 2 + 2 + 4 + elem->GetLength(); // non 0x0000 first group elem
257          } 
258       } else {   // any elem but the first    
259          if (type == ExplicitVR) {
260             if ( (vr == "OB") || (vr == "OW") || (vr == "SQ") ) {
261                groupHt[key] +=  4; // explicit VR AND OB, OW, SQ : 4 more bytes
262             }
263          }
264          groupHt[key] += 2 + 2 + 4 + elem->GetLength(); 
265       } 
266    }
267
268    unsigned short int gr_bid;
269   
270    for (GroupHT::iterator g = groupHt.begin(); // for each group we found
271         g != groupHt.end();
272         ++g){ 
273       // FIXME: g++ -Wall -Wstrict-prototypes reports on following line:
274       //        warning: unsigned int format, different type arg
275       sscanf(g->first.c_str(),"%x",&gr_bid);
276       tk = g->first + "|0000";                  // generate the element full tag
277                      
278       if ( tagHT.count(tk) == 0) {              // if element 0x0000 not found
279          gdcmDictEntry * tagZ = new gdcmDictEntry(gr_bid, 0x0000, "UL");       
280          elemZ = new gdcmHeaderEntry(tagZ);
281          elemZ->SetLength(4);
282          Add(elemZ);                            // create it
283       } else {
284          elemZ=GetHeaderEntryByNumber(gr_bid, 0x0000);
285       }     
286       sprintf(trash ,"%d",g->second);
287       str_trash=trash;
288       elemZ->SetValue(str_trash);
289    }   
290 }
291
292 /**
293  * \ingroup gdcmHeader
294  * \brief   writes on disc according to the requested format
295  * \        (ACR-NEMA, ExplicitVR, ImplicitVR) the image
296  * \ warning does NOT add the missing elements in the header :
297  * \         it's up to the user doing it !
298  * \         (function CheckHeaderCoherence to be written)
299  * @param   type type of the File to be written 
300  *          (ACR-NEMA, ExplicitVR, ImplicitVR)
301  * @param   _fp already open file pointer
302  */
303 void gdcmHeader::WriteEntries(FileType type, FILE * _fp) {
304    guint16 gr, el;
305    guint32 lgr;
306    const char * val;
307    std::string vr;
308    guint32 val_uint32;
309    guint16 val_uint16;
310    
311    std::vector<std::string> tokens;
312    
313    //  uses now listEntries to iterate, not TagHt!
314    //
315    //        pb : gdcmHeader.Add does NOT update listEntries
316    //       TODO : find a trick (in STL?) to do it, at low cost !
317
318    void *ptr;
319
320    // TODO (?) tester les echecs en ecriture (apres chaque fwrite)
321
322    for (ListTag::iterator tag2=listEntries.begin();
323         tag2 != listEntries.end();
324         ++tag2){
325
326       gr =  (*tag2)->GetGroup();
327       el =  (*tag2)->GetElement();
328       lgr = (*tag2)->GetLength();
329       val = (*tag2)->GetValue().c_str();
330       vr =  (*tag2)->GetVR();
331       
332       if ( type == ACR ) { 
333          if (gr < 0x0008)   continue; // ignore pure DICOM V3 groups
334          if (gr %2)         continue; // ignore shadow groups
335          if (vr == "SQ" )   continue; // ignore Sequences
336                    // TODO : find a trick to *skip* the SeQuences !
337                    // Not only ignore the SQ element
338          if (gr == 0xfffe ) continue; // ignore delimiters
339       } 
340
341       fwrite ( &gr,(size_t)2 ,(size_t)1 ,_fp);  //group
342       fwrite ( &el,(size_t)2 ,(size_t)1 ,_fp);  //element
343
344       if ( (type == ExplicitVR) && (gr <= 0x0002) ) {
345          // EXPLICIT VR
346          guint16 z=0, shortLgr;
347          fwrite (vr.c_str(),(size_t)2 ,(size_t)1 ,_fp);
348
349          if ( (vr == "OB") || (vr == "OW") || (vr == "SQ") ) {
350             fwrite ( &z,  (size_t)2 ,(size_t)1 ,_fp);
351             fwrite ( &lgr,(size_t)4 ,(size_t)1 ,_fp);
352
353          } else {
354             shortLgr=lgr;
355             fwrite ( &shortLgr,(size_t)2 ,(size_t)1 ,_fp);
356          }
357       } else { // IMPLICIT VR
358          fwrite ( &lgr,(size_t)4 ,(size_t)1 ,_fp);
359       }
360
361       if (vr == "US" || vr == "SS") {
362          tokens.erase(tokens.begin(),tokens.end()); // clean any previous value
363          Tokenize ((*tag2)->GetValue(), tokens, "\\");
364          for (unsigned int i=0; i<tokens.size();i++) {
365             val_uint16 = atoi(tokens[i].c_str());
366             ptr = &val_uint16;
367             fwrite ( ptr,(size_t)2 ,(size_t)1 ,_fp);
368          }
369          tokens.clear();
370          continue;
371       }
372       if (vr == "UL" || vr == "SL") {
373          tokens.erase(tokens.begin(),tokens.end()); // clean any previous value
374          Tokenize ((*tag2)->GetValue(), tokens, "\\");
375          for (unsigned int i=0; i<tokens.size();i++) {
376             val_uint32 = atoi(tokens[i].c_str());
377             ptr = &val_uint32;
378             fwrite ( ptr,(size_t)4 ,(size_t)1 ,_fp);
379          }
380          tokens.clear();
381          continue;
382       }     
383       // Pixels are never loaded in the element !
384       if ((gr == 0x7fe0) && (el == 0x0010) ) break;
385
386       fwrite ( val,(size_t)lgr ,(size_t)1 ,_fp); // Elem value
387    }
388 }
389
390 //-----------------------------------------------------------------------------