4 #include "gdcmElValSet.h"
8 gdcmElValSet::~gdcmElValSet() {
9 for (TagElValueHT::iterator tag = tagHt.begin(); tag != tagHt.end(); ++tag) {
10 gdcmElValue* EntryToDelete = tag->second;
15 // Since Add() adds symetrical in both tagHt and NameHt we can
16 // assume all the pointed gdcmElValues are already cleaned-up when
22 * \ingroup gdcmElValSet
27 void gdcmElValSet::Add(gdcmElValue * newElValue) {
28 tagHt [newElValue->GetKey()] = newElValue;
29 NameHt[newElValue->GetName()] = newElValue;
31 // WARNING : push_bash in listElem ONLY during ParseHeader
32 // TODO : something to allow further Elements addition
33 // position to be taken care of !
34 listElem.push_back(newElValue);
38 * \ingroup gdcmElValSet
39 * \brief Checks if a given Dicom element exists
45 int gdcmElValSet::CheckIfExistByNumber(guint16 Group, guint16 Elem ) {
46 std::string key = TranslateToKey(Group, Elem );
47 return (tagHt.count(key));
51 * \ingroup gdcmElValSet
54 void gdcmElValSet::Print(std::ostream & os) {
57 unsigned short int g, e;
60 gdcmTS * ts = gdcmGlobal::GetTS();
62 std::cout << "------------- using tagHt ---------------------" << std::endl;
64 for (TagElValueHT::iterator tag = tagHt.begin();
67 g = tag->second->GetGroup();
68 e = tag->second->GetElement();
69 v = tag->second->GetValue();
70 o = tag->second->GetOffset();
71 d2 = _CreateCleanString(v); // replace non printable characters by '.'
73 os << tag->first << ": ";
74 os << " lgr : " << tag->second->GetLength();
75 os << ", Offset : " << o;
76 os << " x(" << std::hex << o << std::dec << ") ";
77 os << "\t[" << tag->second->GetVR() << "]";
78 os << "\t[" << tag->second->GetName() << "]";
79 os << "\t[" << d2 << "]";
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) << "]";
87 if ( (e == 0x0016) || (e == 0x1150) )
88 os << " ==>\t[" << ts->GetValue(v) << "]";
94 std::cout << "------------ using listElem -------------------" << std::endl;
97 char greltag[10]; //group element tag
99 for (ListTag::iterator i = listElem.begin();
102 g = (*i)->GetGroup();
103 e = (*i)->GetElement();
104 v = (*i)->GetValue();
105 o = (*i)->GetOffset();
106 sprintf(greltag,"%04x|%04x",g,e);
107 d2 = _CreateCleanString(v); // replace non printable characters by '.'
108 os << greltag << ": lgth : ";
109 lgth = (*i)->GetReadLength();
110 if ( lgth == 0xffffffff)
111 os << std::hex << lgth << std::dec ;
114 os << ", Offset : " << o;
115 os << " x(" << std::hex << o << std::dec << ") ";
116 os << "\t[" << (*i)->GetVR() << "]";
117 os << "\t[" << (*i)->GetName() << "]";
118 os << "\t[" << d2 << "]";
120 // Display the UID value (instead of displaying the rough code)
121 if (g == 0x0002) { // Any more to be displayed ?
122 if ( (e == 0x0010) || (e == 0x0002) )
123 os << " ==>\t[" << ts->GetValue(v) << "]";
126 if ( (e == 0x0016) || (e == 0x1150) )
127 os << " ==>\t[" << ts->GetValue(v) << "]";
135 * \ingroup gdcmElValSet
138 void gdcmElValSet::PrintByName(std::ostream & os) {
139 for (TagElValueNameHT::iterator tag = NameHt.begin();
142 os << tag->first << ": ";
143 os << "[" << tag->second->GetValue() << "]";
144 os << "[" << tag->second->GetKey() << "]";
145 os << "[" << tag->second->GetVR() << "]" << std::endl;
150 * \ingroup gdcmElValSet
156 gdcmElValue* gdcmElValSet::GetElementByNumber(guint16 group, guint16 element) {
157 TagKey key = gdcmDictEntry::TranslateToKey(group, element);
158 if ( ! tagHt.count(key))
159 return (gdcmElValue*)0;
160 return tagHt.find(key)->second;
164 * \ingroup gdcmElValSet
168 gdcmElValue* gdcmElValSet::GetElementByName(std::string TagName) {
169 if ( ! NameHt.count(TagName))
170 return (gdcmElValue*)0;
171 return NameHt.find(TagName)->second;
175 * \ingroup gdcmElValSet
181 std::string gdcmElValSet::GetElValueByNumber(guint16 group, guint16 element) {
182 TagKey key = gdcmDictEntry::TranslateToKey(group, element);
183 if ( ! tagHt.count(key))
185 return tagHt.find(key)->second->GetValue();
189 * \ingroup gdcmElValSet
193 std::string gdcmElValSet::GetElValueByName(std::string TagName) {
194 if ( ! NameHt.count(TagName))
196 return NameHt.find(TagName)->second->GetValue();
200 * \ingroup gdcmElValSet
207 int gdcmElValSet::SetElValueByNumber(std::string content,
208 guint16 group, guint16 element) {
209 TagKey key = gdcmDictEntry::TranslateToKey(group, element);
210 if ( ! tagHt.count(key))
212 int l = content.length();
213 if(l%2) { // Odd length are padded with a space (020H).
215 content = content + '\0';
217 tagHt[key]->SetValue(content);
219 std::string vr = tagHt[key]->GetVR();
222 if( (vr == "US") || (vr == "SS") )
224 else if( (vr == "UL") || (vr == "SL") )
228 tagHt[key]->SetLength(lgr);
233 * \ingroup gdcmElValSet
239 int gdcmElValSet::SetElValueByName(std::string content, std::string TagName) {
240 if ( ! NameHt.count(TagName))
242 int l = content.length();
243 if(l%2) { // Odd length are padded with a space (020H).
245 // Well. I know that '/0' is NOT a space
246 // but it doesn't work with a space.
247 // Use hexedit and see 0002|0010 value (Transfer Syntax UID)
248 content = content + '\0';
250 NameHt[TagName]->SetValue(content);
252 std::string vr = NameHt[TagName]->GetVR();
255 if( (vr == "US") || (vr == "SS") )
257 else if( (vr == "UL") || (vr == "SL") )
260 lgr = content.length();
262 // TODO : WARNING: le cas de l'element des pixels (7fe0,0010) n'est pas traite
263 // par SetElValueByName
264 // il faudra utiliser SetElValueByNumber
266 NameHt[TagName]->SetLength(lgr);
271 * \ingroup gdcmElValSet
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 gdcmElValSet::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 gdcmElValSet
294 int gdcmElValSet::SetVoidAreaByNumber(void * area,
295 guint16 group, guint16 element) {
296 TagKey key = gdcmDictEntry::TranslateToKey(group, element);
297 if ( ! tagHt.count(key))
299 tagHt[key]->SetVoidArea(area);
304 * \ingroup gdcmElValSet
309 * @return int acts as a boolean
311 int gdcmElValSet::SetElValueLengthByNumber(guint32 length,
312 guint16 group, guint16 element) {
313 TagKey key = gdcmDictEntry::TranslateToKey(group, element);
314 if ( ! tagHt.count(key))
316 if (length%2) length++; // length must be even
317 tagHt[key]->SetLength(length);
321 * \ingroup gdcmElValSet
327 int gdcmElValSet::SetElValueLengthByName(guint32 length, std::string TagName) {
328 if ( ! NameHt.count(TagName))
330 if (length%2) length++; // length must be even
331 NameHt.find(TagName)->second->SetLength(length);
336 * \ingroup gdcmElValSet
337 * \brief Re-computes the length of a ACR-NEMA/Dicom group from a DcmHeader
338 * @param SkipSequence TRUE if we don't want to write Sequences (ACR-NEMA Files)
341 void gdcmElValSet::UpdateGroupLength(bool SkipSequence, FileType type) {
347 std::string str_trash;
350 GroupHT groupHt; // to hold the length of each group
353 // typedef std::map<GroupKey, int> GroupHT;
357 // for each Tag in the DCM Header
359 for (TagElValueHT::iterator tag2 = tagHt.begin();
364 gr = elem->GetGroup();
365 el = elem->GetElement();
368 sprintf(trash, "%04x", gr);
369 key = trash; // generate 'group tag'
371 // if the caller decided not to take SEQUENCEs into account
372 // e.g : he wants to write an ACR-NEMA File
374 if (SkipSequence && vr == "SQ") continue;
376 // Still unsolved problem :
377 // we cannot find the 'Sequence Delimitation Item'
378 // since it's at the end of the Hash Table
381 // pas SEQUENCE en ACR-NEMA
383 // --> la descente a l'interieur' des SQ
384 // devrait etre faite avec une liste chainee, pas avec une HTable...
386 if ( groupHt.count(key) == 0) { // we just read the first elem of a given group
387 if (el == 0x0000) { // the first elem is 0x0000
388 groupHt[key] = 0; // initialize group length
390 groupHt[key] = 2 + 2 + 4 + elem->GetLength(); // non 0x0000 first group elem
392 } else { // any elem but the first
393 if (type == ExplicitVR) {
394 if ( (vr == "OB") || (vr == "OW") || (vr == "SQ") ) {
395 groupHt[key] += 4; // explicit VR AND OB, OW, SQ : 4 more bytes
398 groupHt[key] += 2 + 2 + 4 + elem->GetLength();
402 unsigned short int gr_bid;
404 for (GroupHT::iterator g = groupHt.begin(); // for each group we found
407 // FIXME: g++ -Wall -Wstrict-prototypes reports on following line:
408 // warning: unsigned int format, different type arg
409 sscanf(g->first.c_str(),"%x",&gr_bid);
410 tk = g->first + "|0000"; // generate the element full tag
412 if ( tagHt.count(tk) == 0) { // if element 0x0000 not found
413 gdcmDictEntry * tagZ = new gdcmDictEntry(gr_bid, 0x0000, "UL");
414 elemZ = new gdcmElValue(tagZ);
416 Add(elemZ); // create it
418 elemZ=GetElementByNumber(gr_bid, 0x0000);
420 sprintf(trash ,"%d",g->second);
422 elemZ->SetValue(str_trash);
427 * \ingroup gdcmElValSet
428 * \brief writes on disc according to the requested format
429 * \ (ACR-NEMA, DICOM, RAW) the image
430 * \ warning does NOT add the missing elements in the header :
431 * \ it's up to the user doing it !
432 * \ (function CheckHeaderCoherence to be written)
433 * @param type type of the File to be written
434 * (ACR-NEMA, DICOM, RAW)
435 * @param _fp already open file pointer
438 void gdcmElValSet::WriteElements(FileType type, FILE * _fp) {
446 std::vector<std::string> tokens;
448 // TODO : use listElem to iterate, not TagHt!
449 // pb : gdcmElValSet.Add does NOT update listElem
450 // find a trick in STL to do it, at low cost !
454 // Tout ceci ne marche QUE parce qu'on est sur un proc Little Endian
455 // restent a tester les echecs en ecriture (apres chaque fwrite)
457 for (TagElValueHT::iterator tag2=tagHt.begin();
461 gr = tag2->second->GetGroup();
462 el = tag2->second->GetElement();
463 lgr = tag2->second->GetLength();
464 val = tag2->second->GetValue().c_str();
465 vr = tag2->second->GetVR();
467 // std::cout << "Tag "<< std::hex << gr << " " << el << std::endl;
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 if (gr == 0xfffe ) continue; // ignore delimiters
476 fwrite ( &gr,(size_t)2 ,(size_t)1 ,_fp); //group
477 fwrite ( &el,(size_t)2 ,(size_t)1 ,_fp); //element
479 if ( (type == ExplicitVR) && (gr <= 0x0002) ) {
481 guint16 z=0, shortLgr;
482 fwrite (vr.c_str(),(size_t)2 ,(size_t)1 ,_fp);
484 if ( (vr == "OB") || (vr == "OW") || (vr == "SQ") ) {
485 fwrite ( &z, (size_t)2 ,(size_t)1 ,_fp);
486 fwrite ( &lgr,(size_t)4 ,(size_t)1 ,_fp);
490 fwrite ( &shortLgr,(size_t)2 ,(size_t)1 ,_fp);
492 } else { // IMPLICIT VR
493 fwrite ( &lgr,(size_t)4 ,(size_t)1 ,_fp);
496 if (vr == "US" || vr == "SS") {
497 tokens.erase(tokens.begin(),tokens.end()); // clean any previous value
498 Tokenize (tag2->second->GetValue(), tokens, "\\");
499 for (unsigned int i=0; i<tokens.size();i++) {
500 val_uint16 = atoi(tokens[i].c_str());
502 fwrite ( ptr,(size_t)2 ,(size_t)1 ,_fp);
507 if (vr == "UL" || vr == "SL") {
508 tokens.erase(tokens.begin(),tokens.end()); // clean any previous value
509 Tokenize (tag2->second->GetValue(), tokens, "\\");
510 for (unsigned int i=0; i<tokens.size();i++) {
511 val_uint32 = atoi(tokens[i].c_str());
513 fwrite ( ptr,(size_t)4 ,(size_t)1 ,_fp);
518 // Pixels are never loaded in the element !
519 if ((gr == 0x7fe0) && (el == 0x0010) ) break;
521 fwrite ( val,(size_t)lgr ,(size_t)1 ,_fp); // Elem value
526 * \ingroup gdcmElValSet
532 int gdcmElValSet::Write(FILE * _fp, FileType type) {
535 // Comment pourrait-on savoir si le DcmHeader vient d'un fichier DicomV3 ou non
536 // (FileType est un champ de gdcmHeader ...)
537 // WARNING : Si on veut ecrire du DICOM V3 a partir d'un DcmHeader ACR-NEMA
539 // a moins de se livrer a un tres complique ajout des champs manquants.
540 // faire un CheckAndCorrectHeader (?)
542 if ( (type == ImplicitVR) || (type == ExplicitVR) )
543 UpdateGroupLength(false,type);
545 UpdateGroupLength(true,ACR);
547 WriteElements(type, _fp);