2 //-----------------------------------------------------------------------------
4 #include "gdcmHeader.h"
6 #ifdef GDCM_NO_ANSI_STRING_STREAM
8 # define ostringstream ostrstream
13 #include <iomanip> // for std::ios::left, ...
15 //-----------------------------------------------------------------------------
19 * \brief prints the Dicom Elements of the gdcmHeader
20 * using both H table and Chained List
21 * @param os The output stream to be written to.
23 void gdcmHeader::Print(std::ostream & os) {
26 unsigned short int g, e;
29 gdcmTS * ts = gdcmGlobal::GetTS();
32 // DO NOT remove this code right now.
35 s << "------------- using tagHT ---------------------" << std::endl;
36 for (TagHeaderEntryHT::iterator tag = tagHT.begin();
39 g = tag->second->GetGroup();
40 e = tag->second->GetElement();
41 v = tag->second->GetValue();
42 o = tag->second->GetOffset();
43 d2 = _CreateCleanString(v); // replace non printable characters by '.'
45 s << tag->first << ": ";
46 s << " lgr : " <<tag->second->GetLength();
47 s << ",\t Offset : " << o;
48 s << " x(" << std::hex << o << std::dec << ") ";
49 s << "\t[" << tag->second->GetVR() << "]";
50 s << "\t[" << tag->second->GetName() << "]";
51 s << "\t[" << d2 << "]";
53 // Display the UID value (instead of displaying the rough code)
54 if (g == 0x0002) { // Some more to be displayed ?
55 if ( (e == 0x0010) || (e == 0x0002) )
56 s << " ==>\t[" << ts->GetValue(v) << "]";
59 if ( (e == 0x0016) || (e == 0x1150) )
60 s << " ==>\t[" << ts->GetValue(v) << "]";
69 char greltag[10]; //group element tag
71 s << "------------ using listEntries ----------------" << std::endl;
74 for (ListTag::iterator i = listEntries.begin();
75 i != listEntries.end();
78 e = (*i)->GetElement();
80 o = (*i)->GetOffset();
81 sprintf(greltag,"%04x|%04x ",g,e);
82 d2 = _CreateCleanString(v); // replace non printable characters by '.'
87 lgth = (*i)->GetReadLength();
88 if (lgth == 0xffffffff) {
90 s.setf(std::ios::left);
91 s << std::setw(10-strlen(st)) << " ";
93 s.setf(std::ios::left);
94 s << std::setw(8) << "-1";
96 sprintf(st,"x(%x)",lgth);
97 s.setf(std::ios::left);
98 s << std::setw(10-strlen(st)) << " ";
100 s.setf(std::ios::left);
101 s << std::setw(8) << lgth;
104 sprintf(st,"x(%x)",o);
105 s << std::setw(10-strlen(st)) << " ";
107 s << std::setw(8) << o;
110 s << "[" << (*i)->GetVR() << "] ";
111 s.setf(std::ios::left);
112 s << std::setw(66-(*i)->GetName().length()) << " ";
115 s << "[" << (*i)->GetName()<< "]";
116 s << " [" << 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 s << " ==>\t[" << ts->GetValue(v) << "]";
123 if ( (e == 0x0016) || (e == 0x1150) )
124 s << " ==>\t[" << ts->GetValue(v) << "]";
127 if (e == 0x0000) { // elem 0x0000 --> group length
128 if (v == "4294967295") // to avoid troubles in convertion
129 sprintf (st," x(ffffffff)");
131 sprintf(st," x(%08x)",atoi(v.c_str()));
139 //-----------------------------------------------------------------------------
142 * \ingroup gdcmHeader
143 * \brief add a new Dicom Element pointer to
144 * the H Table and to the chained List
145 * \warning push_bash in listEntries ONLY during ParseHeader
146 * \todo something to allow further Elements addition,
147 * \ when position to be taken care of
148 * @param newHeaderEntry
150 void gdcmHeader::Add(gdcmHeaderEntry * newHeaderEntry) {
152 // tagHT [newHeaderEntry->GetKey()] = newHeaderEntry;
153 tagHT.insert( PairHT( newHeaderEntry->GetKey(),newHeaderEntry) );
154 listEntries.push_back(newHeaderEntry);
160 * \ingroup gdcmHeader
161 * \brief Sets a 'non string' value to a given Dicom Element
163 * @param group Group number of the searched Dicom Element
164 * @param element Element number of the searched Dicom Element
167 bool gdcmHeader::SetVoidAreaByNumber(void * area,
168 guint16 group, guint16 element) {
169 TagKey key = gdcmDictEntry::TranslateToKey(group, element);
170 if ( ! tagHT.count(key))
172 //tagHT[key]->SetVoidArea(area);
173 ( ((tagHT.equal_range(key)).first)->second )->SetVoidArea(area);
178 * \ingroup gdcmHeader
179 * \brief Generate a free TagKey i.e. a TagKey that is not present
180 * in the TagHt dictionary.
181 * @param group The generated tag must belong to this group.
182 * @return The element of tag with given group which is fee.
184 guint32 gdcmHeader::GenerateFreeTagKeyInGroup(guint16 group) {
185 for (guint32 elem = 0; elem < UINT32_MAX; elem++) {
186 TagKey key = gdcmDictEntry::TranslateToKey(group, elem);
187 if (tagHT.count(key) == 0)
193 //-----------------------------------------------------------------------------
196 //-----------------------------------------------------------------------------
199 * \ingroup gdcmHeader
200 * \brief Re-computes the length of a ACR-NEMA/Dicom group from a DcmHeader
201 * \warning : to be re-written using the chained list instead of the H table.
202 * \warning : DO NOT use (doesn't work any longer because of the multimap)
203 * \todo : to be re-written using the chained list instead of the H table
204 * @param SkipSequence TRUE if we don't want to write Sequences (ACR-NEMA Files)
205 * @param type Type of the File (ExplicitVR,ImplicitVR, ACR, ...)
207 void gdcmHeader::UpdateGroupLength(bool SkipSequence, FileType type) {
211 gdcmHeaderEntry *elem;
213 std::string str_trash;
216 GroupHT groupHt; // to hold the length of each group
219 // typedef std::map<GroupKey, int> GroupHT;
221 gdcmHeaderEntry *elemZ;
223 // for each Tag in the DCM Header
225 for (TagHeaderEntryHT::iterator tag2 = tagHT.begin();
230 gr = elem->GetGroup();
231 el = elem->GetElement();
234 sprintf(trash, "%04x", gr);
235 key = trash; // generate 'group tag'
237 // if the caller decided not to take SEQUENCEs into account
238 // e.g : he wants to write an ACR-NEMA File
240 if (SkipSequence && vr == "SQ") continue;
242 // Still unsolved problem :
243 // we cannot find the 'Sequence Delimitation Item'
244 // since it's at the end of the Hash Table
247 // pas SEQUENCE en ACR-NEMA
249 // --> la descente a l'interieur' des SQ
250 // devrait etre faite avec une liste chainee, pas avec une HTable...
252 if ( groupHt.count(key) == 0) { // we just read the first elem of a given group
253 if (el == 0x0000) { // the first elem is 0x0000
254 groupHt[key] = 0; // initialize group length
256 groupHt[key] = 2 + 2 + 4 + elem->GetLength(); // non 0x0000 first group elem
258 } else { // any elem but the first
259 if (type == ExplicitVR) {
260 if ( (vr == "OB") || (vr == "OW") || (vr == "SQ") ) {
261 groupHt[key] += 4; // explicit VR AND OB, OW, SQ : 4 more bytes
264 groupHt[key] += 2 + 2 + 4 + elem->GetLength();
268 unsigned short int gr_bid;
270 for (GroupHT::iterator g = groupHt.begin(); // for each group we found
273 // FIXME: g++ -Wall -Wstrict-prototypes reports on following line:
274 // warning: unsigned int format, different type arg
275 sscanf(g->first.c_str(),"%x",&gr_bid);
276 tk = g->first + "|0000"; // generate the element full tag
278 if ( tagHT.count(tk) == 0) { // if element 0x0000 not found
279 gdcmDictEntry * tagZ = new gdcmDictEntry(gr_bid, 0x0000, "UL");
280 elemZ = new gdcmHeaderEntry(tagZ);
282 Add(elemZ); // create it
284 elemZ=GetHeaderEntryByNumber(gr_bid, 0x0000);
286 sprintf(trash ,"%d",g->second);
288 elemZ->SetValue(str_trash);
293 * \ingroup gdcmHeader
294 * \brief writes on disc according to the requested format
295 * \ (ACR-NEMA, ExplicitVR, ImplicitVR) the image
296 * \ warning does NOT add the missing elements in the header :
297 * \ it's up to the user doing it !
298 * \ (function CheckHeaderCoherence to be written)
299 * @param type type of the File to be written
300 * (ACR-NEMA, ExplicitVR, ImplicitVR)
301 * @param _fp already open file pointer
303 void gdcmHeader::WriteEntries(FileType type, FILE * _fp) {
311 std::vector<std::string> tokens;
313 // uses now listEntries to iterate, not TagHt!
315 // pb : gdcmHeader.Add does NOT update listEntries
316 // TODO : find a trick (in STL?) to do it, at low cost !
320 // TODO (?) tester les echecs en ecriture (apres chaque fwrite)
322 for (ListTag::iterator tag2=listEntries.begin();
323 tag2 != listEntries.end();
326 gr = (*tag2)->GetGroup();
327 el = (*tag2)->GetElement();
328 lgr = (*tag2)->GetLength();
329 val = (*tag2)->GetValue().c_str();
330 vr = (*tag2)->GetVR();
333 if (gr < 0x0008) continue; // ignore pure DICOM V3 groups
334 if (gr %2) continue; // ignore shadow groups
335 if (vr == "SQ" ) continue; // ignore Sequences
336 // TODO : find a trick to *skip* the SeQuences !
337 // Not only ignore the SQ element
338 if (gr == 0xfffe ) continue; // ignore delimiters
341 fwrite ( &gr,(size_t)2 ,(size_t)1 ,_fp); //group
342 fwrite ( &el,(size_t)2 ,(size_t)1 ,_fp); //element
344 if ( (type == ExplicitVR) && (gr <= 0x0002) ) {
346 guint16 z=0, shortLgr;
347 fwrite (vr.c_str(),(size_t)2 ,(size_t)1 ,_fp);
349 if ( (vr == "OB") || (vr == "OW") || (vr == "SQ") ) {
350 fwrite ( &z, (size_t)2 ,(size_t)1 ,_fp);
351 fwrite ( &lgr,(size_t)4 ,(size_t)1 ,_fp);
355 fwrite ( &shortLgr,(size_t)2 ,(size_t)1 ,_fp);
357 } else { // IMPLICIT VR
358 fwrite ( &lgr,(size_t)4 ,(size_t)1 ,_fp);
361 if (vr == "US" || vr == "SS") {
362 tokens.erase(tokens.begin(),tokens.end()); // clean any previous value
363 Tokenize ((*tag2)->GetValue(), tokens, "\\");
364 for (unsigned int i=0; i<tokens.size();i++) {
365 val_uint16 = atoi(tokens[i].c_str());
367 fwrite ( ptr,(size_t)2 ,(size_t)1 ,_fp);
372 if (vr == "UL" || vr == "SL") {
373 tokens.erase(tokens.begin(),tokens.end()); // clean any previous value
374 Tokenize ((*tag2)->GetValue(), tokens, "\\");
375 for (unsigned int i=0; i<tokens.size();i++) {
376 val_uint32 = atoi(tokens[i].c_str());
378 fwrite ( ptr,(size_t)4 ,(size_t)1 ,_fp);
383 // Pixels are never loaded in the element !
384 if ((gr == 0x7fe0) && (el == 0x0010) ) break;
386 fwrite ( val,(size_t)lgr ,(size_t)1 ,_fp); // Elem value
390 //-----------------------------------------------------------------------------