]> Creatis software - gdcm.git/blob - src/gdcmDocEntrySet.cxx
* Correctly use the VRKey for all vr variables... instead of TagName
[gdcm.git] / src / gdcmDocEntrySet.cxx
1 /*=========================================================================
2                                                                                 
3   Program:   gdcm
4   Module:    $RCSfile: gdcmDocEntrySet.cxx,v $
5   Language:  C++
6   Date:      $Date: 2005/10/18 12:58:28 $
7   Version:   $Revision: 1.61 $
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 #include "gdcmDocEntrySet.h"
19
20 #include "gdcmDebug.h"
21 #include "gdcmCommon.h"
22 #include "gdcmDictSet.h"
23 #include "gdcmGlobal.h"
24 #include "gdcmDocEntry.h"
25 #include "gdcmSeqEntry.h"
26 #include "gdcmUtil.h"
27 #include "gdcmDataEntry.h"
28 #include "gdcmVR.h"
29
30 namespace gdcm 
31 {
32 //-----------------------------------------------------------------------------
33 // Constructor / Destructor
34 DocEntrySet::DocEntrySet() 
35
36    PreviousDocEntry = 0;
37 }
38 //-----------------------------------------------------------------------------
39 // Public
40 /**
41  * \brief   Get the "std::string representable" value of the Dicom entry
42  * @param   group  Group number of the searched tag.
43  * @param   elem Element number of the searched tag.
44  * @return  Corresponding element value when it exists,
45  *          and the string GDCM_UNFOUND otherwise.
46  */
47 std::string DocEntrySet::GetEntryString(uint16_t group, uint16_t elem)
48 {
49    DataEntry *entry = dynamic_cast<DataEntry *>(GetDocEntry(group,elem));
50    if ( entry )
51    {
52       if( entry->IsNotLoaded() )
53          return GDCM_NOTLOADED;
54       if( entry->IsUnfound() )
55          return GDCM_UNFOUND;
56       if( entry->IsUnread() )
57          return GDCM_UNREAD;
58       return entry->GetString();
59    }
60    return GDCM_UNFOUND;
61 }
62
63 /**
64  * \brief   Gets (from Header) a 'non string' element value 
65  * @param group   group number of the Entry 
66  * @param elem  element number of the Entry
67  * @return Pointer to the 'non string' area
68  */
69 void *DocEntrySet::GetEntryBinArea(uint16_t group, uint16_t elem) 
70 {
71    DataEntry *entry = GetDataEntry(group, elem);
72    if ( entry )
73       return entry->GetBinArea();
74    return 0;
75 }
76
77 /**
78  * \brief   Return the value of the DataEntry if it's "std::string representable"
79  * @param   group  Group number of the searched tag.
80  * @param   elem Element number of the searched tag.
81  * @return  Corresponding element value when it's "std::string representable"
82  *          and the string GDCM_NOTASCII otherwise.
83  */
84 std::string DocEntrySet::GetEntryForcedAsciiValue(uint16_t group, uint16_t elem)
85 {
86    DocEntry *d = GetDocEntry(group,elem);
87    if ( !d )
88       return GDCM_UNFOUND;
89
90    DataEntry *de = dynamic_cast<DataEntry *>(d);
91    if ( de )
92    {
93       if( de->IsNotLoaded() )
94          return GDCM_NOTLOADED;
95       if( de->IsUnfound() )
96          return GDCM_UNFOUND;
97       if( de->IsUnread() )
98          return GDCM_UNREAD;
99    }
100
101    if( Global::GetVR()->IsVROfStringRepresentable( de->GetVR() ) )
102       return de->GetString();
103    else
104    {
105       uint8_t *a = de->GetBinArea();
106       if( Util::IsCleanArea(a, de->GetLength()) )
107          return  Util::CreateCleanString(a, de->GetLength());
108    }
109    return GDCM_NOTASCII;
110 }
111
112 /**
113  * \brief   Searches within Header Entries (Dicom Elements) parsed with 
114  *          the public and private dictionaries 
115  *          for the value length of a given tag..
116  * @param   group  Group number of the searched tag.
117  * @param   elem Element number of the searched tag.
118  * @return  Corresponding element length; -2 if not found
119  */
120 int DocEntrySet::GetEntryLength(uint16_t group, uint16_t elem)
121 {
122    DocEntry *entry = GetDocEntry(group, elem);
123    if ( entry )
124       return entry->GetLength();
125    return -1;
126 }
127
128 /**
129  * \brief  Same as \ref Document::GetDocEntry except it only
130  *         returns a result when the corresponding entry is of type
131  *         DataEntry.
132  * @param   group  Group number of the searched Dicom Element 
133  * @param   elem Element number of the searched Dicom Element  
134  * @return When present, the corresponding DataEntry. 
135  */
136 DataEntry *DocEntrySet::GetDataEntry(uint16_t group, uint16_t elem)
137 {
138    DocEntry *currentEntry = GetDocEntry(group, elem);
139    if ( !currentEntry )
140       return NULL;
141
142    return dynamic_cast<DataEntry*>(currentEntry);
143 }
144
145 /**
146  * \brief  Same as \ref Document::GetDocEntry except it only
147  *         returns a result when the corresponding entry is of type
148  *         SeqEntry.
149  * @param   group  Group number of the searched Dicom Element 
150  * @param   elem Element number of the searched Dicom Element  
151  * @return When present, the corresponding SeqEntry. 
152  */
153 SeqEntry *DocEntrySet::GetSeqEntry(uint16_t group, uint16_t elem)
154 {
155    DocEntry *currentEntry = GetDocEntry(group, elem);
156    if ( !currentEntry )
157    {
158       gdcmWarningMacro( "No corresponding SeqEntry " << std::hex << group <<
159                         "," << elem);
160       return NULL;
161    }
162
163    return dynamic_cast<SeqEntry*>(currentEntry);
164 }
165
166 /**
167  * \brief   Accesses an existing DocEntry (i.e. a Dicom Element)
168  *          through it's (group, element) and modifies it's content with
169  *          the given value.
170  * @param   content new value (string) to substitute with
171  * @param   group  group number of the Dicom Element to modify
172  * @param   elem element number of the Dicom Element to modify
173  */
174 bool DocEntrySet::SetEntryString(std::string const &content, 
175                                  uint16_t group, uint16_t elem) 
176 {
177    DataEntry *entry = GetDataEntry(group, elem);
178    if (!entry )
179    {
180       gdcmWarningMacro( "No corresponding DataEntry " << std::hex << group <<
181                          "," << elem << " element (try promotion first).");
182       return false;
183    }
184    return SetEntryString(content,entry);
185 }
186
187 /**
188  * \brief   Accesses an existing DocEntry (i.e. a Dicom Element)
189  *          through it's (group, element) and modifies it's content with
190  *          the given value.
191  * @param   content new value (void*  -> uint8_t*) to substitute with
192  * @param   lgth new value length
193  * @param   group  group number of the Dicom Element to modify
194  * @param   elem element number of the Dicom Element to modify
195  */
196 bool DocEntrySet::SetEntryBinArea(uint8_t *content, int lgth, 
197                                   uint16_t group, uint16_t elem) 
198 {
199    DataEntry *entry = GetDataEntry(group, elem);
200    if (!entry )
201    {
202       gdcmWarningMacro( "No corresponding DataEntry " << std::hex << group <<
203                         "," << elem << " element (try promotion first).");
204       return false;
205    }
206
207    return SetEntryBinArea(content,lgth,entry);
208
209
210 /**
211  * \brief   Accesses an existing DocEntry (i.e. a Dicom Element)
212  *          and modifies it's content with the given value.
213  * @param  content new value (string) to substitute with
214  * @param  entry Entry to be modified
215  */
216 bool DocEntrySet::SetEntryString(std::string const &content, DataEntry *entry)
217 {
218    if (entry)
219    {
220       entry->SetString(content);
221       return true;
222    }
223    return false;
224 }
225
226 /**
227  * \brief   Accesses an existing DataEntry (i.e. a Dicom Element)
228  *          and modifies it's content with the given value.
229  * @param   content new value (void*  -> uint8_t*) to substitute with
230  * @param  entry Entry to be modified 
231  * @param  lgth new value length
232  */
233 bool DocEntrySet::SetEntryBinArea(uint8_t *content, int lgth, DataEntry *entry)
234 {
235    if (entry)
236    {
237       entry->SetLength(lgth);
238       entry->SetBinArea(content);  
239       return true;
240    }
241    return false;
242 }
243
244 /**
245  * \brief   Modifies the value of a given Doc Entry (Dicom Element)
246  *          when it exists. Create it with the given value when unexistant.
247  * @param   value (string) Value to be set
248  * @param   group   Group number of the Entry 
249  * @param   elem  Element number of the Entry
250  * @param   vr  V(alue) R(epresentation) of the Entry -if private Entry-
251  * \return  pointer to the modified/created Header Entry (NULL when creation
252  *          failed).
253  */ 
254 DataEntry *DocEntrySet::InsertEntryString(std::string const &value, 
255                                              uint16_t group, uint16_t elem,
256                                              VRKey const &vr )
257 {
258    DataEntry *dataEntry = 0;
259    DocEntry *currentEntry = GetDocEntry( group, elem );
260    
261    if (currentEntry)
262    {
263       dataEntry = dynamic_cast<DataEntry *>(currentEntry);
264
265       // Verify the VR
266       if ( dataEntry )
267          if ( dataEntry->GetVR()!=vr )
268             dataEntry = NULL;
269
270       // if currentEntry doesn't correspond to the requested dataEntry
271       if ( !dataEntry)
272       {
273          if ( !RemoveEntry(currentEntry) )
274          {
275             gdcmWarningMacro( "Removal of previous DocEntry failed.");
276             return NULL;
277          }
278       }
279    }
280
281    // Create a new dataEntry if necessary
282    if ( !dataEntry )
283    {
284       dataEntry = NewDataEntry( group, elem, vr );
285
286       if ( !AddEntry(dataEntry) )
287       {
288          gdcmWarningMacro("AddEntry failed although this is a creation.");
289
290          delete dataEntry;
291          return NULL;
292       }
293    }
294
295    // Set the dataEntry value
296    SetEntryString(value, dataEntry); // The std::string value
297    return dataEntry;
298 }
299
300 /**
301  * \brief   Modifies the value of a given Header Entry (Dicom Element)
302  *          when it exists. Create it with the given value when unexistant.
303  *          A copy of the binArea is made to be kept in the Document.
304  * @param   binArea (binary) value to be set
305  * @param   lgth length of the Bin Area we want to set
306  * @param   group   Group number of the Entry 
307  * @param   elem  Element number of the Entry
308  * @param   vr  V(alue) R(epresentation) of the Entry -if private Entry-
309  * \return  pointer to the modified/created Header Entry (NULL when creation
310  *          failed).
311  */
312 DataEntry *DocEntrySet::InsertEntryBinArea(uint8_t *binArea, int lgth, 
313                                               uint16_t group, uint16_t elem,
314                                               VRKey const &vr )
315 {
316    DataEntry *dataEntry = 0;
317    DocEntry *currentEntry = GetDocEntry( group, elem );
318
319    // Verify the currentEntry
320    if (currentEntry)
321    {
322       dataEntry = dynamic_cast<DataEntry *>(currentEntry);
323
324       // Verify the VR
325       if ( dataEntry )
326          if ( dataEntry->GetVR()!=vr )
327             dataEntry = NULL;
328
329       // if currentEntry doesn't correspond to the requested dataEntry
330       if ( !dataEntry)
331       {
332          if ( !RemoveEntry(currentEntry) )
333          {
334             gdcmWarningMacro( "Removal of previous DocEntry failed.");
335             return NULL;
336          }
337       }
338    }
339
340    // Create a new dataEntry if necessary
341    if ( !dataEntry)
342    {
343       dataEntry = NewDataEntry(group, elem, vr);
344
345       if ( !AddEntry(dataEntry) )
346       {
347          gdcmWarningMacro( "AddEntry failed although this is a creation.");
348
349          delete dataEntry;
350          return NULL;
351       }
352    }
353
354    // Set the dataEntry value
355    uint8_t *tmpArea;
356    if ( lgth>0 && binArea )
357    {
358       tmpArea = new uint8_t[lgth];
359       memcpy(tmpArea,binArea,lgth);
360    }
361    else
362    {
363       tmpArea = 0;
364    }
365    if ( !SetEntryBinArea(tmpArea,lgth,dataEntry) )
366    {
367       if ( tmpArea )
368       {
369          delete[] tmpArea;
370       }
371    }
372
373    return dataEntry;
374 }  
375
376 /**
377  * \brief   Modifies the value of a given Doc Entry (Dicom Element)
378  *          when it exists. Creates it when unexistant.
379  * @param   group   Group number of the Entry 
380  * @param   elem  Element number of the Entry
381  * \return  pointer to the modified/created SeqEntry (NULL when creation
382  *          failed).
383  */
384 SeqEntry *DocEntrySet::InsertSeqEntry(uint16_t group, uint16_t elem)
385 {
386    SeqEntry *seqEntry = 0;
387    DocEntry *currentEntry = GetDocEntry( group, elem );
388
389    // Verify the currentEntry
390    if ( currentEntry )
391    {
392       seqEntry = dynamic_cast<SeqEntry *>(currentEntry);
393
394       // Verify the VR
395       if ( seqEntry )
396          seqEntry = NULL;
397
398       // if currentEntry doesn't correspond to the requested seqEntry
399       if ( !seqEntry )
400       {
401          if (!RemoveEntry(currentEntry))
402          {
403             gdcmWarningMacro( "Removal of previous DocEntry failed.");
404
405             return NULL;
406          }
407       }
408    }
409    // Create a new seqEntry if necessary
410    if ( !seqEntry )
411    {
412       seqEntry = NewSeqEntry(group, elem);
413
414       if ( !AddEntry(seqEntry) )
415       {
416          gdcmWarningMacro( "AddEntry failed although this is a creation.");
417
418          delete seqEntry;
419          return NULL;
420       }
421    }
422
423    // TODO : Find a trick to insert a SequenceDelimitationItem 
424    //       in the SeqEntry, at the end.
425    return seqEntry;
426
427  
428 /**
429  * \brief   Checks if a given Dicom Element exists within the H table
430  * @param   group   Group number of the searched Dicom Element 
431  * @param   elem  Element number of the searched Dicom Element 
432  * @return true is found
433  */
434 bool DocEntrySet::CheckIfEntryExist(uint16_t group, uint16_t elem )
435 {
436    return GetDocEntry(group,elem)!=NULL;
437 }
438
439 /**
440  * \brief   Build a new Val Entry from all the low level arguments. 
441  *          Check for existence of dictionary entry, and build
442  *          a default one when absent.
443  * @param   group Group number   of the new Entry
444  * @param   elem  Element number of the new Entry
445  * @param   vr    V(alue) R(epresentation) of the new Entry 
446  */
447 DataEntry *DocEntrySet::NewDataEntry(uint16_t group,uint16_t elem,
448                                      VRKey const &vr) 
449 {
450    DictEntry *dictEntry = GetDictEntry(group, elem, vr);
451    gdcmAssertMacro(dictEntry);
452
453    DataEntry *newEntry = new DataEntry(dictEntry);
454    if (!newEntry) 
455    {
456       gdcmWarningMacro( "Failed to allocate DataEntry");
457       return 0;
458    }
459    return newEntry;
460 }
461
462 /**
463  * \brief   Build a new Seq Entry from all the low level arguments. 
464  *          Check for existence of dictionary entry, and build
465  *          a default one when absent.
466  * @param   group Group   number of the new Entry
467  * @param   elem  Element number of the new Entry
468  */
469 SeqEntry* DocEntrySet::NewSeqEntry(uint16_t group, uint16_t elem) 
470 {
471    DictEntry *dictEntry = GetDictEntry(group, elem, "SQ");
472    gdcmAssertMacro(dictEntry);
473
474    SeqEntry *newEntry = new SeqEntry( dictEntry );
475    if (!newEntry)
476    {
477       gdcmWarningMacro( "Failed to allocate SeqEntry");
478       return 0;
479    }
480    return newEntry;
481 }
482
483 /**
484  * \brief   Request a new virtual dict entry to the dict set
485  * @param   group Group   number of the underlying DictEntry
486  * @param   elem  Element number of the underlying DictEntry
487  * @param   vr    V(alue) R(epresentation) of the underlying DictEntry
488  * @param   vm    V(alue) M(ultiplicity)   of the underlying DictEntry
489  * @param   name   english name
490  */
491 DictEntry* DocEntrySet::NewVirtualDictEntry( uint16_t group, uint16_t elem,
492                                              VRKey const &vr,
493                                              TagName const &vm,
494                                              TagName const &name )
495 {
496    return Global::GetDicts()->NewVirtualDictEntry(group,elem,vr,vm,name);
497 }
498
499 //-----------------------------------------------------------------------------
500 // Protected
501 /**
502  * \brief   Searches [both] the public [and the shadow dictionary (when they
503  *          exist)] for the presence of the DictEntry with given
504  *          group and element. The public dictionary has precedence on the
505  *          shadow one(s), if any.
506  * @param   group  Group number of the searched DictEntry
507  * @param   elem Element number of the searched DictEntry
508  * @return  Corresponding DictEntry when it exists, NULL otherwise.
509  */
510 DictEntry *DocEntrySet::GetDictEntry(uint16_t group,uint16_t elem) 
511 {
512    DictEntry *found = 0;
513    Dict *pubDict = Global::GetDicts()->GetDefaultPubDict();
514    if (!pubDict) 
515    {
516       gdcmWarningMacro( "We SHOULD have a default dictionary");
517    }
518    else
519    {
520       found = pubDict->GetEntry(group, elem);  
521    }
522    return found;
523 }
524
525 /**
526  * \brief   Searches [both] the public [and the shadow dictionary (when they
527  *          exist)] for the presence of the DictEntry with given
528  *          group and element, and create a new virtual DictEntry if necessary
529  * @param   group  group number of the searched DictEntry
530  * @param   elem element number of the searched DictEntry
531  * @param   vr V(alue) R(epresentation) to use, if necessary 
532  * @return  Corresponding DictEntry when it exists, NULL otherwise.
533  */
534 DictEntry *DocEntrySet::GetDictEntry(uint16_t group, uint16_t elem,
535                                      VRKey const &vr)
536 {
537    DictEntry *dictEntry = GetDictEntry(group,elem);
538    DictEntry *goodEntry = dictEntry;
539    VRKey goodVR = vr;
540
541    if (elem == 0x0000) goodVR="UL";
542
543    if ( goodEntry )
544    {
545       if ( goodVR != goodEntry->GetVR()
546         && goodVR != GDCM_VRUNKNOWN )
547       {
548          goodEntry = NULL;
549       }
550    }
551
552    // Create a new virtual DictEntry if necessary
553    if (!goodEntry)
554    {
555       if (dictEntry)
556       {
557          goodEntry = NewVirtualDictEntry(group, elem, goodVR, "FIXME", 
558                                          dictEntry->GetName() );
559       }
560       else
561       {
562          goodEntry = NewVirtualDictEntry(group, elem, goodVR);
563       }
564    }
565    return goodEntry;
566 }
567
568 //-----------------------------------------------------------------------------
569 // Private
570
571 //-----------------------------------------------------------------------------
572 // Print
573
574 //-----------------------------------------------------------------------------
575 } // end namespace gdcm