]> Creatis software - gdcm.git/blob - src/gdcmDict.cxx
ENH: Now the dictionary is compiled into gdcm lib. This is a default behavior, thus...
[gdcm.git] / src / gdcmDict.cxx
1 /*=========================================================================
2                                                                                 
3   Program:   gdcm
4   Module:    $RCSfile: gdcmDict.cxx,v $
5   Language:  C++
6   Date:      $Date: 2004/11/03 18:08:56 $
7   Version:   $Revision: 1.51 $
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 void FillDefaultDataDict(Dict *d);
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    if( !from )
46    {
47       dbg.Verbose(2,"Dict::Dict: can't open dictionary", filename.c_str());
48       // Using default embeded one:
49       FillDefaultDataDict( this );
50    }
51    else
52    {
53       while (!from.eof())
54       {
55          from >> std::hex;
56          from >> group;
57          from >> element;
58          from >> vr;
59          from >> fourth;
60          from >> std::ws;  //remove white space
61          std::getline(from, name);
62    
63          const DictEntry newEntry(group, element, vr, fourth, name);
64          AddNewEntry(newEntry);
65       }
66       from.close();
67
68       Filename = filename;
69    }
70 }
71
72 /**
73  * \brief  Destructor 
74  */
75 Dict::~Dict()
76 {
77    // Since AddNewEntry adds symetrical in both KeyHt and NameHT we can
78    // assume all the pointed DictEntries 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 Dict::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 Dict::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 Dict::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 Dict
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 Dict::AddNewEntry(DictEntry const & newEntry) 
152 {
153    const TagKey & key = newEntry.GetKey();
154
155    if(KeyHt.count(key) == 1)
156    {
157       dbg.Verbose(1, "Dict::AddNewEntry already present", key.c_str());
158       return false;
159    } 
160    else 
161    {
162       KeyHt.insert( 
163          std::map<TagKey, DictEntry>::value_type
164             (newEntry.GetKey(), newEntry));
165       NameHt.insert(
166          std::map<TagName, DictEntry>::value_type
167             (newEntry.GetName(), newEntry ));
168       return true;
169    }
170 }
171
172 /**
173  * \ingroup Dict
174  * \brief  replaces an already existing Dicom Element by a new one
175  * @param   newEntry new entry (overwrites any previous one with same tag)
176  * @return  false if Dicom Element doesn't exist
177  */
178 bool Dict::ReplaceEntry(DictEntry const & newEntry)
179 {
180    if ( RemoveEntry(newEntry.GetKey()) )
181    {
182       KeyHt.insert( 
183          std::map<TagKey, DictEntry>::value_type
184             (newEntry.GetKey(), newEntry));
185       NameHt.insert(
186          std::map<TagName, DictEntry>::value_type
187             (newEntry.GetName(), newEntry ));
188        return true;
189    } 
190    return false;
191 }
192
193 /**
194  * \ingroup Dict
195  * \brief  removes an already existing Dicom Dictionary Entry,
196  *         identified by its Tag
197  * @param   key (group|element)
198  * @return  false if Dicom Dictionary Entry doesn't exist
199  */
200 bool Dict::RemoveEntry (TagKey const & key) 
201 {
202    TagKeyHT::const_iterator it = KeyHt.find(key);
203    if(it != KeyHt.end()) 
204    {
205       const DictEntry & entryToDelete = it->second;
206       NameHt.erase(entryToDelete.GetName());
207       KeyHt.erase(key);
208
209       return true;
210    } 
211    else 
212    {
213       dbg.Verbose(1, "Dict::RemoveEntry unfound entry", key.c_str());
214       return false;
215   }
216 }
217
218 /**
219  * \brief  removes an already existing Dicom Dictionary Entry, 
220  *          identified by its group,element number
221  * @param   group   Dicom group number of the Dicom Element
222  * @param   element Dicom element number of the Dicom Element
223  * @return  false if Dicom Dictionary Entry doesn't exist
224  */
225 bool Dict::RemoveEntry (uint16_t group, uint16_t element)
226 {
227    return RemoveEntry(DictEntry::TranslateToKey(group, element));
228 }
229
230 /**
231  * \brief   Get the dictionnary entry identified by it's name.
232  * @param   name element of the ElVal to modify
233  * \warning : NEVER use it !
234  *            the 'name' IS NOT an identifier within the Dicom Dictionary
235  *            the name MAY CHANGE between two versions !
236  * @return  the corresponding dictionnary entry when existing, NULL otherwise
237  */
238 DictEntry* Dict::GetDictEntryByName(TagName const & name)
239 {
240    TagNameHT::iterator it = NameHt.find(name);
241    if ( it == NameHt.end() )
242    {
243       return 0;
244    }
245    return &(it->second);
246 }
247
248 /**
249  * \brief   Get the dictionnary entry identified by a given tag (group,element)
250  * @param   group   group of the entry to be found
251  * @param   element element of the entry to be found
252  * @return  the corresponding dictionnary entry when existing, NULL otherwise
253  */
254 DictEntry* Dict::GetDictEntryByNumber(uint16_t group, uint16_t element)
255 {
256    TagKey key = DictEntry::TranslateToKey(group, element);
257    TagKeyHT::iterator it = KeyHt.find(key);
258    if ( it == KeyHt.end() )
259    {
260       return 0;
261    }
262    return &(it->second);
263 }
264
265 /** 
266  * \brief   Consider all the entries of the public dicom dictionnary. 
267  *          Build all list of all the tag names of all those entries.
268  * \sa      DictSet::GetPubDictTagNamesByCategory
269  * @return  A list of all entries of the public dicom dictionnary.
270  */
271 EntryNamesList* Dict::GetDictEntryNames() 
272 {
273    EntryNamesList *result = new EntryNamesList;
274    for (TagKeyHT::iterator tag = KeyHt.begin(); tag != KeyHt.end(); ++tag)
275    {
276       result->push_back( tag->second.GetName() );
277    }
278    return result;
279 }
280
281 /** 
282  * \ingroup Dict
283  * \brief   Consider all the entries of the public dicom dictionnary.
284  *          Build an hashtable whose keys are the names of the groups
285  *          (fourth field in each line of dictionary) and whose corresponding
286  *          values are lists of all the dictionnary entries among that
287  *          group. Note that apparently the Dicom standard doesn't explicitely
288  *          define a name (as a string) for each group.
289  *          A typical usage of this method would be to enable a dynamic
290  *          configuration of a Dicom file browser: the admin/user can
291  *          select in the interface which Dicom tags should be displayed.
292  * \warning Dicom *doesn't* define any name for any 'categorie'
293  *          (the dictionnary fourth field was formerly NIH defined
294  *           - and no longer he is-
295  *           and will be removed when Dicom provides us a text file
296  *           with the 'official' Dictionnary, that would be more friendly
297  *           than asking us to perform a line by line check of the dictionnary
298  *           at the beginning of each year to -try to- guess the changes)
299  *           Therefore : please NEVER use that fourth field :-(
300  *
301  * @return  An hashtable: whose keys are the names of the groups and whose
302  *          corresponding values are lists of all the dictionnary entries
303  *          among that group.
304  */
305 EntryNamesByCatMap *Dict::GetDictEntryNamesByCategory() 
306 {
307    EntryNamesByCatMap *result = new EntryNamesByCatMap;
308
309    for (TagKeyHT::iterator tag = KeyHt.begin(); tag != KeyHt.end(); ++tag)
310    {
311       (*result)[tag->second.GetFourth()].push_back(tag->second.GetName());
312    }
313
314    return result;
315 }
316
317 //-----------------------------------------------------------------------------
318 // Protected
319
320 //-----------------------------------------------------------------------------
321 // Private
322
323 //-----------------------------------------------------------------------------
324
325 } // end namespace gdcm