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