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