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