]> Creatis software - gdcm.git/blob - src/gdcmDict.cxx
ENH: Try to reuse result from a map query, eventhough this is optimised we should...
[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:31:58 $
7   Version:   $Revision: 1.47 $
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 const & key) 
195 {
196    TagKeyHT::const_iterator it = KeyHt.find(key);
197    if(it != KeyHt.end()) 
198    {
199       DictEntry* entryToDelete = it->second;
200
201       if ( entryToDelete )
202       {
203          NameHt.erase(entryToDelete->GetName());
204          delete entryToDelete;
205       }
206
207       KeyHt.erase(key);
208       return true;
209    } 
210    else 
211    {
212       dbg.Verbose(1, "Dict::RemoveEntry unfound entry", key.c_str());
213       return false;
214   }
215 }
216
217 /**
218  * \brief  removes an already existing Dicom Dictionary Entry, 
219  *          identified by its group,element number
220  * @param   group   Dicom group number of the Dicom Element
221  * @param   element Dicom element number of the Dicom Element
222  * @return  false if Dicom Dictionary Entry doesn't exist
223  */
224 bool Dict::RemoveEntry (uint16_t group, uint16_t element)
225 {
226    return RemoveEntry(DictEntry::TranslateToKey(group, element));
227 }
228
229 /**
230  * \brief   Get the dictionnary entry identified by it's name.
231  * @param   name element of the ElVal to modify
232  * \warning : NEVER use it !
233  *            the 'name' IS NOT an identifier within the Dicom Dicom Dictionary
234  *            the name MAY CHANGE between two versions !
235  * @return  the corresponding dictionnary entry when existing, NULL otherwise
236  */
237 DictEntry* Dict::GetDictEntryByName(TagName const & name)
238 {
239    TagNameHT::const_iterator it = NameHt.find(name);
240    if ( it == NameHt.end() )
241    {
242       return 0;
243    }
244    return it->second;
245 }
246
247 /**
248  * \brief   Get the dictionnary entry identified by a given tag (group,element)
249  * @param   group   group of the entry to be found
250  * @param   element element of the entry to be found
251  * @return  the corresponding dictionnary entry when existing, NULL otherwise
252  */
253 DictEntry* Dict::GetDictEntryByNumber(uint16_t group, uint16_t element)
254 {
255    TagKey key = DictEntry::TranslateToKey(group, element);
256    TagKeyHT::const_iterator it = KeyHt.find(key);
257    if ( it == KeyHt.end() )
258    {
259       return 0;
260    }
261    return it->second;
262 }
263
264 /** 
265  * \brief   Consider all the entries of the public dicom dictionnary. 
266  *          Build all list of all the tag names of all those entries.
267  * \sa      DictSet::GetPubDictTagNamesByCategory
268  * @return  A list of all entries of the public dicom dictionnary.
269  */
270 EntryNamesList* Dict::GetDictEntryNames() 
271 {
272    EntryNamesList *result = new EntryNamesList;
273    for (TagKeyHT::iterator tag = KeyHt.begin(); tag != KeyHt.end(); ++tag)
274    {
275       result->push_back( tag->second->GetName() );
276    }
277    return result;
278 }
279
280 /** 
281  * \ingroup Dict
282  * \brief   Consider all the entries of the public dicom dictionnary.
283  *          Build an hashtable whose keys are the names of the groups
284  *          (fourth field in each line of dictionary) and whose corresponding
285  *          values are lists of all the dictionnary entries among that
286  *          group. Note that apparently the Dicom standard doesn't explicitely
287  *          define a name (as a string) for each group.
288  *          A typical usage of this method would be to enable a dynamic
289  *          configuration of a Dicom file browser: the admin/user can
290  *          select in the interface which Dicom tags should be displayed.
291  * \warning Dicom *doesn't* define any name for any 'categorie'
292  *          (the dictionnary fourth field was formerly NIH defined
293  *           - and no longer he is-
294  *           and will be removed when Dicom provides us a text file
295  *           with the 'official' Dictionnary, that would be more friendly
296  *           than asking us to perform a line by line check of the dictionnary
297  *           at the beginning of each year to -try to- guess the changes)
298  *           Therefore : please NEVER use that fourth field :-(
299  *
300  * @return  An hashtable: whose keys are the names of the groups and whose
301  *          corresponding values are lists of all the dictionnary entries
302  *          among that group.
303  */
304 EntryNamesByCatMap *Dict::GetDictEntryNamesByCategory() 
305 {
306    EntryNamesByCatMap *result = new EntryNamesByCatMap;
307
308    for (TagKeyHT::iterator tag = KeyHt.begin(); tag != KeyHt.end(); ++tag)
309    {
310       (*result)[tag->second->GetFourth()].push_back(tag->second->GetName());
311    }
312
313    return result;
314 }
315
316 //-----------------------------------------------------------------------------
317 // Protected
318
319 //-----------------------------------------------------------------------------
320 // Private
321
322 //-----------------------------------------------------------------------------
323
324 } // end namespace gdcm