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