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) << "]";
85 char greltag[10]; //group element tag
87 std::cout << "------------ using listEntries ----------------" << std::endl;
90 for (ListTag::iterator i = listEntries.begin();
91 i != listEntries.end();
94 e = (*i)->GetElement();
96 o = (*i)->GetOffset();
97 sprintf(greltag,"%04x|%04x",g,e);
98 d2 = _CreateCleanString(v); // replace non printable characters by '.'
99 cout << greltag << " lg : ";
100 lgth = (*i)->GetReadLength();
101 sprintf(st,"x(%x)",lgth);
102 std::cout.setf(ios::left);
103 std::cout << setw(10-strlen(st)) << " ";
104 std::cout << st << " ";
105 std::cout.setf(ios::left);
106 std::cout << setw(8) << lgth;
107 std::cout << " Off.: ";
108 sprintf(st,"x(%x)",o);
109 std::cout << setw(10-strlen(st)) << " ";
110 std::cout << st << " ";
111 std::cout << setw(8) << o;
112 std::cout << "[" << (*i)->GetVR() << "] ";
113 std::cout.setf(ios::left);
114 std::cout << setw(66-(*i)->GetName().length()) << " ";
115 std::cout << "[" << (*i)->GetName()<< "] ";
116 std::cout << "[" << d2 << "]";
117 // Display the UID value (instead of displaying the rough code)
118 if (g == 0x0002) { // Any more to be displayed ?
119 if ( (e == 0x0010) || (e == 0x0002) )
120 std::cout << " ==>\t[" << ts->GetValue(v) << "]";
123 if ( (e == 0x0016) || (e == 0x1150) )
124 std::cout << " ==>\t[" << ts->GetValue(v) << "]";
127 std::cout << std::endl;
131 //-----------------------------------------------------------------------------
134 * \ingroup gdcmHeaderEntrySet
135 * \brief add a new Dicom Element pointer to
136 * the H Table and to the chained List
137 * @param newHeaderEntry
139 void gdcmHeaderEntrySet::Add(gdcmHeaderEntry * newHeaderEntry) {
141 // tagHT [newHeaderEntry->GetKey()] = newHeaderEntry;
143 tagHT.insert( PairHT( newHeaderEntry->GetKey(),newHeaderEntry) );
145 // WARNING : push_bash in listEntries ONLY during ParseHeader
146 // TODO : something to allow further Elements addition
147 // position to be taken care of !
148 listEntries.push_back(newHeaderEntry);
152 * \ingroup gdcmHeaderEntrySet
153 * \brief retrieves a Dicom Element (the first one) using (group, element)
154 * \ warning (group, element) IS NOT an identifier inside the Dicom Header
155 * if you think it's NOT UNIQUE, check the count number
156 * and use iterators to retrieve ALL the Dicoms Elements within
157 * a given couple (group, element)
158 * @param group Group number of the searched Dicom Element
159 * @param element Element number of the searched Dicom Element
162 gdcmHeaderEntry* gdcmHeaderEntrySet::GetHeaderEntryByNumber(guint16 group, guint16 element) {
163 TagKey key = gdcmDictEntry::TranslateToKey(group, element);
164 if ( ! tagHT.count(key))
166 return tagHT.find(key)->second;
170 * \ingroup gdcmHeaderEntrySet
171 * \brief Gets the value (string) of the target Dicom Element
172 * @param group Group number of the searched Dicom Element
173 * @param element Element number of the searched Dicom Element
176 std::string gdcmHeaderEntrySet::GetEntryByNumber(guint16 group, guint16 element) {
177 TagKey key = gdcmDictEntry::TranslateToKey(group, element);
178 if ( ! tagHT.count(key))
180 return tagHT.find(key)->second->GetValue();
184 * \ingroup gdcmHeaderEntrySet
185 * \brief Sets the value (string) of the target Dicom Element
186 * @param content string value of the Dicom Element
187 * @param group Group number of the searched Dicom Element
188 * @param element Element number of the searched Dicom Element
191 bool gdcmHeaderEntrySet::SetEntryByNumber(std::string content,
192 guint16 group, guint16 element) {
193 TagKey key = gdcmDictEntry::TranslateToKey(group, element);
194 if ( ! tagHT.count(key))
196 int l = content.length();
197 if(l%2) { // Odd length are padded with a space (020H).
199 content = content + '\0';
202 //tagHT[key]->SetValue(content);
205 TagHeaderEntryHT::iterator p2;
206 // DO NOT remove the following lines : they explain the stuff
207 //p= tagHT.equal_range(key); // get a pair of iterators first-last synonym
208 //p2=p.first; // iterator on the first synonym
209 //a=p2->second; // H Table target column (2-nd col)
212 a = ((tagHT.equal_range(key)).first)->second;
214 a-> SetValue(content);
216 //std::string vr = tagHT[key]->GetVR();
217 std::string vr = a->GetVR();
220 if( (vr == "US") || (vr == "SS") )
222 else if( (vr == "UL") || (vr == "SL") )
226 //tagHT[key]->SetLength(lgr);
232 * \ingroup gdcmHeaderEntrySet
233 * \brief Sets the value length of the Dicom Element
234 * \warning : use with caution !
236 * @param group Group number of the searched Dicom Element
237 * @param element Element number of the searched Dicom Element
240 bool gdcmHeaderEntrySet::SetEntryLengthByNumber(guint32 length,
241 guint16 group, guint16 element) {
242 TagKey key = gdcmDictEntry::TranslateToKey(group, element);
243 if ( ! tagHT.count(key))
245 if (length%2) length++; // length must be even
246 //tagHT[key]->SetLength(length);
247 ( ((tagHT.equal_range(key)).first)->second )->SetLength(length);
252 * \ingroup gdcmHeaderEntrySet
253 * \brief Sets a 'non string' value to a given Dicom Element
255 * @param group Group number of the searched Dicom Element
256 * @param element Element number of the searched Dicom Element
259 bool gdcmHeaderEntrySet::SetVoidAreaByNumber(void * area,
260 guint16 group, guint16 element) {
261 TagKey key = gdcmDictEntry::TranslateToKey(group, element);
262 if ( ! tagHT.count(key))
264 //tagHT[key]->SetVoidArea(area);
265 ( ((tagHT.equal_range(key)).first)->second )->SetVoidArea(area);
270 * \ingroup gdcmHeaderEntrySet
271 * \brief Generate a free TagKey i.e. a TagKey that is not present
272 * in the TagHt dictionary.
273 * @param group The generated tag must belong to this group.
274 * @return The element of tag with given group which is fee.
276 guint32 gdcmHeaderEntrySet::GenerateFreeTagKeyInGroup(guint16 group) {
277 for (guint32 elem = 0; elem < UINT32_MAX; elem++) {
278 TagKey key = gdcmDictEntry::TranslateToKey(group, elem);
279 if (tagHT.count(key) == 0)
286 * \ingroup gdcmHeaderEntrySet
287 * \brief Checks if a given Dicom Element exists
288 * \ within the H table
289 * @param group Group number of the searched Dicom Element
290 * @param element Element number of the searched Dicom Element
291 * @return number of occurences
293 int gdcmHeaderEntrySet::CheckIfExistByNumber(guint16 group, guint16 element ) {
294 std::string key = gdcmDictEntry::TranslateToKey(group, element );
295 return (tagHT.count(key));
299 // TODO to be re-written using the chained list instead of the H table
300 // so we can remove the GroupHT from the gdcmHeader
303 * \ingroup gdcmHeaderEntrySet
305 * @param _fp already open file pointer
306 * @param type type of the File to be written
307 * (ACR-NEMA, ExplicitVR, ImplicitVR)
308 * @return always "True" ?!
310 bool gdcmHeaderEntrySet::Write(FILE * _fp, FileType type) {
313 // Comment pourrait-on savoir si le DcmHeader vient d'un fichier DicomV3 ou non
314 // (FileType est un champ de gdcmHeader ...)
315 // WARNING : Si on veut ecrire du DICOM V3 a partir d'un DcmHeader ACR-NEMA
317 // a moins de se livrer a un tres complique ajout des champs manquants.
318 // faire un CheckAndCorrectHeader (?)
320 if ( (type == ImplicitVR) || (type == ExplicitVR) )
321 UpdateGroupLength(false,type);
323 UpdateGroupLength(true,ACR);
325 WriteEntries(type, _fp);
329 //-----------------------------------------------------------------------------
332 //-----------------------------------------------------------------------------
335 * \ingroup gdcmHeaderEntrySet
336 * \brief Re-computes the length of a ACR-NEMA/Dicom group from a DcmHeader
337 * \warning : to be re-written using the chained list instead of the H table.
338 * \todo : to be re-written using the chained list instead of the H table
339 * @param SkipSequence TRUE if we don't want to write Sequences (ACR-NEMA Files)
340 * @param type Type of the File (ExplicitVR,ImplicitVR, ACR, ...)
342 void gdcmHeaderEntrySet::UpdateGroupLength(bool SkipSequence, FileType type) {
346 gdcmHeaderEntry *elem;
348 std::string str_trash;
351 GroupHT groupHt; // to hold the length of each group
354 // typedef std::map<GroupKey, int> GroupHT;
356 gdcmHeaderEntry *elemZ;
358 // for each Tag in the DCM Header
360 for (TagHeaderEntryHT::iterator tag2 = tagHT.begin();
365 gr = elem->GetGroup();
366 el = elem->GetElement();
369 sprintf(trash, "%04x", gr);
370 key = trash; // generate 'group tag'
372 // if the caller decided not to take SEQUENCEs into account
373 // e.g : he wants to write an ACR-NEMA File
375 if (SkipSequence && vr == "SQ") continue;
377 // Still unsolved problem :
378 // we cannot find the 'Sequence Delimitation Item'
379 // since it's at the end of the Hash Table
382 // pas SEQUENCE en ACR-NEMA
384 // --> la descente a l'interieur' des SQ
385 // devrait etre faite avec une liste chainee, pas avec une HTable...
387 if ( groupHt.count(key) == 0) { // we just read the first elem of a given group
388 if (el == 0x0000) { // the first elem is 0x0000
389 groupHt[key] = 0; // initialize group length
391 groupHt[key] = 2 + 2 + 4 + elem->GetLength(); // non 0x0000 first group elem
393 } else { // any elem but the first
394 if (type == ExplicitVR) {
395 if ( (vr == "OB") || (vr == "OW") || (vr == "SQ") ) {
396 groupHt[key] += 4; // explicit VR AND OB, OW, SQ : 4 more bytes
399 groupHt[key] += 2 + 2 + 4 + elem->GetLength();
403 unsigned short int gr_bid;
405 for (GroupHT::iterator g = groupHt.begin(); // for each group we found
408 // FIXME: g++ -Wall -Wstrict-prototypes reports on following line:
409 // warning: unsigned int format, different type arg
410 sscanf(g->first.c_str(),"%x",&gr_bid);
411 tk = g->first + "|0000"; // generate the element full tag
413 if ( tagHT.count(tk) == 0) { // if element 0x0000 not found
414 gdcmDictEntry * tagZ = new gdcmDictEntry(gr_bid, 0x0000, "UL");
415 elemZ = new gdcmHeaderEntry(tagZ);
417 Add(elemZ); // create it
419 elemZ=GetHeaderEntryByNumber(gr_bid, 0x0000);
421 sprintf(trash ,"%d",g->second);
423 elemZ->SetValue(str_trash);
428 * \ingroup gdcmHeaderEntrySet
429 * \brief writes on disc according to the requested format
430 * \ (ACR-NEMA, ExplicitVR, ImplicitVR) the image
431 * \ warning does NOT add the missing elements in the header :
432 * \ it's up to the user doing it !
433 * \ (function CheckHeaderCoherence to be written)
434 * @param type type of the File to be written
435 * (ACR-NEMA, ExplicitVR, ImplicitVR)
436 * @param _fp already open file pointer
439 void gdcmHeaderEntrySet::WriteEntries(FileType type, FILE * _fp) {
447 std::vector<std::string> tokens;
449 // TODO : use listEntries to iterate, not TagHt!
450 // pb : gdcmHeaderEntrySet.Add does NOT update listEntries
451 // find a trick in STL to do it, at low cost !
455 // Tout ceci ne marche QUE parce qu'on est sur un proc Little Endian
456 // restent a tester les echecs en ecriture (apres chaque fwrite)
458 for (TagHeaderEntryHT::iterator tag2=tagHT.begin();
462 gr = tag2->second->GetGroup();
463 el = tag2->second->GetElement();
464 lgr = tag2->second->GetLength();
465 val = tag2->second->GetValue().c_str();
466 vr = tag2->second->GetVR();
469 if (gr < 0x0008) continue; // ignore pure DICOM V3 groups
470 if (gr %2) continue; // ignore shadow groups
471 if (vr == "SQ" ) continue; // ignore Sequences
472 // TODO : find a trick to *skip* the SeQuences !
473 // Not only ignore the SQ element
474 if (gr == 0xfffe ) continue; // ignore delimiters
477 fwrite ( &gr,(size_t)2 ,(size_t)1 ,_fp); //group
478 fwrite ( &el,(size_t)2 ,(size_t)1 ,_fp); //element
480 if ( (type == ExplicitVR) && (gr <= 0x0002) ) {
482 guint16 z=0, shortLgr;
483 fwrite (vr.c_str(),(size_t)2 ,(size_t)1 ,_fp);
485 if ( (vr == "OB") || (vr == "OW") || (vr == "SQ") ) {
486 fwrite ( &z, (size_t)2 ,(size_t)1 ,_fp);
487 fwrite ( &lgr,(size_t)4 ,(size_t)1 ,_fp);
491 fwrite ( &shortLgr,(size_t)2 ,(size_t)1 ,_fp);
493 } else { // IMPLICIT VR
494 fwrite ( &lgr,(size_t)4 ,(size_t)1 ,_fp);
497 if (vr == "US" || vr == "SS") {
498 tokens.erase(tokens.begin(),tokens.end()); // clean any previous value
499 Tokenize (tag2->second->GetValue(), tokens, "\\");
500 for (unsigned int i=0; i<tokens.size();i++) {
501 val_uint16 = atoi(tokens[i].c_str());
503 fwrite ( ptr,(size_t)2 ,(size_t)1 ,_fp);
508 if (vr == "UL" || vr == "SL") {
509 tokens.erase(tokens.begin(),tokens.end()); // clean any previous value
510 Tokenize (tag2->second->GetValue(), tokens, "\\");
511 for (unsigned int i=0; i<tokens.size();i++) {
512 val_uint32 = atoi(tokens[i].c_str());
514 fwrite ( ptr,(size_t)4 ,(size_t)1 ,_fp);
519 // Pixels are never loaded in the element !
520 if ((gr == 0x7fe0) && (el == 0x0010) ) break;
522 fwrite ( val,(size_t)lgr ,(size_t)1 ,_fp); // Elem value
526 //-----------------------------------------------------------------------------