]> Creatis software - gdcm.git/blob - src/gdcmDocEntrySet.cxx
Summer nights are really too hot to sleep.
[gdcm.git] / src / gdcmDocEntrySet.cxx
1 /*=========================================================================
2                                                                                 
3   Program:   gdcm
4   Module:    $RCSfile: gdcmDocEntrySet.cxx,v $
5   Language:  C++
6   Date:      $Date: 2005/06/24 10:55:59 $
7   Version:   $Revision: 1.57 $
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       gdcmWarningMacro( "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       gdcmWarningMacro( "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       gdcmWarningMacro( "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       gdcmWarningMacro( "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             gdcmWarningMacro( "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          gdcmWarningMacro("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             gdcmWarningMacro( "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          gdcmWarningMacro( "AddEntry failed although 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 Doc 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          seqEntry = NULL;
395
396       // if currentEntry doesn't correspond to the requested seqEntry
397       if ( !seqEntry )
398       {
399          if (!RemoveEntry(currentEntry))
400          {
401             gdcmWarningMacro( "Removal of previous DocEntry failed.");
402
403             return NULL;
404          }
405       }
406    }
407    // Create a new seqEntry if necessary
408    if ( !seqEntry )
409    {
410       seqEntry = NewSeqEntry(group, elem);
411
412       if ( !AddEntry(seqEntry) )
413       {
414          gdcmWarningMacro( "AddEntry failed although this is a creation.");
415
416          delete seqEntry;
417          return NULL;
418       }
419    }
420
421    // TODO : Find a trick to insert a SequenceDelimitationItem 
422    //       in the SeqEntry, at the end.
423    return seqEntry;
424
425  
426 /**
427  * \brief   Checks if a given Dicom Element exists within the H table
428  * @param   group   Group number of the searched Dicom Element 
429  * @param   elem  Element number of the searched Dicom Element 
430  * @return true is found
431  */
432 bool DocEntrySet::CheckIfEntryExist(uint16_t group, uint16_t elem )
433 {
434    return GetDocEntry(group,elem)!=NULL;
435 }
436
437 /**
438  * \brief   Build a new Val Entry from all the low level arguments. 
439  *          Check for existence of dictionary entry, and build
440  *          a default one when absent.
441  * @param   group Group number   of the new Entry
442  * @param   elem  Element number of the new Entry
443  * @param   vr    V(alue) R(epresentation) of the new Entry 
444  */
445 ValEntry *DocEntrySet::NewValEntry(uint16_t group,uint16_t elem,
446                                    TagName const &vr) 
447 {
448    DictEntry *dictEntry = GetDictEntry(group, elem, vr);
449    gdcmAssertMacro(dictEntry);
450
451    ValEntry *newEntry = new ValEntry(dictEntry);
452    if (!newEntry) 
453    {
454       gdcmWarningMacro( "Failed to allocate ValEntry");
455       return 0;
456    }
457    return newEntry;
458 }
459
460
461 /**
462  * \brief   Build a new Bin Entry from all the low level arguments. 
463  *          Check for existence of dictionary entry, and build
464  *          a default one when absent.
465  * @param   group Group   number of the new Entry
466  * @param   elem  Element number of the new Entry
467  * @param   vr    V(alue) R(epresentation) of the new Entry 
468  */
469 BinEntry *DocEntrySet::NewBinEntry(uint16_t group, uint16_t elem,
470                                    TagName const &vr) 
471 {
472    DictEntry *dictEntry = GetDictEntry(group, elem, vr);
473    gdcmAssertMacro(dictEntry);
474
475    BinEntry *newEntry = new BinEntry(dictEntry);
476    if (!newEntry) 
477    {
478       gdcmWarningMacro( "Failed to allocate BinEntry");
479       return 0;
480    }
481    return newEntry;
482 }
483
484 /**
485  * \brief   Build a new Seq Entry from all the low level arguments. 
486  *          Check for existence of dictionary entry, and build
487  *          a default one when absent.
488  * @param   group Group   number of the new Entry
489  * @param   elem  Element number of the new Entry
490  */
491 SeqEntry* DocEntrySet::NewSeqEntry(uint16_t group, uint16_t elem) 
492 {
493    DictEntry *dictEntry = GetDictEntry(group, elem, "SQ");
494    gdcmAssertMacro(dictEntry);
495
496    SeqEntry *newEntry = new SeqEntry( dictEntry );
497    if (!newEntry)
498    {
499       gdcmWarningMacro( "Failed to allocate SeqEntry");
500       return 0;
501    }
502    return newEntry;
503 }
504
505 /**
506  * \brief   Request a new virtual dict entry to the dict set
507  * @param   group Group   number of the underlying DictEntry
508  * @param   elem  Element number of the underlying DictEntry
509  * @param   vr    V(alue) R(epresentation) of the underlying DictEntry
510  * @param   vm    V(alue) M(ultiplicity)   of the underlying DictEntry
511  * @param   name   english name
512  */
513 DictEntry* DocEntrySet::NewVirtualDictEntry( uint16_t group, uint16_t elem,
514                                              TagName const &vr,
515                                              TagName const &vm,
516                                              TagName const &name )
517 {
518    return Global::GetDicts()->NewVirtualDictEntry(group,elem,vr,vm,name);
519 }
520
521 //-----------------------------------------------------------------------------
522 // Protected
523 /**
524  * \brief   Searches [both] the public [and the shadow dictionary (when they
525  *          exist)] for the presence of the DictEntry with given
526  *          group and element. The public dictionary has precedence on the
527  *          shadow one(s), if any.
528  * @param   group  Group number of the searched DictEntry
529  * @param   elem Element number of the searched DictEntry
530  * @return  Corresponding DictEntry when it exists, NULL otherwise.
531  */
532 DictEntry *DocEntrySet::GetDictEntry(uint16_t group,uint16_t elem) 
533 {
534    DictEntry *found = 0;
535    Dict *pubDict = Global::GetDicts()->GetDefaultPubDict();
536    if (!pubDict) 
537    {
538       gdcmWarningMacro( "We SHOULD have a default dictionary");
539    }
540    else
541    {
542       found = pubDict->GetEntry(group, elem);  
543    }
544    return found;
545 }
546
547 /**
548  * \brief   Searches [both] the public [and the shadow dictionary (when they
549  *          exist)] for the presence of the DictEntry with given
550  *          group and element, and create a new virtual DictEntry if necessary
551  * @param   group  group number of the searched DictEntry
552  * @param   elem element number of the searched DictEntry
553  * @param   vr V(alue) R(epresentation) to use, if necessary 
554  * @return  Corresponding DictEntry when it exists, NULL otherwise.
555  */
556 DictEntry *DocEntrySet::GetDictEntry(uint16_t group, uint16_t elem,
557                                      TagName const &vr)
558 {
559    DictEntry *dictEntry = GetDictEntry(group,elem);
560    DictEntry *goodEntry = dictEntry;
561    std::string goodVR = vr;
562
563    if (elem == 0x0000) goodVR="UL";
564
565    if ( goodEntry )
566    {
567       if ( goodVR != goodEntry->GetVR()
568         && goodVR != GDCM_UNKNOWN )
569       {
570          goodEntry = NULL;
571       }
572    }
573
574    // Create a new virtual DictEntry if necessary
575    if (!goodEntry)
576    {
577       if (dictEntry)
578       {
579          goodEntry = NewVirtualDictEntry(group, elem, goodVR, "FIXME", 
580                                          dictEntry->GetName() );
581       }
582       else
583       {
584          goodEntry = NewVirtualDictEntry(group, elem, goodVR);
585       }
586    }
587    return goodEntry;
588 }
589
590 //-----------------------------------------------------------------------------
591 // Private
592
593 //-----------------------------------------------------------------------------
594 // Print
595
596 //-----------------------------------------------------------------------------
597 } // end namespace gdcm