]> Creatis software - gdcm.git/blob - src/gdcmDict.cxx
ENH: Guess what ! Still some cosmetic cleanup
[gdcm.git] / src / gdcmDict.cxx
1 /*=========================================================================
2                                                                                 
3   Program:   gdcm
4   Module:    $RCSfile: gdcmDict.cxx,v $
5   Language:  C++
6   Date:      $Date: 2004/08/01 02:39:09 $
7   Version:   $Revision: 1.41 $
8                                                                                 
9   Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
10   l'Image). All rights reserved. See Doc/License.txt or
11   http://www.creatis.insa-lyon.fr/Public/Gdcm/License.htm for details.
12                                                                                 
13      This software is distributed WITHOUT ANY WARRANTY; without even
14      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15      PURPOSE.  See the above copyright notices for more information.
16                                                                                 
17 =========================================================================*/
18
19 #include "gdcmDict.h"
20 #include "gdcmUtil.h"
21 #include "gdcmDebug.h"
22
23 #include <fstream>
24 #include <iostream>
25 #include <iomanip>
26
27 //-----------------------------------------------------------------------------
28 // Constructor / Destructor
29 /**
30  * \brief   Construtor
31  * @param   FileName from which to build the dictionary.
32  */
33 gdcmDict::gdcmDict(std::string const & filename)
34 {
35    uint16_t group;
36    uint16_t element;
37    TagName vr;
38    TagName fourth;
39    TagName name;
40
41    std::ifstream from( filename.c_str() );
42    dbg.Error(!from, "gdcmDict::gdcmDict: can't open dictionary",
43                     filename.c_str());
44
45    while (!from.eof())
46    {
47       from >> std::hex;
48       from >> group;          /// MEMORY LEAK in std::istream::operator>>
49       from >> element;
50       from >> vr;
51       from >> fourth;
52       eatwhite(from);
53       std::getline(from, name);    /// MEMORY LEAK in std::getline<>
54
55       gdcmDictEntry * newEntry = new gdcmDictEntry(group, element,
56                                                    vr, fourth, name);
57       AddNewEntry(newEntry);
58    }
59    from.close();
60
61    Filename = filename;
62 }
63
64 /**
65  * \brief  Destructor 
66  */
67 gdcmDict::~gdcmDict()
68 {
69    for (TagKeyHT::iterator tag = KeyHt.begin(); tag != KeyHt.end(); ++tag)
70    {
71       gdcmDictEntry* entryToDelete = tag->second;
72       if ( entryToDelete )
73       {
74          delete entryToDelete;
75       }
76    }
77    // Since AddNewEntry adds symetrical in both KeyHt and NameHT we can
78    // assume all the pointed gdcmDictEntries are already cleaned-up when
79    // we cleaned KeyHt.
80    KeyHt.clear();
81    NameHt.clear();
82 }
83
84 //-----------------------------------------------------------------------------
85 // Print
86 /**
87  * \brief   Print all the dictionary entries contained in this dictionary.
88  *          Entries will be sorted by tag i.e. the couple (group, element).
89  * @param   os The output stream to be written to.
90  */
91 void gdcmDict::Print(std::ostream &os)
92 {
93    os << "Dict file name : " << Filename << std::endl;
94    PrintByKey(os);
95 }
96
97 /**
98  * \brief   Print all the dictionary entries contained in this dictionary.
99  *          Entries will be sorted by tag i.e. the couple (group, element).
100  * @param   os The output stream to be written to.
101  */
102 void gdcmDict::PrintByKey(std::ostream &os)
103 {
104    std::ostringstream s;
105
106    for (TagKeyHT::iterator tag = KeyHt.begin(); tag != KeyHt.end(); ++tag)
107    {
108       s << "Entry : ";
109       s << "(" << std::hex << std::setw(4) << tag->second->GetGroup() << ',';
110       s << std::hex << std::setw(4) << tag->second->GetElement() << ") = "
111         << std::dec;
112       s << tag->second->GetVR() << ", ";
113       s << tag->second->GetFourth() << ", ";
114       s << tag->second->GetName() << "."  << std::endl;
115    }
116    os << s.str();
117 }
118
119 /**
120  * \brief   Print all the dictionary entries contained in this dictionary.
121  *          Entries will be sorted by the name of the dictionary entries.
122  * \warning AVOID USING IT : the name IS NOT an identifier; 
123  *                           unpredictable result
124  * @param   os The output stream to be written to.
125  */
126 void gdcmDict::PrintByName(std::ostream& os)
127 {
128    std::ostringstream s;
129
130    for (TagNameHT::iterator tag = NameHt.begin(); tag != NameHt.end(); ++tag)
131    {
132       s << "Entry : ";
133       s << tag->second->GetName() << ",";
134       s << tag->second->GetVR() << ", ";
135       s << tag->second->GetFourth() << ", ";
136       s << "(" << std::hex << std::setw(4) << tag->second->GetGroup() << ',';
137       s << std::hex << std::setw(4) << tag->second->GetElement() << ") = ";
138       s << std::dec << std::endl;
139    }
140    os << s.str();
141 }
142
143 //-----------------------------------------------------------------------------
144 // Public
145 /**
146  * \ingroup gdcmDict
147  * \brief  adds a new Dicom Dictionary Entry 
148  * @param   NewEntry entry to add 
149  * @return  false if Dicom Element already exists
150  */
151 bool gdcmDict::AddNewEntry(gdcmDictEntry *newEntry) 
152 {
153    gdcmTagKey key = newEntry->GetKey();
154
155    if(KeyHt.count(key) == 1)
156    {
157       dbg.Verbose(1, "gdcmDict::AddNewEntry already present", key.c_str());
158       return false;
159    } 
160    else 
161    {
162       KeyHt[newEntry->GetKey()] = newEntry;
163       NameHt[newEntry->GetName()] = newEntry;
164       return true;
165    }
166 }
167
168 /**
169  * \ingroup gdcmDict
170  * \brief  replaces an already existing Dicom Element by a new one
171  * @param   NewEntry new entry (overwrites any previous one with same tag)
172  * @return  false if Dicom Element doesn't exist
173  */
174 bool gdcmDict::ReplaceEntry(gdcmDictEntry *newEntry)
175 {
176    if ( RemoveEntry(newEntry->gdcmDictEntry::GetKey()) )
177    {
178        KeyHt[newEntry->GetKey()] = newEntry;
179        NameHt[newEntry->GetName()] = newEntry;
180        return true;
181    } 
182    return false;
183 }
184
185 /**
186  * \ingroup gdcmDict
187  * \brief  removes an already existing Dicom Dictionary Entry,
188  *         identified by its Tag
189  * @param   key (group|element)
190  * @return  false if Dicom Dictionary Entry doesn't exist
191  */
192 bool gdcmDict::RemoveEntry(gdcmTagKey key) 
193 {
194    if(KeyHt.count(key) == 1) 
195    {
196       gdcmDictEntry* entryToDelete = KeyHt.find(key)->second;
197
198       if ( entryToDelete )
199       {
200          NameHt.erase(entryToDelete->GetName());
201          delete entryToDelete;
202       }
203
204       KeyHt.erase(key);
205       return true;
206    } 
207    else 
208    {
209       dbg.Verbose(1, "gdcmDict::RemoveEntry unfound entry", key.c_str());
210       return false;
211   }
212 }
213
214 /**
215  * \brief  removes an already existing Dicom Dictionary Entry, 
216  *          identified by its group,element number
217  * @param   group   Dicom group number of the Dicom Element
218  * @param   element Dicom element number of the Dicom Element
219  * @return  false if Dicom Dictionary Entry doesn't exist
220  */
221 bool gdcmDict::RemoveEntry (uint16_t group, uint16_t element)
222 {
223    return RemoveEntry(gdcmDictEntry::TranslateToKey(group, element));
224 }
225
226 /**
227  * \brief   Get the dictionnary entry identified by it's name.
228  * @param   name element of the ElVal to modify
229  * \warning : NEVER use it !
230  *            the 'name' IS NOT an identifier within the Dicom Dicom Dictionary
231  *            the name MAY CHANGE between two versions !
232  * @return  the corresponding dictionnary entry when existing, NULL otherwise
233  */
234 gdcmDictEntry* gdcmDict::GetDictEntryByName(TagName name)
235 {
236    if ( !NameHt.count(name))
237    {
238       return 0;
239    }
240    return NameHt.find(name)->second;
241 }
242
243 /**
244  * \brief   Get the dictionnary entry identified by a given tag (group,element)
245  * @param   group   group of the entry to be found
246  * @param   element element of the entry to be found
247  * @return  the corresponding dictionnary entry when existing, NULL otherwise
248  */
249 gdcmDictEntry* gdcmDict::GetDictEntryByNumber(uint16_t group, uint16_t element)
250 {
251    gdcmTagKey key = gdcmDictEntry::TranslateToKey(group, element);
252    if ( !KeyHt.count(key) )
253    {
254       return 0;
255    }
256    return KeyHt.find(key)->second;
257 }
258
259 /** 
260  * \brief   Consider all the entries of the public dicom dictionnary. 
261  *          Build all list of all the tag names of all those entries.
262  * \sa      gdcmDictSet::GetPubDictTagNamesByCategory
263  * @return  A list of all entries of the public dicom dictionnary.
264  */
265 std::list<std::string>* gdcmDict::GetDictEntryNames() 
266 {
267    std::list<std::string> *result = new std::list<std::string>;
268    for (TagKeyHT::iterator tag = KeyHt.begin(); tag != KeyHt.end(); ++tag)
269    {
270       result->push_back( tag->second->GetName() );
271    }
272    return result;
273 }
274
275 /** 
276  * \ingroup gdcmDict
277  * \brief   Consider all the entries of the public dicom dictionnary.
278  *          Build an hashtable whose keys are the names of the groups
279  *          (fourth field in each line of dictionary) and whose corresponding
280  *          values are lists of all the dictionnary entries among that
281  *          group. Note that apparently the Dicom standard doesn't explicitely
282  *          define a name (as a string) for each group.
283  *          A typical usage of this method would be to enable a dynamic
284  *          configuration of a Dicom file browser: the admin/user can
285  *          select in the interface which Dicom tags should be displayed.
286  * \warning Dicom *doesn't* define any name for any 'categorie'
287  *          (the dictionnary fourth field was formerly NIH defined
288  *           - and no longer he is-
289  *           and will be removed when Dicom provides us a text file
290  *           with the 'official' Dictionnary, that would be more friendly
291  *           than asking us to perform a line by line check of the dictionnary
292  *           at the beginning of each year to -try to- guess the changes)
293  *           Therefore : please NEVER use that fourth field :-(
294  *
295  * @return  An hashtable: whose keys are the names of the groups and whose
296  *          corresponding values are lists of all the dictionnary entries
297  *          among that group.
298  */
299 std::map<std::string, std::list<std::string> > *gdcmDict::GetDictEntryNamesByCategory(void) 
300 {
301    std::map<std::string, std::list<std::string> > *result = new std::map<std::string, std::list<std::string> >;
302
303    for (TagKeyHT::iterator tag = KeyHt.begin(); tag != KeyHt.end(); ++tag)
304    {
305       (*result)[tag->second->GetFourth()].push_back(tag->second->GetName());
306    }
307
308    return result;
309 }
310
311 //-----------------------------------------------------------------------------
312 // Protected
313
314 //-----------------------------------------------------------------------------
315 // Private
316
317 //-----------------------------------------------------------------------------