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();
33 char greltag[10]; //group element tag
35 s << "------------ using listEntries ----------------" << std::endl;
38 for (ListTag::iterator i = listEntries.begin();
39 i != listEntries.end();
41 (*i)->SetPrintLevel(printLevel);
47 //-----------------------------------------------------------------------------
51 * \brief add a new Dicom Element pointer to
52 * the H Table and to the chained List
53 * \warning push_bash in listEntries ONLY during ParseHeader
54 * \todo something to allow further Elements addition,
55 * \ when position to be taken care of
56 * @param newHeaderEntry
58 void gdcmHeader::Add(gdcmHeaderEntry * newHeaderEntry) {
60 // tagHT [newHeaderEntry->GetKey()] = newHeaderEntry;
61 tagHT.insert( PairHT( newHeaderEntry->GetKey(),newHeaderEntry) );
62 listEntries.push_back(newHeaderEntry);
69 * \brief Sets a 'non string' value to a given Dicom Element
71 * @param group Group number of the searched Dicom Element
72 * @param element Element number of the searched Dicom Element
75 bool gdcmHeader::SetVoidAreaByNumber(void * area,
76 guint16 group, guint16 element) {
77 TagKey key = gdcmDictEntry::TranslateToKey(group, element);
78 if ( ! tagHT.count(key))
80 //tagHT[key]->SetVoidArea(area);
81 ( ((tagHT.equal_range(key)).first)->second )->SetVoidArea(area);
87 * \brief Generate a free TagKey i.e. a TagKey that is not present
88 * in the TagHt dictionary.
89 * @param group The generated tag must belong to this group.
90 * @return The element of tag with given group which is fee.
92 guint32 gdcmHeader::GenerateFreeTagKeyInGroup(guint16 group) {
93 for (guint32 elem = 0; elem < UINT32_MAX; elem++) {
94 TagKey key = gdcmDictEntry::TranslateToKey(group, elem);
95 if (tagHT.count(key) == 0)
101 //-----------------------------------------------------------------------------
104 //-----------------------------------------------------------------------------
107 * \ingroup gdcmHeader
108 * \brief Re-computes the length of a ACR-NEMA/Dicom group from a DcmHeader
109 * \warning : to be re-written using the chained list instead of the H table.
110 * \warning : DO NOT use (doesn't work any longer because of the multimap)
111 * \todo : to be re-written using the chained list instead of the H table
112 * @param SkipSequence TRUE if we don't want to write Sequences (ACR-NEMA Files)
113 * @param type Type of the File (ExplicitVR,ImplicitVR, ACR, ...)
115 void gdcmHeader::UpdateGroupLength(bool SkipSequence, FileType type) {
119 gdcmHeaderEntry *elem;
121 std::string str_trash;
124 GroupHT groupHt; // to hold the length of each group
127 // typedef std::map<GroupKey, int> GroupHT;
129 gdcmHeaderEntry *elemZ;
131 // for each Tag in the DCM Header
133 for (TagHeaderEntryHT::iterator tag2 = tagHT.begin();
138 gr = elem->GetGroup();
139 el = elem->GetElement();
142 sprintf(trash, "%04x", gr);
143 key = trash; // generate 'group tag'
145 // if the caller decided not to take SEQUENCEs into account
146 // e.g : he wants to write an ACR-NEMA File
148 if (SkipSequence && vr == "SQ") continue;
150 // Still unsolved problem :
151 // we cannot find the 'Sequence Delimitation Item'
152 // since it's at the end of the Hash Table
155 // pas SEQUENCE en ACR-NEMA
157 // --> la descente a l'interieur' des SQ
158 // devrait etre faite avec une liste chainee, pas avec une HTable...
160 if ( groupHt.count(key) == 0) { // we just read the first elem of a given group
161 if (el == 0x0000) { // the first elem is 0x0000
162 groupHt[key] = 0; // initialize group length
164 groupHt[key] = 2 + 2 + 4 + elem->GetLength(); // non 0x0000 first group elem
166 } else { // any elem but the first
167 if (type == ExplicitVR) {
168 if ( (vr == "OB") || (vr == "OW") || (vr == "SQ") ) {
169 groupHt[key] += 4; // explicit VR AND OB, OW, SQ : 4 more bytes
172 groupHt[key] += 2 + 2 + 4 + elem->GetLength();
176 unsigned short int gr_bid;
178 for (GroupHT::iterator g = groupHt.begin(); // for each group we found
181 // FIXME: g++ -Wall -Wstrict-prototypes reports on following line:
182 // warning: unsigned int format, different type arg
183 sscanf(g->first.c_str(),"%x",&gr_bid);
184 tk = g->first + "|0000"; // generate the element full tag
186 if ( tagHT.count(tk) == 0) { // if element 0x0000 not found
187 gdcmDictEntry * tagZ = new gdcmDictEntry(gr_bid, 0x0000, "UL");
188 elemZ = new gdcmHeaderEntry(tagZ);
190 Add(elemZ); // create it
192 elemZ=GetHeaderEntryByNumber(gr_bid, 0x0000);
194 sprintf(trash ,"%d",g->second);
196 elemZ->SetValue(str_trash);
201 * \ingroup gdcmHeader
202 * \brief writes on disc according to the requested format
203 * \ (ACR-NEMA, ExplicitVR, ImplicitVR) the image
204 * \ warning does NOT add the missing elements in the header :
205 * \ it's up to the user doing it !
206 * \ (function CheckHeaderCoherence to be written)
207 * @param type type of the File to be written
208 * (ACR-NEMA, ExplicitVR, ImplicitVR)
209 * @param _fp already open file pointer
211 void gdcmHeader::WriteEntries(FileType type, FILE * _fp) {
219 std::vector<std::string> tokens;
221 // uses now listEntries to iterate, not TagHt!
223 // pb : gdcmHeader.Add does NOT update listEntries
224 // TODO : find a trick (in STL?) to do it, at low cost !
228 // TODO (?) tester les echecs en ecriture (apres chaque fwrite)
230 for (ListTag::iterator tag2=listEntries.begin();
231 tag2 != listEntries.end();
234 gr = (*tag2)->GetGroup();
235 el = (*tag2)->GetElement();
236 lgr = (*tag2)->GetLength();
237 val = (*tag2)->GetValue().c_str();
238 vr = (*tag2)->GetVR();
241 if (gr < 0x0008) continue; // ignore pure DICOM V3 groups
242 if (gr %2) continue; // ignore shadow groups
243 if (vr == "SQ" ) continue; // ignore Sequences
244 // TODO : find a trick to *skip* the SeQuences !
245 // Not only ignore the SQ element
246 if (gr == 0xfffe ) continue; // ignore delimiters
249 fwrite ( &gr,(size_t)2 ,(size_t)1 ,_fp); //group
250 fwrite ( &el,(size_t)2 ,(size_t)1 ,_fp); //element
252 if ( (type == ExplicitVR) && (gr <= 0x0002) ) {
254 guint16 z=0, shortLgr;
255 fwrite (vr.c_str(),(size_t)2 ,(size_t)1 ,_fp);
257 if ( (vr == "OB") || (vr == "OW") || (vr == "SQ") ) {
258 fwrite ( &z, (size_t)2 ,(size_t)1 ,_fp);
259 fwrite ( &lgr,(size_t)4 ,(size_t)1 ,_fp);
263 fwrite ( &shortLgr,(size_t)2 ,(size_t)1 ,_fp);
265 } else { // IMPLICIT VR
266 fwrite ( &lgr,(size_t)4 ,(size_t)1 ,_fp);
269 if (vr == "US" || vr == "SS") {
270 tokens.erase(tokens.begin(),tokens.end()); // clean any previous value
271 Tokenize ((*tag2)->GetValue(), tokens, "\\");
272 for (unsigned int i=0; i<tokens.size();i++) {
273 val_uint16 = atoi(tokens[i].c_str());
275 fwrite ( ptr,(size_t)2 ,(size_t)1 ,_fp);
280 if (vr == "UL" || vr == "SL") {
281 tokens.erase(tokens.begin(),tokens.end()); // clean any previous value
282 Tokenize ((*tag2)->GetValue(), tokens, "\\");
283 for (unsigned int i=0; i<tokens.size();i++) {
284 val_uint32 = atoi(tokens[i].c_str());
286 fwrite ( ptr,(size_t)4 ,(size_t)1 ,_fp);
291 // Pixels are never loaded in the element !
292 if ((gr == 0x7fe0) && (el == 0x0010) ) break;
294 fwrite ( val,(size_t)lgr ,(size_t)1 ,_fp); // Elem value
298 //-----------------------------------------------------------------------------