]> Creatis software - gdcm.git/blob - src/gdcmElValSet.cxx
adding jpeg12 bits .h file , in libijg12.
[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 already 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  * \ingroup gdcmElValSet
39  * \brief   Checks if a given Dicom element exists
40  * \        within a ElValSet
41  * @param   Group
42  * @param   Elem
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  */
54 void gdcmElValSet::Print(ostream & os) {
55
56    size_t o;
57    short int g, e;
58    TSKey v;
59    char * d;
60    string d2;
61    gdcmTS * ts = gdcmGlobal::GetTS();
62    
63    for (TagElValueHT::iterator tag = tagHt.begin();
64            tag != tagHt.end();
65            ++tag){
66       g = tag->second->GetGroup();
67       e = tag->second->GetElement();
68       v = tag->second->GetValue();
69       o = tag->second->GetOffset();
70       d = _CreateCleanString(v);  // replace non printable characters by '.'
71       d2=d;
72                  
73       os << tag->first << ": ";
74       os << " lgr : " << tag->second->GetLength();
75       os << ", Offset : " << o;
76       os << " x(" << hex << o << dec << ") ";
77       os << "\t[" << tag->second->GetVR()    << "]";
78       os << "\t[" << tag->second->GetName()  << "]";       
79       os << "\t[" << d2 << "]";
80       
81       // Display the UID value (instead of displaying the rough code)  
82       if (g == 0x0002) {  // Some more to be displayed ?
83          if ( (e == 0x0010) || (e == 0x0002) )     
84             os << "  ==>\t[" << ts->GetValue(v) << "]";   
85       } else {
86          if (g == 0x0008) {
87             if ( (e == 0x0016) || (e == 0x1150)  )         
88                os << "  ==>\t[" << ts->GetValue(v) << "]"; 
89          }
90       }              
91       free(d);     
92       os << endl;
93    }
94
95
96 /**
97  * \ingroup gdcmElValSet
98  * \brief   
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   group 
115  * @param   element 
116  * @return  
117  */
118 gdcmElValue* gdcmElValSet::GetElementByNumber(guint16 group, guint16 element) {
119    TagKey key = gdcmDictEntry::TranslateToKey(group, element);
120    if ( ! tagHt.count(key))
121       return (gdcmElValue*)0;
122    return tagHt.find(key)->second;
123 }
124
125 /**
126  * \ingroup gdcmElValSet
127  * \brief   
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   group 
140  * @param   element 
141  * @return  
142  */
143 string gdcmElValSet::GetElValueByNumber(guint16 group, guint16 element) {
144    TagKey key = gdcmDictEntry::TranslateToKey(group, element);
145    if ( ! tagHt.count(key))
146       return "gdcm::Unfound";
147    return tagHt.find(key)->second->GetValue();
148 }
149
150 /**
151  * \ingroup gdcmElValSet
152  * \brief   
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   content
165  * @param   group 
166  * @param   element 
167  * @return  
168  */
169 int gdcmElValSet::SetElValueByNumber(string content,
170                                      guint16 group, guint16 element) {
171    TagKey key = gdcmDictEntry::TranslateToKey(group, element);
172    if ( ! tagHt.count(key))
173       return 0;
174    tagHt[key]->SetValue(content);       
175    string vr = tagHt[key]->GetVR();
176    guint32 lgr;
177
178    if( (vr == "US") || (vr == "SS") ) 
179       lgr = 2;
180    else if( (vr == "UL") || (vr == "SL") )
181       lgr = 4;
182    else
183       lgr = content.length();      
184    tagHt[key]->SetLength(lgr); 
185    return 1;
186 }
187
188 /**
189  * \ingroup gdcmElValSet
190  * \brief   
191  * @param   content
192  * @param   TagName
193  * @return  
194  */
195 int gdcmElValSet::SetElValueByName(string content, string TagName) {
196    if ( ! NameHt.count(TagName))
197       return 0;
198    NameHt[TagName]->SetValue(content);
199    string vr = NameHt[TagName]->GetVR();
200    guint32 lgr;
201
202    if( (vr == "US") || (vr == "SS") ) 
203       lgr = 2;
204    else if( (vr == "UL") || (vr == "SL") )
205       lgr = 4;     
206    else 
207       lgr = content.length();
208            
209 // TODO : WARNING: le cas de l'element des pixels (7fe0,0010) n'est pas traite
210 // par SetElValueByName
211 // il faudra utiliser SetElValueByNumber
212            
213    NameHt[TagName]->SetLength(lgr);
214    return 1;            
215 }
216
217 /**
218  * \ingroup gdcmElValSet
219  * \brief   Generate a free TagKey i.e. a TagKey that is not present
220  *          in the TagHt dictionary.
221  * @param   group The generated tag must belong to this group.  
222  * @return  The element of tag with given group which is fee.
223  */
224 guint32 gdcmElValSet::GenerateFreeTagKeyInGroup(guint16 group) {
225    for (guint32 elem = 0; elem < UINT32_MAX; elem++) {
226       TagKey key = gdcmDictEntry::TranslateToKey(group, elem);
227       if (tagHt.count(key) == 0)
228          return elem;
229    }
230    return UINT32_MAX;
231 }
232
233 /**
234  * \ingroup gdcmElValSet
235  * \brief   
236  * @param   area
237  * @param   group 
238  * @param   element 
239  * @return  
240  */
241 int gdcmElValSet::SetVoidAreaByNumber(void * area,
242                                       guint16 group, guint16 element) {
243    TagKey key = gdcmDictEntry::TranslateToKey(group, element);
244    if ( ! tagHt.count(key))
245       return 0;
246    tagHt[key]->SetVoidArea(area);        
247    return 1 ;           
248 }
249
250 /**
251  * \ingroup gdcmElValSet
252  * \brief   
253  * @param   length
254  * @param   group 
255  * @param   element 
256  * @return  int acts as a boolean
257  */
258 int gdcmElValSet::SetElValueLengthByNumber(guint32 length,
259                                            guint16 group, guint16 element) {
260    TagKey key = gdcmDictEntry::TranslateToKey(group, element);
261    if ( ! tagHt.count(key))
262       return 0;
263    tagHt[key]->SetLength(length);        
264    return 1 ;           
265 }
266 /**
267  * \ingroup gdcmElValSet
268  * \brief   
269  * @param   length
270  * @param   TagName
271  * @return  
272  */
273 int gdcmElValSet::SetElValueLengthByName(guint32 length, string TagName) {
274    if ( ! NameHt.count(TagName))
275       return 0;
276    NameHt.find(TagName)->second->SetLength(length);      
277    return 1 ;           
278 }
279
280 /**
281  * \ingroup gdcmElValSet
282  * \brief   Re-computes the length of a ACR-NEMA/Dicom group from a DcmHeader
283  * @param   SkipSequence TRUE if we don't want to write Sequences (ACR-NEMA Files)
284  * @param   type
285  */
286 void gdcmElValSet::UpdateGroupLength(bool SkipSequence, FileType type) {
287    guint16 gr, el;
288    string vr;
289    
290    gdcmElValue *elem;
291    char trash[10];
292    string str_trash;
293    
294    GroupKey key;
295    GroupHT groupHt;  // to hold the length of each group
296    TagKey tk;
297    // remember :
298    // typedef std::map<GroupKey, int> GroupHT;
299    
300    gdcmElValue *elemZ;
301   
302    // for each Tag in the DCM Header
303    
304    for (TagElValueHT::iterator tag2 = tagHt.begin(); 
305         tag2 != tagHt.end();
306         ++tag2){
307
308       elem  = tag2->second;
309       gr = elem->GetGroup();
310       el = elem->GetElement();
311       vr = elem->GetVR(); 
312                  
313       sprintf(trash, "%04x", gr);
314       key = trash;              // generate 'group tag'
315       
316       // if the caller decided not to take SEQUENCEs into account 
317       // e.g : he wants to write an ACR-NEMA File 
318                 
319       if (SkipSequence && vr == "SQ") continue;
320       
321          // Still unsolved problem :
322          // we cannot find the 'Sequence Delimitation Item'
323          // since it's at the end of the Hash Table
324          // (fffe,e0dd) 
325              
326          // pas SEQUENCE en ACR-NEMA
327          // WARNING : 
328          // --> la descente a l'interieur' des SQ 
329          // devrait etre faite avec une liste chainee, pas avec une HTable...
330             
331       if ( groupHt.count(key) == 0) { // we just read the first elem of a given group
332          if (el == 0x0000) {          // the first elem is 0x0000
333             groupHt[key] = 0;         // initialize group length 
334          } else {
335             groupHt[key] = 2 + 2 + 4 + elem->GetLength(); // non 0x0000 first group elem
336          } 
337       } else {   // any elem but the first    
338          if (type == ExplicitVR) {
339             if ( (vr == "OB") || (vr == "OW") || (vr == "SQ") ) {
340                groupHt[key] +=  4; // explicit VR AND OB, OW, SQ : 4 more bytes
341             }
342          }
343          groupHt[key] += 2 + 2 + 4 + elem->GetLength(); 
344       } 
345    }
346
347    unsigned short int gr_bid;
348   
349    for (GroupHT::iterator g = groupHt.begin(); // for each group we found
350         g != groupHt.end();
351         ++g){ 
352       // FIXME: g++ -Wall -Wstrict-prototypes reports on following line:
353       //        warning: unsigned int format, different type arg
354       sscanf(g->first.c_str(),"%x",&gr_bid);
355       tk = g->first + "|0000";                  // generate the element full tag
356                      
357       if ( tagHt.count(tk) == 0) {              // if element 0x0000 not found
358          gdcmDictEntry * tagZ = new gdcmDictEntry(gr_bid, 0x0000, "UL");       
359          elemZ = new gdcmElValue(tagZ);
360          elemZ->SetLength(4);
361          Add(elemZ);                            // create it
362       } else {
363          elemZ=GetElementByNumber(gr_bid, 0x0000);
364       }     
365       sprintf(trash ,"%d",g->second);
366       str_trash=trash;
367       elemZ->SetValue(str_trash);
368    }   
369 }
370
371 /**
372  * \ingroup gdcmElValSet
373  * \brief   
374  * @param   type
375  * @param   _fp 
376  * @return  
377  */
378 void gdcmElValSet::WriteElements(FileType type, FILE * _fp) {
379    guint16 gr, el;
380    guint32 lgr;
381    const char * val;
382    string vr;
383    guint32 val_uint32;
384    guint16 val_uint16;
385    
386    vector<string> tokens;
387
388    void *ptr;
389
390    // Tout ceci ne marche QUE parce qu'on est sur un proc Little Endian 
391    // restent à tester les echecs en écriture (apres chaque fwrite)
392
393    for (TagElValueHT::iterator tag2=tagHt.begin();
394         tag2 != tagHt.end();
395         ++tag2){
396
397       gr =  tag2->second->GetGroup();
398       el =  tag2->second->GetElement();
399       lgr = tag2->second->GetLength();
400       val = tag2->second->GetValue().c_str();
401       vr =  tag2->second->GetVR();
402       
403      // cout << "Tag "<< hex << gr << " " << el << "\n";
404
405       if ( type == ACR ) { 
406          if (gr < 0x0008)   continue; // ignore pure DICOM V3 groups
407          if (gr %2)         continue; // ignore shadow groups
408          if (vr == "SQ" )   continue; // ignore Sequences
409          if (gr == 0xfffe ) continue; // ignore delimiters
410       } 
411
412       fwrite ( &gr,(size_t)2 ,(size_t)1 ,_fp);  //group
413       fwrite ( &el,(size_t)2 ,(size_t)1 ,_fp);  //element
414
415       if ( (type == ExplicitVR) && (gr <= 0x0002) ) {
416          // EXPLICIT VR
417          guint16 z=0, shortLgr;
418          fwrite (vr.c_str(),(size_t)2 ,(size_t)1 ,_fp);
419
420          if ( (vr == "OB") || (vr == "OW") || (vr == "SQ") ) {
421             fwrite ( &z,  (size_t)2 ,(size_t)1 ,_fp);
422             fwrite ( &lgr,(size_t)4 ,(size_t)1 ,_fp);
423
424          } else {
425             shortLgr=lgr;
426             fwrite ( &shortLgr,(size_t)2 ,(size_t)1 ,_fp);
427          }
428       } else { // IMPLICIT VR
429          fwrite ( &lgr,(size_t)4 ,(size_t)1 ,_fp);
430       }
431
432       if (vr == "US" || vr == "SS") {
433          tokens.erase(tokens.begin(),tokens.end()); // clean any previous value
434          Tokenize (tag2->second->GetValue(), tokens, "\\");
435          for (unsigned int i=0; i<tokens.size();i++) {
436             val_uint16 = atoi(tokens[i].c_str());
437             ptr = &val_uint16;
438             fwrite ( ptr,(size_t)2 ,(size_t)1 ,_fp);
439          }
440          tokens.clear();
441          continue;
442       }
443       if (vr == "UL" || vr == "SL") {
444          tokens.erase(tokens.begin(),tokens.end()); // clean any previous value
445          Tokenize (tag2->second->GetValue(), tokens, "\\");
446          for (unsigned int i=0; i<tokens.size();i++) {
447             val_uint32 = atoi(tokens[i].c_str());
448             ptr = &val_uint32;
449             fwrite ( ptr,(size_t)4 ,(size_t)1 ,_fp);
450          }
451          tokens.clear();
452          continue;
453       }     
454       // Pixels are never loaded in the element !
455       if ((gr == 0x7fe0) && (el == 0x0010) ) break;
456
457       fwrite ( val,(size_t)lgr ,(size_t)1 ,_fp); // Elem value
458    }
459 }
460
461 /**
462  * \ingroup gdcmElValSet
463  * \brief   
464  * @param   _fp
465  * @param   type
466  * @return  
467  */
468 int gdcmElValSet::Write(FILE * _fp, FileType type) {
469
470    if (type == ImplicitVR) {
471       string implicitVRTransfertSyntax = "1.2.840.10008.1.2";
472       SetElValueByNumber(implicitVRTransfertSyntax, 0x0002, 0x0010);
473       
474       //FIXME Refer to standards on page 21, chapter 6.2 "Value representation":
475       //      values with a VR of UI shall be padded with a single trailing null
476       //      Dans le cas suivant on doit pader manuellement avec un 0
477       
478       SetElValueLengthByNumber(18, 0x0002, 0x0010);
479    }  
480         // Question :
481         // Comment pourrait-on savoir si le DcmHeader vient d'un fichier DicomV3 ou non ,
482         // (FileType est un champ de gdcmHeader ...)
483         // WARNING : Si on veut ecrire du DICOM V3 a partir d'un DcmHeader ACR-NEMA
484         // no way
485         
486    if (type == ExplicitVR) {
487       string explicitVRTransfertSyntax = "1.2.840.10008.1.2.1";
488       SetElValueByNumber(explicitVRTransfertSyntax, 0x0002, 0x0010);
489       // See above comment 
490       SetElValueLengthByNumber(20, 0x0002, 0x0010);
491    }
492
493    if ( (type == ImplicitVR) || (type == ExplicitVR) )
494       UpdateGroupLength(false,type);
495    if ( type == ACR)
496       UpdateGroupLength(true,ACR);
497
498    WriteElements(type, _fp);
499    return(1);
500 }