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;
105 //for (ListTag::iterator i = listElem.begin();
109 for (std::list<gdcmElValue*>::iterator i = listElem.begin();
112 sprintf(tag,"%04x|%04x",(*i)->GetGroup(),(*i)->GetElement());
113 g = (*i)->GetGroup();
114 e = (*i)->GetElement();
115 v = (*i)->GetValue();
116 o = (*i)->GetOffset();
117 d2 = _CreateCleanString(v); // replace non printable characters by '.'
118 //os << std::hex <<g << "|" << e << std::dec << ": ";
120 os << " lgr : " << (*i)->GetReadLength();
121 os << ", Offset : " << o;
122 os << " x(" << std::hex << o << std::dec << ") ";
123 os << "\t[" << (*i)->GetVR() << "]";
124 os << "\t[" << (*i)->GetName() << "]";
125 os << "\t[" << d2 << "]";
127 // Display the UID value (instead of displaying the rough code)
128 if (g == 0x0002) { // Any more to be displayed ?
129 if ( (e == 0x0010) || (e == 0x0002) )
130 os << " ==>\t[" << ts->GetValue(v) << "]";
133 if ( (e == 0x0016) || (e == 0x1150) )
134 os << " ==>\t[" << ts->GetValue(v) << "]";
142 * \ingroup gdcmElValSet
145 void gdcmElValSet::PrintByName(std::ostream & os) {
146 for (TagElValueNameHT::iterator tag = NameHt.begin();
149 os << tag->first << ": ";
150 os << "[" << tag->second->GetValue() << "]";
151 os << "[" << tag->second->GetKey() << "]";
152 os << "[" << tag->second->GetVR() << "]" << std::endl;
157 * \ingroup gdcmElValSet
163 gdcmElValue* gdcmElValSet::GetElementByNumber(guint16 group, guint16 element) {
164 TagKey key = gdcmDictEntry::TranslateToKey(group, element);
165 if ( ! tagHt.count(key))
166 return (gdcmElValue*)0;
167 return tagHt.find(key)->second;
171 * \ingroup gdcmElValSet
175 gdcmElValue* gdcmElValSet::GetElementByName(std::string TagName) {
176 if ( ! NameHt.count(TagName))
177 return (gdcmElValue*)0;
178 return NameHt.find(TagName)->second;
182 * \ingroup gdcmElValSet
188 std::string gdcmElValSet::GetElValueByNumber(guint16 group, guint16 element) {
189 TagKey key = gdcmDictEntry::TranslateToKey(group, element);
190 if ( ! tagHt.count(key))
192 return tagHt.find(key)->second->GetValue();
196 * \ingroup gdcmElValSet
200 std::string gdcmElValSet::GetElValueByName(std::string TagName) {
201 if ( ! NameHt.count(TagName))
203 return NameHt.find(TagName)->second->GetValue();
207 * \ingroup gdcmElValSet
214 int gdcmElValSet::SetElValueByNumber(std::string content,
215 guint16 group, guint16 element) {
216 TagKey key = gdcmDictEntry::TranslateToKey(group, element);
217 if ( ! tagHt.count(key))
219 int l = content.length();
220 if(l%2) { // Odd length are padded with a space (020H).
222 content = content + '\0';
224 tagHt[key]->SetValue(content);
226 std::string vr = tagHt[key]->GetVR();
229 if( (vr == "US") || (vr == "SS") )
231 else if( (vr == "UL") || (vr == "SL") )
235 tagHt[key]->SetLength(lgr);
240 * \ingroup gdcmElValSet
246 int gdcmElValSet::SetElValueByName(std::string content, std::string TagName) {
247 if ( ! NameHt.count(TagName))
249 int l = content.length();
250 if(l%2) { // Odd length are padded with a space (020H).
252 // Well. I know that '/0' is NOT a space
253 // but it doesn't work with a space.
254 // Use hexedit and see 0002|0010 value (Transfer Syntax UID)
255 content = content + '\0';
257 NameHt[TagName]->SetValue(content);
259 std::string vr = NameHt[TagName]->GetVR();
262 if( (vr == "US") || (vr == "SS") )
264 else if( (vr == "UL") || (vr == "SL") )
267 lgr = content.length();
269 // TODO : WARNING: le cas de l'element des pixels (7fe0,0010) n'est pas traite
270 // par SetElValueByName
271 // il faudra utiliser SetElValueByNumber
273 NameHt[TagName]->SetLength(lgr);
278 * \ingroup gdcmElValSet
279 * \brief Generate a free TagKey i.e. a TagKey that is not present
280 * in the TagHt dictionary.
281 * @param group The generated tag must belong to this group.
282 * @return The element of tag with given group which is fee.
284 guint32 gdcmElValSet::GenerateFreeTagKeyInGroup(guint16 group) {
285 for (guint32 elem = 0; elem < UINT32_MAX; elem++) {
286 TagKey key = gdcmDictEntry::TranslateToKey(group, elem);
287 if (tagHt.count(key) == 0)
294 * \ingroup gdcmElValSet
301 int gdcmElValSet::SetVoidAreaByNumber(void * area,
302 guint16 group, guint16 element) {
303 TagKey key = gdcmDictEntry::TranslateToKey(group, element);
304 if ( ! tagHt.count(key))
306 tagHt[key]->SetVoidArea(area);
311 * \ingroup gdcmElValSet
316 * @return int acts as a boolean
318 int gdcmElValSet::SetElValueLengthByNumber(guint32 length,
319 guint16 group, guint16 element) {
320 TagKey key = gdcmDictEntry::TranslateToKey(group, element);
321 if ( ! tagHt.count(key))
323 if (length%2) length++; // length must be even
324 tagHt[key]->SetLength(length);
328 * \ingroup gdcmElValSet
334 int gdcmElValSet::SetElValueLengthByName(guint32 length, std::string TagName) {
335 if ( ! NameHt.count(TagName))
337 if (length%2) length++; // length must be even
338 NameHt.find(TagName)->second->SetLength(length);
343 * \ingroup gdcmElValSet
344 * \brief Re-computes the length of a ACR-NEMA/Dicom group from a DcmHeader
345 * @param SkipSequence TRUE if we don't want to write Sequences (ACR-NEMA Files)
348 void gdcmElValSet::UpdateGroupLength(bool SkipSequence, FileType type) {
354 std::string str_trash;
357 GroupHT groupHt; // to hold the length of each group
360 // typedef std::map<GroupKey, int> GroupHT;
364 // for each Tag in the DCM Header
366 for (TagElValueHT::iterator tag2 = tagHt.begin();
371 gr = elem->GetGroup();
372 el = elem->GetElement();
375 sprintf(trash, "%04x", gr);
376 key = trash; // generate 'group tag'
378 // if the caller decided not to take SEQUENCEs into account
379 // e.g : he wants to write an ACR-NEMA File
381 if (SkipSequence && vr == "SQ") continue;
383 // Still unsolved problem :
384 // we cannot find the 'Sequence Delimitation Item'
385 // since it's at the end of the Hash Table
388 // pas SEQUENCE en ACR-NEMA
390 // --> la descente a l'interieur' des SQ
391 // devrait etre faite avec une liste chainee, pas avec une HTable...
393 if ( groupHt.count(key) == 0) { // we just read the first elem of a given group
394 if (el == 0x0000) { // the first elem is 0x0000
395 groupHt[key] = 0; // initialize group length
397 groupHt[key] = 2 + 2 + 4 + elem->GetLength(); // non 0x0000 first group elem
399 } else { // any elem but the first
400 if (type == ExplicitVR) {
401 if ( (vr == "OB") || (vr == "OW") || (vr == "SQ") ) {
402 groupHt[key] += 4; // explicit VR AND OB, OW, SQ : 4 more bytes
405 groupHt[key] += 2 + 2 + 4 + elem->GetLength();
409 unsigned short int gr_bid;
411 for (GroupHT::iterator g = groupHt.begin(); // for each group we found
414 // FIXME: g++ -Wall -Wstrict-prototypes reports on following line:
415 // warning: unsigned int format, different type arg
416 sscanf(g->first.c_str(),"%x",&gr_bid);
417 tk = g->first + "|0000"; // generate the element full tag
419 if ( tagHt.count(tk) == 0) { // if element 0x0000 not found
420 gdcmDictEntry * tagZ = new gdcmDictEntry(gr_bid, 0x0000, "UL");
421 elemZ = new gdcmElValue(tagZ);
423 Add(elemZ); // create it
425 elemZ=GetElementByNumber(gr_bid, 0x0000);
427 sprintf(trash ,"%d",g->second);
429 elemZ->SetValue(str_trash);
434 * \ingroup gdcmElValSet
435 * \brief writes on disc according to the requested format
436 * \ (ACR-NEMA, DICOM, RAW) the image
437 * \ warning does NOT add the missing elements in the header :
438 * \ it's up to the user doing it !
439 * \ (function CheckHeaderCoherence to be written)
440 * @param type type of the File to be written
441 * (ACR-NEMA, DICOM, RAW)
442 * @param _fp already open file pointer
445 void gdcmElValSet::WriteElements(FileType type, FILE * _fp) {
453 std::vector<std::string> tokens;
455 // TODO : use listElem to iterate, not TagHt!
456 // pb : gdcmElValSet.Add does NOT update listElem
457 // find a trick in STL to do it, at low cost !
461 // Tout ceci ne marche QUE parce qu'on est sur un proc Little Endian
462 // restent a tester les echecs en ecriture (apres chaque fwrite)
464 for (TagElValueHT::iterator tag2=tagHt.begin();
468 gr = tag2->second->GetGroup();
469 el = tag2->second->GetElement();
470 lgr = tag2->second->GetLength();
471 val = tag2->second->GetValue().c_str();
472 vr = tag2->second->GetVR();
474 // std::cout << "Tag "<< std::hex << gr << " " << el << std::endl;
477 if (gr < 0x0008) continue; // ignore pure DICOM V3 groups
478 if (gr %2) continue; // ignore shadow groups
479 if (vr == "SQ" ) continue; // ignore Sequences
480 if (gr == 0xfffe ) continue; // ignore delimiters
483 fwrite ( &gr,(size_t)2 ,(size_t)1 ,_fp); //group
484 fwrite ( &el,(size_t)2 ,(size_t)1 ,_fp); //element
486 if ( (type == ExplicitVR) && (gr <= 0x0002) ) {
488 guint16 z=0, shortLgr;
489 fwrite (vr.c_str(),(size_t)2 ,(size_t)1 ,_fp);
491 if ( (vr == "OB") || (vr == "OW") || (vr == "SQ") ) {
492 fwrite ( &z, (size_t)2 ,(size_t)1 ,_fp);
493 fwrite ( &lgr,(size_t)4 ,(size_t)1 ,_fp);
497 fwrite ( &shortLgr,(size_t)2 ,(size_t)1 ,_fp);
499 } else { // IMPLICIT VR
500 fwrite ( &lgr,(size_t)4 ,(size_t)1 ,_fp);
503 if (vr == "US" || vr == "SS") {
504 tokens.erase(tokens.begin(),tokens.end()); // clean any previous value
505 Tokenize (tag2->second->GetValue(), tokens, "\\");
506 for (unsigned int i=0; i<tokens.size();i++) {
507 val_uint16 = atoi(tokens[i].c_str());
509 fwrite ( ptr,(size_t)2 ,(size_t)1 ,_fp);
514 if (vr == "UL" || vr == "SL") {
515 tokens.erase(tokens.begin(),tokens.end()); // clean any previous value
516 Tokenize (tag2->second->GetValue(), tokens, "\\");
517 for (unsigned int i=0; i<tokens.size();i++) {
518 val_uint32 = atoi(tokens[i].c_str());
520 fwrite ( ptr,(size_t)4 ,(size_t)1 ,_fp);
525 // Pixels are never loaded in the element !
526 if ((gr == 0x7fe0) && (el == 0x0010) ) break;
528 fwrite ( val,(size_t)lgr ,(size_t)1 ,_fp); // Elem value
533 * \ingroup gdcmElValSet
539 int gdcmElValSet::Write(FILE * _fp, FileType type) {
542 // Comment pourrait-on savoir si le DcmHeader vient d'un fichier DicomV3 ou non
543 // (FileType est un champ de gdcmHeader ...)
544 // WARNING : Si on veut ecrire du DICOM V3 a partir d'un DcmHeader ACR-NEMA
546 // a moins de se livrer a un tres complique ajout des champs manquants.
547 // faire un CheckAndCorrectHeader (?)
549 if ( (type == ImplicitVR) || (type == ExplicitVR) )
550 UpdateGroupLength(false,type);
552 UpdateGroupLength(true,ACR);
554 WriteElements(type, _fp);