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 for (TagElValueHT::iterator tag = tagHt.begin();
74 g = tag->second->GetGroup();
75 e = tag->second->GetElement();
76 v = tag->second->GetValue();
77 o = tag->second->GetOffset();
78 d2 = _CreateCleanString(v); // replace non printable characters by '.'
80 os << tag->first << ": ";
81 os << " lgr : " << tag->second->GetLength();
82 os << ", Offset : " << o;
83 os << " x(" << std::hex << o << std::dec << ") ";
84 os << "\t[" << tag->second->GetVR() << "]";
85 os << "\t[" << tag->second->GetName() << "]";
86 os << "\t[" << d2 << "]";
88 // Display the UID value (instead of displaying the rough code)
89 if (g == 0x0002) { // Some more to be displayed ?
90 if ( (e == 0x0010) || (e == 0x0002) )
91 os << " ==>\t[" << ts->GetValue(v) << "]";
94 if ( (e == 0x0016) || (e == 0x1150) )
95 os << " ==>\t[" << ts->GetValue(v) << "]";
101 std::cout << "----------------------------------------------" << std::endl;
103 //for (ListTag::iterator i = listElem.begin();
107 for (std::list<gdcmElValue*>::iterator i = listElem.begin();
110 sprintf(tag,"%04x|%04x",(*i)->GetGroup(),(*i)->GetElement());
111 g = (*i)->GetGroup();
112 e = (*i)->GetElement();
113 v = (*i)->GetValue();
114 o = (*i)->GetOffset();
115 d2 = _CreateCleanString(v); // replace non printable characters by '.'
116 //os << std::hex <<g << "|" << e << std::dec << ": ";
118 os << " lgr : " << (*i)->GetLength();
119 os << ", Offset : " << o;
120 os << " x(" << std::hex << o << std::dec << ") ";
121 os << "\t[" << (*i)->GetVR() << "]";
122 os << "\t[" << (*i)->GetName() << "]";
123 os << "\t[" << d2 << "]";
125 // Display the UID value (instead of displaying the rough code)
126 if (g == 0x0002) { // Any more to be displayed ?
127 if ( (e == 0x0010) || (e == 0x0002) )
128 os << " ==>\t[" << ts->GetValue(v) << "]";
131 if ( (e == 0x0016) || (e == 0x1150) )
132 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);
243 * \ingroup gdcmElValSet
249 int gdcmElValSet::SetElValueByName(std::string content, std::string TagName) {
250 if ( ! NameHt.count(TagName))
252 int l = content.length();
253 if(l%2) { // Odd length are padded with a space (020H).
255 // Well. I know that '/0' is NOT a space
256 // but it doesn't work with a space.
257 // Use hexedit and see 0002|0010 value (Transfer Syntax UID)
258 content = content + '\0';
260 NameHt[TagName]->SetValue(content);
262 std::string vr = NameHt[TagName]->GetVR();
265 if( (vr == "US") || (vr == "SS") )
267 else if( (vr == "UL") || (vr == "SL") )
270 lgr = content.length();
272 // TODO : WARNING: le cas de l'element des pixels (7fe0,0010) n'est pas traite
273 // par SetElValueByName
274 // il faudra utiliser SetElValueByNumber
276 NameHt[TagName]->SetLength(lgr);
281 * \ingroup gdcmElValSet
282 * \brief Generate a free TagKey i.e. a TagKey that is not present
283 * in the TagHt dictionary.
284 * @param group The generated tag must belong to this group.
285 * @return The element of tag with given group which is fee.
287 guint32 gdcmElValSet::GenerateFreeTagKeyInGroup(guint16 group) {
288 for (guint32 elem = 0; elem < UINT32_MAX; elem++) {
289 TagKey key = gdcmDictEntry::TranslateToKey(group, elem);
290 if (tagHt.count(key) == 0)
297 * \ingroup gdcmElValSet
304 int gdcmElValSet::SetVoidAreaByNumber(void * area,
305 guint16 group, guint16 element) {
306 TagKey key = gdcmDictEntry::TranslateToKey(group, element);
307 if ( ! tagHt.count(key))
309 tagHt[key]->SetVoidArea(area);
314 * \ingroup gdcmElValSet
319 * @return int acts as a boolean
321 int gdcmElValSet::SetElValueLengthByNumber(guint32 length,
322 guint16 group, guint16 element) {
323 TagKey key = gdcmDictEntry::TranslateToKey(group, element);
324 if ( ! tagHt.count(key))
326 if (length%2) length++; // length must be even
327 tagHt[key]->SetLength(length);
331 * \ingroup gdcmElValSet
337 int gdcmElValSet::SetElValueLengthByName(guint32 length, std::string TagName) {
338 if ( ! NameHt.count(TagName))
340 if (length%2) length++; // length must be even
341 NameHt.find(TagName)->second->SetLength(length);
346 * \ingroup gdcmElValSet
347 * \brief Re-computes the length of a ACR-NEMA/Dicom group from a DcmHeader
348 * @param SkipSequence TRUE if we don't want to write Sequences (ACR-NEMA Files)
351 void gdcmElValSet::UpdateGroupLength(bool SkipSequence, FileType type) {
357 std::string str_trash;
360 GroupHT groupHt; // to hold the length of each group
363 // typedef std::map<GroupKey, int> GroupHT;
367 // for each Tag in the DCM Header
369 for (TagElValueHT::iterator tag2 = tagHt.begin();
374 gr = elem->GetGroup();
375 el = elem->GetElement();
378 sprintf(trash, "%04x", gr);
379 key = trash; // generate 'group tag'
381 // if the caller decided not to take SEQUENCEs into account
382 // e.g : he wants to write an ACR-NEMA File
384 if (SkipSequence && vr == "SQ") continue;
386 // Still unsolved problem :
387 // we cannot find the 'Sequence Delimitation Item'
388 // since it's at the end of the Hash Table
391 // pas SEQUENCE en ACR-NEMA
393 // --> la descente a l'interieur' des SQ
394 // devrait etre faite avec une liste chainee, pas avec une HTable...
396 if ( groupHt.count(key) == 0) { // we just read the first elem of a given group
397 if (el == 0x0000) { // the first elem is 0x0000
398 groupHt[key] = 0; // initialize group length
400 groupHt[key] = 2 + 2 + 4 + elem->GetLength(); // non 0x0000 first group elem
402 } else { // any elem but the first
403 if (type == ExplicitVR) {
404 if ( (vr == "OB") || (vr == "OW") || (vr == "SQ") ) {
405 groupHt[key] += 4; // explicit VR AND OB, OW, SQ : 4 more bytes
408 groupHt[key] += 2 + 2 + 4 + elem->GetLength();
412 unsigned short int gr_bid;
414 for (GroupHT::iterator g = groupHt.begin(); // for each group we found
417 // FIXME: g++ -Wall -Wstrict-prototypes reports on following line:
418 // warning: unsigned int format, different type arg
419 sscanf(g->first.c_str(),"%x",&gr_bid);
420 tk = g->first + "|0000"; // generate the element full tag
422 if ( tagHt.count(tk) == 0) { // if element 0x0000 not found
423 gdcmDictEntry * tagZ = new gdcmDictEntry(gr_bid, 0x0000, "UL");
424 elemZ = new gdcmElValue(tagZ);
426 Add(elemZ); // create it
428 elemZ=GetElementByNumber(gr_bid, 0x0000);
430 sprintf(trash ,"%d",g->second);
432 elemZ->SetValue(str_trash);
437 * \ingroup gdcmElValSet
443 void gdcmElValSet::WriteElements(FileType type, FILE * _fp) {
451 std::vector<std::string> tokens;
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 (TagElValueHT::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();
468 // std::cout << "Tag "<< std::hex << gr << " " << el << std::endl;
471 if (gr < 0x0008) continue; // ignore pure DICOM V3 groups
472 if (gr %2) continue; // ignore shadow groups
473 if (vr == "SQ" ) continue; // ignore Sequences
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
527 * \ingroup gdcmElValSet
533 int gdcmElValSet::Write(FILE * _fp, FileType type) {
536 // Comment pourrait-on savoir si le DcmHeader vient d'un fichier DicomV3 ou non
537 // (FileType est un champ de gdcmHeader ...)
538 // WARNING : Si on veut ecrire du DICOM V3 a partir d'un DcmHeader ACR-NEMA
540 // a moins de se livrer a un tres complique ajout des champs manquants.
541 // faire un CheckAndCorrectHeader (?)
543 if ( (type == ImplicitVR) || (type == ExplicitVR) )
544 UpdateGroupLength(false,type);
546 UpdateGroupLength(true,ACR);
548 WriteElements(type, _fp);