]> Creatis software - gdcm.git/blob - src/gdcmElValSet.cxx
Adding :
[gdcm.git] / src / gdcmElValSet.cxx
1 // gdcmElValSet.cxx
2
3 #include <sstream>
4 #include "gdcmUtil.h"
5 #include "gdcmElValSet.h"
6 #include "gdcmTS.h"
7 using namespace std;
8
9 gdcmElValSet::~gdcmElValSet() {
10    for (TagElValueHT::iterator tag = tagHt.begin(); tag != tagHt.end(); ++tag) {
11       gdcmElValue* EntryToDelete = tag->second;
12       if ( EntryToDelete )
13          delete EntryToDelete;
14    }
15    tagHt.clear();
16    // Since Add() adds symetrical in both tagHt and NameHt we can
17    // assume all the pointed gdcmElValues are allready cleaned-up when
18    // we cleaned tagHt.
19    NameHt.clear();
20 }
21
22 TagElValueHT & gdcmElValSet::GetTagHt(void) {
23         return tagHt;
24 }
25
26 /**
27  * \ingroup gdcmElValSet
28  * \brief   
29  * @param     
30  * @return  
31  */
32 void gdcmElValSet::Add(gdcmElValue * newElValue) {
33         tagHt [newElValue->GetKey()]  = newElValue;
34         NameHt[newElValue->GetName()] = newElValue;
35 }
36
37
38 /**
39  * \ingroup gdcmElValSet
40  * \brief   Checks if a given Dicom element exists
41  * \        within a ElValSet
42  * @param     
43  * @return  
44  */
45 int gdcmElValSet::CheckIfExistByNumber(guint16 Group, guint16 Elem ) {
46         string key = TranslateToKey(Group, Elem );
47         return (tagHt.count(key));
48 }
49
50 /**
51  * \ingroup gdcmElValSet
52  * \brief   
53  * @param     
54  * @return  
55  */
56  void gdcmElValSet::Print(ostream & os) {
57
58    size_t o;
59    short int g, e;
60    TSKey v;
61    char * d;
62    string d2;
63    gdcmTS * ts = gdcmGlobal::GetTS();
64    
65    for (TagElValueHT::iterator tag = tagHt.begin();
66            tag != tagHt.end();
67            ++tag){
68       g = tag->second->GetGroup();
69       e = tag->second->GetElement();
70       v = tag->second->GetValue();
71       o = tag->second->GetOffset();
72       d = _CreateCleanString(v); // TODO : trouver qq chose moins goret
73       d2=d;
74                  
75       os << tag->first << ": ";
76       //os << "[" << v << "]";
77       os << "[" << d2 << "]";
78       os << "[" << tag->second->GetName()  << "]";
79       os << "[" << tag->second->GetVR()    << "]"; 
80       
81       if ( (g == 0x0002) && (e == 0x0010) ) {      
82          os << " [" << ts->GetValue(v) << "]";   
83       }
84       
85       // liberer 'd' ici ?
86       
87       os << " lgr : " << tag->second->GetLength();
88       os << ", Offset : " << o;
89       os << " x(" << hex << o << dec << ") ";
90       os << endl;
91    }
92
93
94 /**
95  * \ingroup gdcmElValSet
96  * \brief   
97  * @param     
98  * @return  
99  */
100  void gdcmElValSet::PrintByName(ostream & os) {
101    for (TagElValueNameHT::iterator tag = NameHt.begin();
102           tag != NameHt.end();
103           ++tag){
104       os << tag->first << ": ";
105       os << "[" << tag->second->GetValue() << "]";
106       os << "[" << tag->second->GetKey()   << "]";
107       os << "[" << tag->second->GetVR()    << "]" << endl;
108    }
109 }
110
111 /**
112  * \ingroup gdcmElValSet
113  * \brief   
114  * @param     
115  * @return  
116  */
117 gdcmElValue* gdcmElValSet::GetElementByNumber(guint16 group, guint16 element) {
118    TagKey key = gdcmDictEntry::TranslateToKey(group, element);
119    if ( ! tagHt.count(key))
120       return (gdcmElValue*)0;
121    return tagHt.find(key)->second;
122 }
123
124 /**
125  * \ingroup gdcmElValSet
126  * \brief   
127  * @param     
128  * @return  
129  */
130 gdcmElValue* gdcmElValSet::GetElementByName(string TagName) {
131    if ( ! NameHt.count(TagName))
132       return (gdcmElValue*)0;
133    return NameHt.find(TagName)->second;
134 }
135
136 /**
137  * \ingroup gdcmElValSet
138  * \brief   
139  * @param     
140  * @return  
141  */
142 string gdcmElValSet::GetElValueByNumber(guint16 group, guint16 element) {
143    TagKey key = gdcmDictEntry::TranslateToKey(group, element);
144    if ( ! tagHt.count(key))
145       return "gdcm::Unfound";
146    return tagHt.find(key)->second->GetValue();
147 }
148
149 /**
150  * \ingroup gdcmElValSet
151  * \brief   
152  * @param     
153  * @return  
154  */
155 string gdcmElValSet::GetElValueByName(string TagName) {
156    if ( ! NameHt.count(TagName))
157       return "gdcm::Unfound";
158    return NameHt.find(TagName)->second->GetValue();
159 }
160
161 /**
162  * \ingroup gdcmElValSet
163  * \brief   
164  * @param     
165  * @return  
166  */
167 int gdcmElValSet::SetElValueByNumber(string content,
168                                      guint16 group, guint16 element) {
169    TagKey key = gdcmDictEntry::TranslateToKey(group, element);
170    if ( ! tagHt.count(key))
171       return 0;
172    tagHt[key]->SetValue(content);       
173    string vr = tagHt[key]->GetVR();
174    guint32 lgr;
175
176    if( (vr == "US") || (vr == "SS") ) 
177       lgr = 2;
178    else if( (vr == "UL") || (vr == "SL") )
179       lgr = 4;
180    else
181       lgr = content.length();      
182    tagHt[key]->SetLength(lgr); 
183    return 1;
184 }
185
186 /**
187  * \ingroup gdcmElValSet
188  * \brief   
189  * @param     
190  * @return  
191  */
192 int gdcmElValSet::SetElValueByName(string content, string TagName) {
193    if ( ! NameHt.count(TagName))
194       return 0;
195    NameHt[TagName]->SetValue(content);
196    string vr = NameHt[TagName]->GetVR();
197    guint32 lgr;
198
199    if( (vr == "US") || (vr == "SS") ) 
200       lgr = 2;
201    else if( (vr == "UL") || (vr == "SL") )
202       lgr = 4;     
203    else 
204       lgr = content.length();
205            
206 // TODO : WARNING: le cas de l'element des pixels (7fe0,0010) n'est pas traite
207 // par SetElValueByName
208 // il faudra utiliser SetElValueByNumber
209            
210    NameHt[TagName]->SetLength(lgr);
211    return 1;            
212 }
213
214 /**
215  * \ingroup gdcmElValSet
216  * \brief   Generate a free TagKey i.e. a TagKey that is not present
217  *          in the TagHt dictionary.
218  * @param   group The generated tag must belong to this group.  
219  * @return  The element of tag with given group which is fee.
220  */
221 guint32 gdcmElValSet::GenerateFreeTagKeyInGroup(guint16 group) {
222    for (guint32 elem = 0; elem < UINT32_MAX; elem++) {
223       TagKey key = gdcmDictEntry::TranslateToKey(group, elem);
224       if (tagHt.count(key) == 0)
225          return elem;
226    }
227    return UINT32_MAX;
228 }
229
230 /**
231  * \ingroup gdcmElValSet
232  * \brief   
233  * @param     
234  * @return  
235  */
236 int gdcmElValSet::SetElValueLengthByNumber(guint32 length,
237                                            guint16 group, guint16 element) {
238    TagKey key = gdcmDictEntry::TranslateToKey(group, element);
239    if ( ! tagHt.count(key))
240       return 0;
241    tagHt[key]->SetLength(length);        
242    return 1 ;           
243 }
244
245
246 /**
247  * \ingroup gdcmElValSet
248  * \brief   
249  * @param     
250  * @return  
251  */
252 int gdcmElValSet::SetElValueLengthByName(guint32 length, string TagName) {
253    if ( ! NameHt.count(TagName))
254       return 0;
255    NameHt.find(TagName)->second->SetLength(length);      
256    return 1 ;           
257 }
258
259
260 // re-computes the length of a ACR-NEMA/Dicom group
261 // from a DcmHeader
262
263 /**
264  * \ingroup gdcmElValSet
265  * \brief   
266  * @param     
267  * @return  
268  */
269 void gdcmElValSet::UpdateGroupLength(bool SkipSequence, FileType type) {
270    guint16 gr, el;
271    string vr;
272    
273    gdcmElValue *elem;
274    char trash[10];
275    string str_trash;
276    
277    GroupKey key;
278    GroupHT groupHt;  // to hold the length of each group
279    TagKey tk;
280    // remember :
281    // typedef std::map<GroupKey, int> GroupHT;
282    
283    gdcmElValue *elemZ;
284   
285    // for each Tag in the DCM Header
286    
287    for (TagElValueHT::iterator tag2 = tagHt.begin(); 
288         tag2 != tagHt.end();
289         ++tag2){
290
291       elem  = tag2->second;
292       gr = elem->GetGroup();
293       el = elem->GetElement();
294       vr = elem->GetVR(); 
295                  
296       sprintf(trash, "%04x", gr);
297       key = trash;              // generate 'group tag'
298       
299       // if the caller decided not to take SEQUENCEs into account 
300       // e.g : he wants to write an ACR-NEMA File 
301                 
302       if (SkipSequence && vr == "SQ") continue;
303       
304          // pas SEQUENCE en ACR-NEMA
305          // WARNING : pb CERTAIN
306          //           si on est descendu 'a l'interieur' des SQ 
307          //
308          // --> la descente a l'interieur' des SQ 
309          // devra etre faite avec une liste chainee, pas avec une HTable...
310              
311       if ( groupHt.count(key) == 0) { // we just read the first elem of a given group
312          if (el == 0x0000) {          // the first elem is 0x0000
313             groupHt[key] = 0;         // initialize group length 
314          } else {
315             groupHt[key] = 2 + 2 + 4 + elem->GetLength(); // non 0x0000 first group elem
316          } 
317       } else {   // any elem but the first    
318          if (type == ExplicitVR) {
319             if ( (vr == "OB") || (vr == "OW") || (vr == "SQ") ) {
320                groupHt[key] +=  4; // explicit VR AND OB, OW, SQ : 4 more bytes
321             }
322          }
323          groupHt[key] += 2 + 2 + 4 + elem->GetLength(); 
324       } 
325    }
326   
327      if(1) // unnormalized way to see what happened
328      for (GroupHT::iterator g = groupHt.begin();
329         g != groupHt.end();
330         ++g){        
331         printf("groupKey %s : %d\n",g->first.c_str(),g->second);
332      }
333        
334    unsigned short int gr_bid;
335   
336    for (GroupHT::iterator g = groupHt.begin(); // for each group we found
337         g != groupHt.end();
338         ++g){ 
339       // FIXME: g++ -Wall -Wstrict-prototypes reports on following line:
340       //        warning: unsigned int format, different type arg
341       sscanf(g->first.c_str(),"%x",&gr_bid);
342       tk = g->first + "|0000";                  // generate the element full tag
343                      
344       if ( tagHt.count(tk) == 0) {              // if element 0x0000 not found
345          gdcmDictEntry * tagZ = new gdcmDictEntry(gr_bid, 0x0000, "UL");       
346          elemZ = new gdcmElValue(tagZ);
347          elemZ->SetLength(4);
348          Add(elemZ);                            // create it
349       } else {
350          elemZ=GetElementByNumber(gr_bid, 0x0000);
351       }     
352       sprintf(trash ,"%d",g->second);
353       str_trash=trash;
354       elemZ->SetValue(str_trash);
355    }   
356 }
357
358 /**
359  * \ingroup gdcmElValSet
360  * \brief   
361  * @param     
362  * @return  
363  */
364 void gdcmElValSet::WriteElements(FileType type, FILE * _fp) {
365    guint16 gr, el;
366    guint32 lgr;
367    const char * val;
368    string vr;
369    guint32 val_uint32;
370    guint16 val_uint16;
371    
372    vector<string> tokens;
373
374    void *ptr;
375
376    // Tout ceci ne marche QUE parce qu'on est sur un proc Little Endian 
377    // restent à tester les echecs en écriture (apres chaque fwrite)
378
379    for (TagElValueHT::iterator tag2=tagHt.begin();
380         tag2 != tagHt.end();
381         ++tag2){
382
383       gr =  tag2->second->GetGroup();
384       el =  tag2->second->GetElement();
385       lgr = tag2->second->GetLength();
386       val = tag2->second->GetValue().c_str();
387       vr =  tag2->second->GetVR();
388
389       if ( type == ACR ) { 
390          if (gr < 0x0008) continue;
391          // if (gr %2)   continue; // pour voir
392          if (vr == "SQ" ) continue;
393       } 
394
395       fwrite ( &gr,(size_t)2 ,(size_t)1 ,_fp);  //group
396       fwrite ( &el,(size_t)2 ,(size_t)1 ,_fp);  //element
397
398       if ( (type == ExplicitVR) && (gr <= 0x0002) ) {
399          // On est en EXPLICIT VR
400          guint16 z=0, shortLgr;
401          fwrite (vr.c_str(),(size_t)2 ,(size_t)1 ,_fp);
402
403          if ( (vr == "OB") || (vr == "OW") || (vr == "SQ") ) {
404             fwrite ( &z,  (size_t)2 ,(size_t)1 ,_fp);
405             fwrite ( &lgr,(size_t)4 ,(size_t)1 ,_fp);
406
407          } else {
408             shortLgr=lgr;
409             fwrite ( &shortLgr,(size_t)2 ,(size_t)1 ,_fp);
410          }
411       } else {
412          fwrite ( &lgr,(size_t)4 ,(size_t)1 ,_fp);
413       }
414
415       tokens.erase(tokens.begin(),tokens.end());
416       Tokenize (tag2->second->GetValue(), tokens, "\\");
417
418       if (vr == "US" || vr == "SS") {
419          for (unsigned int i=0; i<tokens.size();i++) {
420             val_uint16 = atoi(tokens[i].c_str());
421             ptr = &val_uint16;
422             fwrite ( ptr,(size_t)2 ,(size_t)1 ,_fp);
423          }
424          continue;
425       }
426       if (vr == "UL" || vr == "SL") {
427          for (unsigned int i=0; i<tokens.size();i++) {
428             val_uint32 = atoi(tokens[i].c_str());
429             ptr = &val_uint32;
430             fwrite ( ptr,(size_t)4 ,(size_t)1 ,_fp);
431          }
432          continue;
433       }
434       tokens.clear();
435
436       // Les pixels ne sont pas chargés dans l'element !
437       if ((gr == 0x7fe0) && (el == 0x0010) ) break;
438
439       fwrite ( val,(size_t)lgr ,(size_t)1 ,_fp); //valeur Elem
440    }
441 }
442
443 /**
444  * \ingroup gdcmElValSet
445  * \brief   
446  * @param     
447  * @return  
448  */
449 int gdcmElValSet::Write(FILE * _fp, FileType type) {
450
451    if (type == ImplicitVR) {
452       string implicitVRTransfertSyntax = "1.2.840.10008.1.2";
453       SetElValueByNumber(implicitVRTransfertSyntax, 0x0002, 0x0010);
454       
455       //FIXME Refer to standards on page 21, chapter 6.2 "Value representation":
456       //      values with a VR of UI shall be padded with a single trailing null
457       //      Dans le cas suivant on doit pader manuellement avec un 0
458       
459       SetElValueLengthByNumber(18, 0x0002, 0x0010);
460    }  
461         // Question :
462         // Comment pourrait-on savoir si le DcmHeader vient d'un fichier DicomV3 ou non ,
463         // (FileType est un champ de gdcmHeader ...)
464         // WARNING : Si on veut ecrire du DICOM V3 a partir d'un DcmHeader ACR-NEMA
465         // no way
466         
467    if (type == ExplicitVR) {
468       string explicitVRTransfertSyntax = "1.2.840.10008.1.2.1";
469       SetElValueByNumber(explicitVRTransfertSyntax, 0x0002, 0x0010);
470       // See above comment 
471       SetElValueLengthByNumber(20, 0x0002, 0x0010);
472    }
473
474    if ( (type == ImplicitVR) || (type == ExplicitVR) )
475       UpdateGroupLength(false,type);
476    if ( type == ACR)
477       UpdateGroupLength(true,ACR);
478
479    WriteElements(type, _fp);
480    return(1);
481 }