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