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