]> Creatis software - gdcm.git/blob - src/gdcmElValSet.cxx
fonction UpdateGroupLengthNew (utilisant une HTable)
[gdcm.git] / src / gdcmElValSet.cxx
1 // gdcmElValSet.cxx
2
3 #include <sstream>
4 #include "gdcmUtil.h"
5 #include "gdcmElValSet.h"
6
7 #define DEBUG 0
8
9
10 TagElValueHT & gdcmElValSet::GetTagHt(void) {
11         return tagHt;
12 }
13
14 void gdcmElValSet::Add(gdcmElValue * newElValue) {
15         tagHt [newElValue->GetKey()]  = newElValue;
16         NameHt[newElValue->GetName()] = newElValue;
17 }
18
19 void gdcmElValSet::Print(ostream & os) {
20         for (TagElValueHT::iterator tag = tagHt.begin();
21                   tag != tagHt.end();
22                   ++tag){
23                 os << tag->first << ": ";
24                 os << "[" << tag->second->GetValue() << "]";
25                 os << "[" << tag->second->GetName()  << "]";
26                 os << "[" << tag->second->GetVR()    << "]"; 
27                 os << " lgr : " << tag->second->GetLength();
28                 os << endl;
29         }
30
31
32 void gdcmElValSet::PrintByName(ostream & os) {
33         for (TagElValueNameHT::iterator tag = NameHt.begin();
34                   tag != NameHt.end();
35                   ++tag){
36                 os << tag->first << ": ";
37                 os << "[" << tag->second->GetValue() << "]";
38                 os << "[" << tag->second->GetKey()   << "]";
39                 os << "[" << tag->second->GetVR()    << "]" << endl;
40         }
41 }
42
43 gdcmElValue* gdcmElValSet::GetElementByNumber(guint16 group, guint16 element) {
44         TagKey key = gdcmDictEntry::TranslateToKey(group, element);
45         if ( ! tagHt.count(key))
46                 return (gdcmElValue*)0;
47         return tagHt.find(key)->second;
48 }
49
50 gdcmElValue* gdcmElValSet::GetElementByName(string TagName) {
51    if ( ! NameHt.count(TagName))
52       return (gdcmElValue*)0;
53    return NameHt.find(TagName)->second;
54 }
55
56 string gdcmElValSet::GetElValueByNumber(guint16 group, guint16 element) {
57         TagKey key = gdcmDictEntry::TranslateToKey(group, element);
58         if ( ! tagHt.count(key))
59                 return "gdcm::Unfound";
60         return tagHt.find(key)->second->GetValue();
61 }
62
63 string gdcmElValSet::GetElValueByName(string TagName) {
64         if ( ! NameHt.count(TagName))
65                 return "gdcm::Unfound";
66         return NameHt.find(TagName)->second->GetValue();
67 }
68
69
70 int gdcmElValSet::SetElValueByNumber(string content,
71                                      guint16 group, guint16 element) {
72         TagKey key = gdcmDictEntry::TranslateToKey(group, element);
73         if ( ! tagHt.count(key))
74                 return 0;
75         tagHt[key]->SetValue(content);
76         tagHt[key]->SetLength(content.length());         
77         return 1;
78 }
79
80 int gdcmElValSet::SetElValueByName(string content, string TagName) {
81         if ( ! NameHt.count(TagName))
82                 return 0;
83         NameHt[TagName]->SetValue(content);
84         NameHt[TagName]->SetLength(content.length());
85         return 1;               
86 }
87
88 /**
89  * \ingroup gdcmElValSet
90  * \brief   Generate a free TagKey i.e. a TagKey that is not present
91  *          in the TagHt dictionary.
92  * @param   group The generated tag must belong to this group.  
93  * @return  The element of tag with given group which is fee.
94  */
95 guint32 gdcmElValSet::GenerateFreeTagKeyInGroup(guint16 group) {
96    for (guint32 elem = 0; elem < UINT32_MAX; elem++) {
97       TagKey key = gdcmDictEntry::TranslateToKey(group, elem);
98       if (tagHt.count(key) == 0)
99          return elem;
100    }
101    return UINT32_MAX;
102 }
103
104 int gdcmElValSet::SetElValueLengthByNumber(guint32 length,
105                                            guint16 group, guint16 element) {
106         TagKey key = gdcmDictEntry::TranslateToKey(group, element);
107         if ( ! tagHt.count(key))
108                 return 0;
109         tagHt[key]->SetLength(length);   
110         return 1 ;              
111 }
112
113
114 int gdcmElValSet::SetElValueLengthByName(guint32 length, string TagName) {
115         if ( ! NameHt.count(TagName))
116                 return 0;
117         NameHt.find(TagName)->second->SetLength(length);         
118         return 1 ;              
119 }
120
121 void gdcmElValSet::UpdateGroupLength(bool SkipSequence) {
122
123    // TODO : reecrire entierement : une HTable dans la quelle on stocke les groupes, puis leur lgr
124    // Voir juste apres
125
126         // On parcourt la table pour recalculer la longueur des 'elements 0x0000'
127         // au cas ou un tag ai été ajouté par rapport à ce qui a été lu
128         // dans l'image native
129         //
130         // cf : code IdDcmWriteFile dans libido/src/dcmwrite.c
131                                 
132         // On fait de l'implicit VR little Endian 
133         // (pour moins se fairche sur processeur INTEL)
134         // On force le TRANSFERT SYNTAX UID
135    guint16 gr, el;
136    string vr;
137    guint32 lgrCalcGroupe=0;
138    gdcmElValue *elem, *elemZ, *elemZPrec;
139    guint16 grCourant = 0;
140                                 
141         TagElValueHT::iterator tag = tagHt.begin();
142         
143         elem = tag->second;
144         gr   = elem->GetGroup();
145         el   = elem->GetElement();
146                         
147         if (el != 0x0000) {
148                 if(DEBUG)printf("ajout elem OOOO premiere fois\n");
149                 gdcmDictEntry * tagZ = new gdcmDictEntry(gr, 0x0000, "UL");
150                 elemZPrec = new gdcmElValue(tagZ);      // on le cree
151                 elemZPrec->SetLength(4);
152                 Add(elemZPrec);                         // On l'accroche à sa place
153         } else {
154                 elemZPrec = elem;
155                 if(DEBUG)printf("Pas d'ajout elem OOOO premiere fois\n");
156         }
157         lgrCalcGroupe = 0;
158         if(DEBUG)printf("init-1 lgr (%d) pour gr %04x\n",lgrCalcGroupe, gr);
159         grCourant = gr;
160         
161         for (tag = ++tagHt.begin();
162                   tag != tagHt.end();
163                   ++tag){
164                   
165                 elem = tag->second;
166                 gr = elem->GetGroup();
167                 el = elem->GetElement();
168       vr = elem->GetVR();
169
170       if (SkipSequence && vr == "SQ")  continue;
171          // pas SEQUENCE en ACR-NEMA
172          // WARNING : pb CERTAIN
173          //           si on est descendu 'a l'interieur' des SQ 
174         
175         if ( (gr != grCourant) /*&&     // On arrive sur un nv Groupe     
176                 (el != 0xfffe) */       ) {
177                             
178                         if (el != 0x0000) {
179                                 gdcmDictEntry * tagZ = new gdcmDictEntry(gr, 0x0000, "UL");
180                                 elemZ = new gdcmElValue(tagZ); // on le cree
181                                 elemZ->SetLength(4);
182                                 Add(elemZ);                     // On l'accroche à sa place 
183                                 if(DEBUG)printf("ajout elem OOOO pour gr %04x\n",gr);
184                         } else { 
185                                 elemZ=elem;
186                                 if(DEBUG)printf("maj elemZ\n");
187                         }
188                         
189                         ostringstream f;
190                         f << lgrCalcGroupe; 
191                         //sprintf(str_lgrCalcGroupe,"%d",lgrCalcGroupe);
192                         elemZPrec->SetValue(f.str());
193                         if(DEBUG)printf("ecriture lgr (%d, %s) pour gr %04x\n",lgrCalcGroupe, f.str().c_str(), grCourant);
194                         if(DEBUG)printf ("%04x %04x [%s]\n",elemZPrec->GetGroup(), elemZPrec->GetElement(),
195                                                         elemZPrec->GetValue().c_str());
196                         if(DEBUG)cout << "Addresse elemZPrec " << elemZPrec<< endl;
197                         elemZPrec=elemZ;
198                         lgrCalcGroupe = 0;
199                         grCourant     = gr;
200         // BUG :
201         // calcule lgr erronnée si ExplicitVR et VR =OB, SQ, etc
202         //      
203                         if(DEBUG)printf("init-2 lgr (%d) pour gr %04x\n",lgrCalcGroupe, gr);                    
204                 } else {                        // On n'EST PAS sur un nv Groupe
205                         lgrCalcGroupe += 2 + 2 + 4 + elem->GetLength();  // Gr + Num + Lgr + LgrElem
206                         if(DEBUG)printf("increment (%d) el %04x-->lgr (%d) pour gr %04x\n",
207                                                                 elem->GetLength(), el, lgrCalcGroupe, gr);
208                 }               
209         }
210         
211         // BUG :
212         // Ecriture incorrecte si (7FE0 0000) absent et aucun element apres groupe 7FE0 :-(
213         // A JETTER !
214         //
215 }
216
217 //
218 // Remplacera UpdateGroupLength
219 // Commite par precaution.
220 // Ne pas utiliser
221 //
222
223 void gdcmElValSet::UpdateGroupLengthNew(bool SkipSequence, FileType type) {
224    guint16 gr, el;
225    string vr;
226    
227    gdcmElValue *elem;
228    char trash[10];
229    GroupKey key;
230    GroupHT groupHt;
231    
232    for (TagElValueHT::iterator tag2 = tagHt.begin();
233         tag2 != tagHt.end();
234         ++tag2){
235
236       elem  = tag2->second;
237       gr = elem->GetGroup();
238       el = elem->GetElement();
239       vr = elem->GetVR(); 
240            
241       sprintf(trash, "%04x", gr);
242       key = trash;
243       
244       if (SkipSequence && vr == "SQ") continue;
245          // pas SEQUENCE en ACR-NEMA
246          // WARNING : pb CERTAIN
247          //           si on est descendu 'a l'interieur' des SQ 
248          //
249          // --> la descente a l'interieur' des SQ 
250          // devra etre faite avec une liste chainee, pas avec une HTable...
251              
252       if ( groupHt.count(key) == 0) { 
253          groupHt[key] = 2 + 2 + 4 + 4; // creation automatique, par affectation ???
254       } else {       
255          if (type = ExplicitVR) {
256             if ( (vr == "OB") || (vr == "OW") || (vr == "SQ") ) {
257                groupHt[key] +=  4;
258             }
259          }
260          groupHt[key] += 2 + 2 + 4 + elem->GetLength(); 
261       }   
262    }
263    
264    // Liberer groupHt !
265 }
266
267
268
269 void gdcmElValSet::WriteElements(FileType type, FILE * _fp) {
270    guint16 gr, el;
271    guint32 lgr;
272    const char * val;
273    string vr;
274    guint32 val_uint32;
275    guint16 val_uint16;
276    
277    vector<string> tokens;
278
279    void *ptr;
280
281    // Tout ceci ne marche QUE parce qu'on est sur un proc Little Endian 
282    // restent à tester les echecs en écriture (apres chaque fwrite)
283
284    for (TagElValueHT::iterator tag2=tagHt.begin();
285         tag2 != tagHt.end();
286         ++tag2){
287
288       gr =  tag2->second->GetGroup();
289       el =  tag2->second->GetElement();
290       lgr = tag2->second->GetLength();
291       val = tag2->second->GetValue().c_str();
292       vr =  tag2->second->GetVR();
293       if(DEBUG)printf ("%04x %04x [%s] : [%s]\n",gr, el, vr.c_str(), val);
294
295       if ( type == ACR ) { 
296          if (gr < 0x0008) continue;
297          if (gr %2)   continue;
298          if (vr == "SQ" ) continue;
299       } 
300
301       fwrite ( &gr,(size_t)2 ,(size_t)1 ,_fp);  //group
302       fwrite ( &el,(size_t)2 ,(size_t)1 ,_fp);  //element
303
304       if ( (type == ExplicitVR) && (gr <= 0x0002) ) {
305          // On est en EXPLICIT VR
306          guint16 z=0, shortLgr;
307          fwrite (vr.c_str(),(size_t)2 ,(size_t)1 ,_fp);
308
309          if ( (vr == "OB") || (vr == "OW") || (vr == "SQ") ) {
310             fwrite ( &z,  (size_t)2 ,(size_t)1 ,_fp);
311             fwrite ( &lgr,(size_t)4 ,(size_t)1 ,_fp);
312
313          } else {
314             shortLgr=lgr;
315             fwrite ( &shortLgr,(size_t)2 ,(size_t)1 ,_fp);
316          }
317       } else {
318          fwrite ( &lgr,(size_t)4 ,(size_t)1 ,_fp);
319       }
320
321       tokens.erase(tokens.begin(),tokens.end());
322       Tokenize (tag2->second->GetValue(), tokens, "\\");
323
324       if (vr == "US" || vr == "SS") {
325          for (unsigned int i=0; i<tokens.size();i++) {
326             val_uint16 = atoi(tokens[i].c_str());
327             ptr = &val_uint16;
328             fwrite ( ptr,(size_t)2 ,(size_t)1 ,_fp);
329          }
330          continue;
331       }
332       if (vr == "UL" || vr == "SL") {
333          for (unsigned int i=0; i<tokens.size();i++) {
334             val_uint32 = atoi(tokens[i].c_str());
335             ptr = &val_uint32;
336             fwrite ( ptr,(size_t)4 ,(size_t)1 ,_fp);
337          }
338          continue;
339       }
340
341       // Les pixels ne sont pas chargés dans l'element !
342       if ((gr == 0x7fe0) && (el == 0x0010) ) break;
343
344       fwrite ( val,(size_t)lgr ,(size_t)1 ,_fp); //valeur Elem
345    }
346 }
347
348 int gdcmElValSet::Write(FILE * _fp, FileType type) {
349
350    if (type == ImplicitVR) {
351       string implicitVRTransfertSyntax = "1.2.840.10008.1.2";
352       SetElValueByNumber(implicitVRTransfertSyntax, 0x0002, 0x0010);
353       
354       //FIXME Refer to standards on page 21, chapter 6.2 "Value representation":
355       //      values with a VR of UI shall be padded with a single trailing null
356       //      Dans le cas suivant on doit pader manuellement avec un 0.
357       SetElValueLengthByNumber(18, 0x0002, 0x0010);
358    }
359    
360         // Question :
361         // Comment pourrait-on si le DcmHeader vient d'un fichoer DicomV3 ou non ,
362         // (FileType est un champ de gdcmHeader ...)
363         // WARNING : Si on veut ecrire du DICOM V3 a partir d'un DcmHeader ACR-NEMA
364         // no way
365         
366         
367    if (type == ExplicitVR) {
368       string explicitVRTransfertSyntax = "1.2.840.10008.1.2.1";
369       SetElValueByNumber(explicitVRTransfertSyntax, 0x0002, 0x0010);
370       // See above comment 
371       SetElValueLengthByNumber(20, 0x0002, 0x0010);
372    }
373
374    if ( (type == ImplicitVR) || (type == ExplicitVR) )
375       UpdateGroupLength();
376    if ( type == ACR)
377       UpdateGroupLength(true);
378
379    WriteElements(type, _fp);
380
381    return(1);
382 }