1 // gdcmHeaderEntrySet.cxx
2 //-----------------------------------------------------------------------------
4 #include "gdcmHeaderEntrySet.h"
6 #ifdef GDCM_NO_ANSI_STRING_STREAM
8 # define ostringstream ostrstream
13 #include <iomanip> //la bibli qui va bien
15 //-----------------------------------------------------------------------------
16 // Constructor / Destructor
18 * \ingroup gdcmHeaderEntrySet
21 gdcmHeaderEntrySet::~gdcmHeaderEntrySet() {
22 for (TagHeaderEntryHT::iterator tag = tagHT.begin(); tag != tagHT.end(); ++tag) {
23 gdcmHeaderEntry* EntryToDelete = tag->second;
32 //-----------------------------------------------------------------------------
35 * \ingroup gdcmHeaderEntrySet
36 * \brief prints the Dicom Elements of the gdcmHeader
37 * using both H table and Chained List
38 * @param os The output stream to be written to.
40 void gdcmHeaderEntrySet::Print(std::ostream & os) {
43 unsigned short int g, e;
46 gdcmTS * ts = gdcmGlobal::GetTS();
51 s << "------------- using tagHT ---------------------" << std::endl;
52 for (TagHeaderEntryHT::iterator tag = tagHT.begin();
55 g = tag->second->GetGroup();
56 e = tag->second->GetElement();
57 v = tag->second->GetValue();
58 o = tag->second->GetOffset();
59 d2 = _CreateCleanString(v); // replace non printable characters by '.'
61 s << tag->first << ": ";
62 s << " lgr : " <<tag->second->GetLength();
63 s << ",\t Offset : " << o;
64 s << " x(" << std::hex << o << std::dec << ") ";
65 s << "\t[" << tag->second->GetVR() << "]";
66 s << "\t[" << tag->second->GetName() << "]";
67 s << "\t[" << d2 << "]";
69 // Display the UID value (instead of displaying the rough code)
70 if (g == 0x0002) { // Some more to be displayed ?
71 if ( (e == 0x0010) || (e == 0x0002) )
72 s << " ==>\t[" << ts->GetValue(v) << "]";
75 if ( (e == 0x0016) || (e == 0x1150) )
76 s << " ==>\t[" << ts->GetValue(v) << "]";
84 char greltag[10]; //group element tag
86 s << "------------ using listEntries ----------------" << std::endl;
89 for (ListTag::iterator i = listEntries.begin();
90 i != listEntries.end();
93 e = (*i)->GetElement();
95 o = (*i)->GetOffset();
96 sprintf(greltag,"%04x|%04x",g,e);
97 d2 = _CreateCleanString(v); // replace non printable characters by '.'
98 s << greltag << " lg : ";
99 lgth = (*i)->GetReadLength();
100 sprintf(st,"x(%x)",lgth);
101 s.setf(std::ios::left);
102 s << std::setw(10-strlen(st)) << " ";
104 s.setf(std::ios::left);
105 s << std::setw(8) << lgth;
107 sprintf(st,"x(%x)",o);
108 s << std::setw(10-strlen(st)) << " ";
110 s << std::setw(8) << o;
111 s << "[" << (*i)->GetVR() << "] ";
112 s.setf(std::ios::left);
113 s << std::setw(66-(*i)->GetName().length()) << " ";
114 s << "[" << (*i)->GetName()<< "] ";
115 s << "[" << d2 << "]";
116 // Display the UID value (instead of displaying the rough code)
117 if (g == 0x0002) { // Any more to be displayed ?
118 if ( (e == 0x0010) || (e == 0x0002) )
119 s << " ==>\t[" << ts->GetValue(v) << "]";
122 if ( (e == 0x0016) || (e == 0x1150) )
123 s << " ==>\t[" << ts->GetValue(v) << "]";
132 //-----------------------------------------------------------------------------
135 * \ingroup gdcmHeaderEntrySet
136 * \brief add a new Dicom Element pointer to
137 * the H Table and to the chained List
138 * @param newHeaderEntry
140 void gdcmHeaderEntrySet::Add(gdcmHeaderEntry * newHeaderEntry) {
142 // tagHT [newHeaderEntry->GetKey()] = newHeaderEntry;
144 tagHT.insert( PairHT( newHeaderEntry->GetKey(),newHeaderEntry) );
146 // WARNING : push_bash in listEntries ONLY during ParseHeader
147 // TODO : something to allow further Elements addition
148 // position to be taken care of !
149 listEntries.push_back(newHeaderEntry);
153 * \ingroup gdcmHeaderEntrySet
154 * \brief retrieves a Dicom Element (the first one) using (group, element)
155 * \ warning (group, element) IS NOT an identifier inside the Dicom Header
156 * if you think it's NOT UNIQUE, check the count number
157 * and use iterators to retrieve ALL the Dicoms Elements within
158 * a given couple (group, element)
159 * @param group Group number of the searched Dicom Element
160 * @param element Element number of the searched Dicom Element
163 gdcmHeaderEntry* gdcmHeaderEntrySet::GetHeaderEntryByNumber(guint16 group, guint16 element) {
164 TagKey key = gdcmDictEntry::TranslateToKey(group, element);
165 if ( ! tagHT.count(key))
167 return tagHT.find(key)->second;
171 * \ingroup gdcmHeaderEntrySet
172 * \brief Gets the value (string) of the target Dicom Element
173 * @param group Group number of the searched Dicom Element
174 * @param element Element number of the searched Dicom Element
177 std::string gdcmHeaderEntrySet::GetEntryByNumber(guint16 group, guint16 element) {
178 TagKey key = gdcmDictEntry::TranslateToKey(group, element);
179 if ( ! tagHT.count(key))
181 return tagHT.find(key)->second->GetValue();
185 * \ingroup gdcmHeaderEntrySet
186 * \brief Sets the value (string) of the target Dicom Element
187 * @param content string value of the Dicom Element
188 * @param group Group number of the searched Dicom Element
189 * @param element Element number of the searched Dicom Element
192 bool gdcmHeaderEntrySet::SetEntryByNumber(std::string content,
193 guint16 group, guint16 element) {
194 TagKey key = gdcmDictEntry::TranslateToKey(group, element);
195 if ( ! tagHT.count(key))
197 int l = content.length();
198 if(l%2) { // Odd length are padded with a space (020H).
200 content = content + '\0';
203 //tagHT[key]->SetValue(content);
206 TagHeaderEntryHT::iterator p2;
207 // DO NOT remove the following lines : they explain the stuff
208 //p= tagHT.equal_range(key); // get a pair of iterators first-last synonym
209 //p2=p.first; // iterator on the first synonym
210 //a=p2->second; // H Table target column (2-nd col)
213 a = ((tagHT.equal_range(key)).first)->second;
215 a-> SetValue(content);
217 //std::string vr = tagHT[key]->GetVR();
218 std::string vr = a->GetVR();
221 if( (vr == "US") || (vr == "SS") )
223 else if( (vr == "UL") || (vr == "SL") )
227 //tagHT[key]->SetLength(lgr);
233 * \ingroup gdcmHeaderEntrySet
234 * \brief Sets the value length of the Dicom Element
235 * \warning : use with caution !
237 * @param group Group number of the searched Dicom Element
238 * @param element Element number of the searched Dicom Element
241 bool gdcmHeaderEntrySet::SetEntryLengthByNumber(guint32 length,
242 guint16 group, guint16 element) {
243 TagKey key = gdcmDictEntry::TranslateToKey(group, element);
244 if ( ! tagHT.count(key))
246 if (length%2) length++; // length must be even
247 //tagHT[key]->SetLength(length);
248 ( ((tagHT.equal_range(key)).first)->second )->SetLength(length);
253 * \ingroup gdcmHeaderEntrySet
254 * \brief Sets a 'non string' value to a given Dicom Element
256 * @param group Group number of the searched Dicom Element
257 * @param element Element number of the searched Dicom Element
260 bool gdcmHeaderEntrySet::SetVoidAreaByNumber(void * area,
261 guint16 group, guint16 element) {
262 TagKey key = gdcmDictEntry::TranslateToKey(group, element);
263 if ( ! tagHT.count(key))
265 //tagHT[key]->SetVoidArea(area);
266 ( ((tagHT.equal_range(key)).first)->second )->SetVoidArea(area);
271 * \ingroup gdcmHeaderEntrySet
272 * \brief Generate a free TagKey i.e. a TagKey that is not present
273 * in the TagHt dictionary.
274 * @param group The generated tag must belong to this group.
275 * @return The element of tag with given group which is fee.
277 guint32 gdcmHeaderEntrySet::GenerateFreeTagKeyInGroup(guint16 group) {
278 for (guint32 elem = 0; elem < UINT32_MAX; elem++) {
279 TagKey key = gdcmDictEntry::TranslateToKey(group, elem);
280 if (tagHT.count(key) == 0)
287 * \ingroup gdcmHeaderEntrySet
288 * \brief Checks if a given Dicom Element exists
289 * \ within the H table
290 * @param group Group number of the searched Dicom Element
291 * @param element Element number of the searched Dicom Element
292 * @return number of occurences
294 int gdcmHeaderEntrySet::CheckIfExistByNumber(guint16 group, guint16 element ) {
295 std::string key = gdcmDictEntry::TranslateToKey(group, element );
296 return (tagHT.count(key));
300 // TODO to be re-written using the chained list instead of the H table
301 // so we can remove the GroupHT from the gdcmHeader
304 * \ingroup gdcmHeaderEntrySet
306 * @param _fp already open file pointer
307 * @param type type of the File to be written
308 * (ACR-NEMA, ExplicitVR, ImplicitVR)
309 * @return always "True" ?!
311 bool gdcmHeaderEntrySet::Write(FILE * _fp, FileType type) {
314 // Comment pourrait-on savoir si le DcmHeader vient d'un fichier DicomV3 ou non
315 // (FileType est un champ de gdcmHeader ...)
316 // WARNING : Si on veut ecrire du DICOM V3 a partir d'un DcmHeader ACR-NEMA
318 // a moins de se livrer a un tres complique ajout des champs manquants.
319 // faire un CheckAndCorrectHeader (?)
321 if ( (type == ImplicitVR) || (type == ExplicitVR) )
322 UpdateGroupLength(false,type);
324 UpdateGroupLength(true,ACR);
326 WriteEntries(type, _fp);
330 //-----------------------------------------------------------------------------
333 //-----------------------------------------------------------------------------
336 * \ingroup gdcmHeaderEntrySet
337 * \brief Re-computes the length of a ACR-NEMA/Dicom group from a DcmHeader
338 * \warning : to be re-written using the chained list instead of the H table.
339 * \todo : to be re-written using the chained list instead of the H table
340 * @param SkipSequence TRUE if we don't want to write Sequences (ACR-NEMA Files)
341 * @param type Type of the File (ExplicitVR,ImplicitVR, ACR, ...)
343 void gdcmHeaderEntrySet::UpdateGroupLength(bool SkipSequence, FileType type) {
347 gdcmHeaderEntry *elem;
349 std::string str_trash;
352 GroupHT groupHt; // to hold the length of each group
355 // typedef std::map<GroupKey, int> GroupHT;
357 gdcmHeaderEntry *elemZ;
359 // for each Tag in the DCM Header
361 for (TagHeaderEntryHT::iterator tag2 = tagHT.begin();
366 gr = elem->GetGroup();
367 el = elem->GetElement();
370 sprintf(trash, "%04x", gr);
371 key = trash; // generate 'group tag'
373 // if the caller decided not to take SEQUENCEs into account
374 // e.g : he wants to write an ACR-NEMA File
376 if (SkipSequence && vr == "SQ") continue;
378 // Still unsolved problem :
379 // we cannot find the 'Sequence Delimitation Item'
380 // since it's at the end of the Hash Table
383 // pas SEQUENCE en ACR-NEMA
385 // --> la descente a l'interieur' des SQ
386 // devrait etre faite avec une liste chainee, pas avec une HTable...
388 if ( groupHt.count(key) == 0) { // we just read the first elem of a given group
389 if (el == 0x0000) { // the first elem is 0x0000
390 groupHt[key] = 0; // initialize group length
392 groupHt[key] = 2 + 2 + 4 + elem->GetLength(); // non 0x0000 first group elem
394 } else { // any elem but the first
395 if (type == ExplicitVR) {
396 if ( (vr == "OB") || (vr == "OW") || (vr == "SQ") ) {
397 groupHt[key] += 4; // explicit VR AND OB, OW, SQ : 4 more bytes
400 groupHt[key] += 2 + 2 + 4 + elem->GetLength();
404 unsigned short int gr_bid;
406 for (GroupHT::iterator g = groupHt.begin(); // for each group we found
409 // FIXME: g++ -Wall -Wstrict-prototypes reports on following line:
410 // warning: unsigned int format, different type arg
411 sscanf(g->first.c_str(),"%x",&gr_bid);
412 tk = g->first + "|0000"; // generate the element full tag
414 if ( tagHT.count(tk) == 0) { // if element 0x0000 not found
415 gdcmDictEntry * tagZ = new gdcmDictEntry(gr_bid, 0x0000, "UL");
416 elemZ = new gdcmHeaderEntry(tagZ);
418 Add(elemZ); // create it
420 elemZ=GetHeaderEntryByNumber(gr_bid, 0x0000);
422 sprintf(trash ,"%d",g->second);
424 elemZ->SetValue(str_trash);
429 * \ingroup gdcmHeaderEntrySet
430 * \brief writes on disc according to the requested format
431 * \ (ACR-NEMA, ExplicitVR, ImplicitVR) the image
432 * \ warning does NOT add the missing elements in the header :
433 * \ it's up to the user doing it !
434 * \ (function CheckHeaderCoherence to be written)
435 * @param type type of the File to be written
436 * (ACR-NEMA, ExplicitVR, ImplicitVR)
437 * @param _fp already open file pointer
440 void gdcmHeaderEntrySet::WriteEntries(FileType type, FILE * _fp) {
448 std::vector<std::string> tokens;
450 // TODO : use listEntries to iterate, not TagHt!
451 // pb : gdcmHeaderEntrySet.Add does NOT update listEntries
452 // find a trick in STL to do it, at low cost !
456 // Tout ceci ne marche QUE parce qu'on est sur un proc Little Endian
457 // restent a tester les echecs en ecriture (apres chaque fwrite)
459 for (TagHeaderEntryHT::iterator tag2=tagHT.begin();
463 gr = tag2->second->GetGroup();
464 el = tag2->second->GetElement();
465 lgr = tag2->second->GetLength();
466 val = tag2->second->GetValue().c_str();
467 vr = tag2->second->GetVR();
470 if (gr < 0x0008) continue; // ignore pure DICOM V3 groups
471 if (gr %2) continue; // ignore shadow groups
472 if (vr == "SQ" ) continue; // ignore Sequences
473 // TODO : find a trick to *skip* the SeQuences !
474 // Not only ignore the SQ element
475 if (gr == 0xfffe ) continue; // ignore delimiters
478 fwrite ( &gr,(size_t)2 ,(size_t)1 ,_fp); //group
479 fwrite ( &el,(size_t)2 ,(size_t)1 ,_fp); //element
481 if ( (type == ExplicitVR) && (gr <= 0x0002) ) {
483 guint16 z=0, shortLgr;
484 fwrite (vr.c_str(),(size_t)2 ,(size_t)1 ,_fp);
486 if ( (vr == "OB") || (vr == "OW") || (vr == "SQ") ) {
487 fwrite ( &z, (size_t)2 ,(size_t)1 ,_fp);
488 fwrite ( &lgr,(size_t)4 ,(size_t)1 ,_fp);
492 fwrite ( &shortLgr,(size_t)2 ,(size_t)1 ,_fp);
494 } else { // IMPLICIT VR
495 fwrite ( &lgr,(size_t)4 ,(size_t)1 ,_fp);
498 if (vr == "US" || vr == "SS") {
499 tokens.erase(tokens.begin(),tokens.end()); // clean any previous value
500 Tokenize (tag2->second->GetValue(), tokens, "\\");
501 for (unsigned int i=0; i<tokens.size();i++) {
502 val_uint16 = atoi(tokens[i].c_str());
504 fwrite ( ptr,(size_t)2 ,(size_t)1 ,_fp);
509 if (vr == "UL" || vr == "SL") {
510 tokens.erase(tokens.begin(),tokens.end()); // clean any previous value
511 Tokenize (tag2->second->GetValue(), tokens, "\\");
512 for (unsigned int i=0; i<tokens.size();i++) {
513 val_uint32 = atoi(tokens[i].c_str());
515 fwrite ( ptr,(size_t)4 ,(size_t)1 ,_fp);
520 // Pixels are never loaded in the element !
521 if ((gr == 0x7fe0) && (el == 0x0010) ) break;
523 fwrite ( val,(size_t)lgr ,(size_t)1 ,_fp); // Elem value
527 //-----------------------------------------------------------------------------