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