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
21 TagElValueHT & gdcmElValSet::GetTagHt(void) {
26 ListTag & gdcmElValSet::GetListElem(void) {
31 * \ingroup gdcmElValSet
36 void gdcmElValSet::Add(gdcmElValue * newElValue) {
37 tagHt [newElValue->GetKey()] = newElValue;
38 NameHt[newElValue->GetName()] = newElValue;
40 // WARNING : push_bash in listElem ONLY during ParseHeader
41 // TODO : something to allow further Elements addition
42 // position to be taken care of !
43 listElem.push_back(newElValue);
47 * \ingroup gdcmElValSet
48 * \brief Checks if a given Dicom element exists
54 int gdcmElValSet::CheckIfExistByNumber(guint16 Group, guint16 Elem ) {
55 std::string key = TranslateToKey(Group, Elem );
56 return (tagHt.count(key));
60 * \ingroup gdcmElValSet
63 void gdcmElValSet::Print(std::ostream & os) {
69 gdcmTS * ts = gdcmGlobal::GetTS();
71 std::cout << "------------- using tagHt ----------------------------" << std::endl;
73 for (TagElValueHT::iterator tag = tagHt.begin();
76 g = tag->second->GetGroup();
77 e = tag->second->GetElement();
78 v = tag->second->GetValue();
79 o = tag->second->GetOffset();
80 d2 = _CreateCleanString(v); // replace non printable characters by '.'
82 os << tag->first << ": ";
83 os << " lgr : " << tag->second->GetLength();
84 os << ", Offset : " << o;
85 os << " x(" << std::hex << o << std::dec << ") ";
86 os << "\t[" << tag->second->GetVR() << "]";
87 os << "\t[" << tag->second->GetName() << "]";
88 os << "\t[" << d2 << "]";
90 // Display the UID value (instead of displaying the rough code)
91 if (g == 0x0002) { // Some more to be displayed ?
92 if ( (e == 0x0010) || (e == 0x0002) )
93 os << " ==>\t[" << ts->GetValue(v) << "]";
96 if ( (e == 0x0016) || (e == 0x1150) )
97 os << " ==>\t[" << ts->GetValue(v) << "]";
103 std::cout << "------------ using listElem -----------------" << std::endl;
106 char greltag[9]; //group element tag
108 for (std::list<gdcmElValue*>::iterator i = listElem.begin();
111 g = (*i)->GetGroup();
112 e = (*i)->GetElement();
113 sprintf(greltag,"%04x|%04x",g,e);
114 v = (*i)->GetValue();
115 o = (*i)->GetOffset();
116 d2 = _CreateCleanString(v); // replace non printable characters by '.'
117 os << greltag << ": lgth : ";
118 lgth = (*i)->GetReadLength();
119 if ( lgth == 0xffffffff)
120 os << std::hex << lgth << std::dec ;
123 os << ", Offset : " << o;
124 os << " x(" << std::hex << o << std::dec << ") ";
125 os << "\t[" << (*i)->GetVR() << "]";
126 os << "\t[" << (*i)->GetName() << "]";
127 os << "\t[" << d2 << "]";
129 // Display the UID value (instead of displaying the rough code)
130 if (g == 0x0002) { // Any more to be displayed ?
131 if ( (e == 0x0010) || (e == 0x0002) )
132 os << " ==>\t[" << ts->GetValue(v) << "]";
135 if ( (e == 0x0016) || (e == 0x1150) )
136 os << " ==>\t[" << ts->GetValue(v) << "]";
144 * \ingroup gdcmElValSet
147 void gdcmElValSet::PrintByName(std::ostream & os) {
148 for (TagElValueNameHT::iterator tag = NameHt.begin();
151 os << tag->first << ": ";
152 os << "[" << tag->second->GetValue() << "]";
153 os << "[" << tag->second->GetKey() << "]";
154 os << "[" << tag->second->GetVR() << "]" << std::endl;
159 * \ingroup gdcmElValSet
165 gdcmElValue* gdcmElValSet::GetElementByNumber(guint16 group, guint16 element) {
166 TagKey key = gdcmDictEntry::TranslateToKey(group, element);
167 if ( ! tagHt.count(key))
168 return (gdcmElValue*)0;
169 return tagHt.find(key)->second;
173 * \ingroup gdcmElValSet
177 gdcmElValue* gdcmElValSet::GetElementByName(std::string TagName) {
178 if ( ! NameHt.count(TagName))
179 return (gdcmElValue*)0;
180 return NameHt.find(TagName)->second;
184 * \ingroup gdcmElValSet
190 std::string gdcmElValSet::GetElValueByNumber(guint16 group, guint16 element) {
191 TagKey key = gdcmDictEntry::TranslateToKey(group, element);
192 if ( ! tagHt.count(key))
194 return tagHt.find(key)->second->GetValue();
198 * \ingroup gdcmElValSet
202 std::string gdcmElValSet::GetElValueByName(std::string TagName) {
203 if ( ! NameHt.count(TagName))
205 return NameHt.find(TagName)->second->GetValue();
209 * \ingroup gdcmElValSet
216 int gdcmElValSet::SetElValueByNumber(std::string content,
217 guint16 group, guint16 element) {
218 TagKey key = gdcmDictEntry::TranslateToKey(group, element);
219 if ( ! tagHt.count(key))
221 int l = content.length();
222 if(l%2) { // Odd length are padded with a space (020H).
224 content = content + '\0';
226 tagHt[key]->SetValue(content);
228 std::string vr = tagHt[key]->GetVR();
231 if( (vr == "US") || (vr == "SS") )
233 else if( (vr == "UL") || (vr == "SL") )
237 tagHt[key]->SetLength(lgr);
242 * \ingroup gdcmElValSet
248 int gdcmElValSet::SetElValueByName(std::string content, std::string TagName) {
249 if ( ! NameHt.count(TagName))
251 int l = content.length();
252 if(l%2) { // Odd length are padded with a space (020H).
254 // Well. I know that '/0' is NOT a space
255 // but it doesn't work with a space.
256 // Use hexedit and see 0002|0010 value (Transfer Syntax UID)
257 content = content + '\0';
259 NameHt[TagName]->SetValue(content);
261 std::string vr = NameHt[TagName]->GetVR();
264 if( (vr == "US") || (vr == "SS") )
266 else if( (vr == "UL") || (vr == "SL") )
269 lgr = content.length();
271 // TODO : WARNING: le cas de l'element des pixels (7fe0,0010) n'est pas traite
272 // par SetElValueByName
273 // il faudra utiliser SetElValueByNumber
275 NameHt[TagName]->SetLength(lgr);
280 * \ingroup gdcmElValSet
281 * \brief Generate a free TagKey i.e. a TagKey that is not present
282 * in the TagHt dictionary.
283 * @param group The generated tag must belong to this group.
284 * @return The element of tag with given group which is fee.
286 guint32 gdcmElValSet::GenerateFreeTagKeyInGroup(guint16 group) {
287 for (guint32 elem = 0; elem < UINT32_MAX; elem++) {
288 TagKey key = gdcmDictEntry::TranslateToKey(group, elem);
289 if (tagHt.count(key) == 0)
296 * \ingroup gdcmElValSet
303 int gdcmElValSet::SetVoidAreaByNumber(void * area,
304 guint16 group, guint16 element) {
305 TagKey key = gdcmDictEntry::TranslateToKey(group, element);
306 if ( ! tagHt.count(key))
308 tagHt[key]->SetVoidArea(area);
313 * \ingroup gdcmElValSet
318 * @return int acts as a boolean
320 int gdcmElValSet::SetElValueLengthByNumber(guint32 length,
321 guint16 group, guint16 element) {
322 TagKey key = gdcmDictEntry::TranslateToKey(group, element);
323 if ( ! tagHt.count(key))
325 if (length%2) length++; // length must be even
326 tagHt[key]->SetLength(length);
330 * \ingroup gdcmElValSet
336 int gdcmElValSet::SetElValueLengthByName(guint32 length, std::string TagName) {
337 if ( ! NameHt.count(TagName))
339 if (length%2) length++; // length must be even
340 NameHt.find(TagName)->second->SetLength(length);
345 * \ingroup gdcmElValSet
346 * \brief Re-computes the length of a ACR-NEMA/Dicom group from a DcmHeader
347 * @param SkipSequence TRUE if we don't want to write Sequences (ACR-NEMA Files)
350 void gdcmElValSet::UpdateGroupLength(bool SkipSequence, FileType type) {
356 std::string str_trash;
359 GroupHT groupHt; // to hold the length of each group
362 // typedef std::map<GroupKey, int> GroupHT;
366 // for each Tag in the DCM Header
368 for (TagElValueHT::iterator tag2 = tagHt.begin();
373 gr = elem->GetGroup();
374 el = elem->GetElement();
377 sprintf(trash, "%04x", gr);
378 key = trash; // generate 'group tag'
380 // if the caller decided not to take SEQUENCEs into account
381 // e.g : he wants to write an ACR-NEMA File
383 if (SkipSequence && vr == "SQ") continue;
385 // Still unsolved problem :
386 // we cannot find the 'Sequence Delimitation Item'
387 // since it's at the end of the Hash Table
390 // pas SEQUENCE en ACR-NEMA
392 // --> la descente a l'interieur' des SQ
393 // devrait etre faite avec une liste chainee, pas avec une HTable...
395 if ( groupHt.count(key) == 0) { // we just read the first elem of a given group
396 if (el == 0x0000) { // the first elem is 0x0000
397 groupHt[key] = 0; // initialize group length
399 groupHt[key] = 2 + 2 + 4 + elem->GetLength(); // non 0x0000 first group elem
401 } else { // any elem but the first
402 if (type == ExplicitVR) {
403 if ( (vr == "OB") || (vr == "OW") || (vr == "SQ") ) {
404 groupHt[key] += 4; // explicit VR AND OB, OW, SQ : 4 more bytes
407 groupHt[key] += 2 + 2 + 4 + elem->GetLength();
411 unsigned short int gr_bid;
413 for (GroupHT::iterator g = groupHt.begin(); // for each group we found
416 // FIXME: g++ -Wall -Wstrict-prototypes reports on following line:
417 // warning: unsigned int format, different type arg
418 sscanf(g->first.c_str(),"%x",&gr_bid);
419 tk = g->first + "|0000"; // generate the element full tag
421 if ( tagHt.count(tk) == 0) { // if element 0x0000 not found
422 gdcmDictEntry * tagZ = new gdcmDictEntry(gr_bid, 0x0000, "UL");
423 elemZ = new gdcmElValue(tagZ);
425 Add(elemZ); // create it
427 elemZ=GetElementByNumber(gr_bid, 0x0000);
429 sprintf(trash ,"%d",g->second);
431 elemZ->SetValue(str_trash);
436 * \ingroup gdcmElValSet
437 * \brief writes on disc according to the requested format
438 * \ (ACR-NEMA, DICOM, RAW) the image
439 * \ warning does NOT add the missing elements in the header :
440 * \ it's up to the user doing it !
441 * \ (function CheckHeaderCoherence to be written)
442 * @param type type of the File to be written
443 * (ACR-NEMA, DICOM, RAW)
444 * @param _fp already open file pointer
447 void gdcmElValSet::WriteElements(FileType type, FILE * _fp) {
455 std::vector<std::string> tokens;
457 // TODO : use listElem to iterate, not TagHt!
458 // pb : gdcmElValSet.Add does NOT update listElem
459 // find a trick in STL to do it, at low cost !
463 // Tout ceci ne marche QUE parce qu'on est sur un proc Little Endian
464 // restent a tester les echecs en ecriture (apres chaque fwrite)
466 for (TagElValueHT::iterator tag2=tagHt.begin();
470 gr = tag2->second->GetGroup();
471 el = tag2->second->GetElement();
472 lgr = tag2->second->GetLength();
473 val = tag2->second->GetValue().c_str();
474 vr = tag2->second->GetVR();
476 // std::cout << "Tag "<< std::hex << gr << " " << el << std::endl;
479 if (gr < 0x0008) continue; // ignore pure DICOM V3 groups
480 if (gr %2) continue; // ignore shadow groups
481 if (vr == "SQ" ) continue; // ignore Sequences
482 if (gr == 0xfffe ) continue; // ignore delimiters
485 fwrite ( &gr,(size_t)2 ,(size_t)1 ,_fp); //group
486 fwrite ( &el,(size_t)2 ,(size_t)1 ,_fp); //element
488 if ( (type == ExplicitVR) && (gr <= 0x0002) ) {
490 guint16 z=0, shortLgr;
491 fwrite (vr.c_str(),(size_t)2 ,(size_t)1 ,_fp);
493 if ( (vr == "OB") || (vr == "OW") || (vr == "SQ") ) {
494 fwrite ( &z, (size_t)2 ,(size_t)1 ,_fp);
495 fwrite ( &lgr,(size_t)4 ,(size_t)1 ,_fp);
499 fwrite ( &shortLgr,(size_t)2 ,(size_t)1 ,_fp);
501 } else { // IMPLICIT VR
502 fwrite ( &lgr,(size_t)4 ,(size_t)1 ,_fp);
505 if (vr == "US" || vr == "SS") {
506 tokens.erase(tokens.begin(),tokens.end()); // clean any previous value
507 Tokenize (tag2->second->GetValue(), tokens, "\\");
508 for (unsigned int i=0; i<tokens.size();i++) {
509 val_uint16 = atoi(tokens[i].c_str());
511 fwrite ( ptr,(size_t)2 ,(size_t)1 ,_fp);
516 if (vr == "UL" || vr == "SL") {
517 tokens.erase(tokens.begin(),tokens.end()); // clean any previous value
518 Tokenize (tag2->second->GetValue(), tokens, "\\");
519 for (unsigned int i=0; i<tokens.size();i++) {
520 val_uint32 = atoi(tokens[i].c_str());
522 fwrite ( ptr,(size_t)4 ,(size_t)1 ,_fp);
527 // Pixels are never loaded in the element !
528 if ((gr == 0x7fe0) && (el == 0x0010) ) break;
530 fwrite ( val,(size_t)lgr ,(size_t)1 ,_fp); // Elem value
535 * \ingroup gdcmElValSet
541 int gdcmElValSet::Write(FILE * _fp, FileType type) {
544 // Comment pourrait-on savoir si le DcmHeader vient d'un fichier DicomV3 ou non
545 // (FileType est un champ de gdcmHeader ...)
546 // WARNING : Si on veut ecrire du DICOM V3 a partir d'un DcmHeader ACR-NEMA
548 // a moins de se livrer a un tres complique ajout des champs manquants.
549 // faire un CheckAndCorrectHeader (?)
551 if ( (type == ImplicitVR) || (type == ExplicitVR) )
552 UpdateGroupLength(false,type);
554 UpdateGroupLength(true,ACR);
556 WriteElements(type, _fp);