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