]> Creatis software - gdcm.git/blob - src/gdcmDocEntrySet.cxx
To avoid futher confusion in Validator, when the VR found on disc missmatches
[gdcm.git] / src / gdcmDocEntrySet.cxx
1 /*=========================================================================
2                                                                                 
3   Program:   gdcm
4   Module:    $RCSfile: gdcmDocEntrySet.cxx,v $
5   Language:  C++
6   Date:      $Date: 2005/11/21 09:41:46 $
7   Version:   $Revision: 1.68 $
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   Searches within the DocEntrySet
79  *          for the value length of a given tag..
80  * @param   group  Group number of the searched tag.
81  * @param   elem Element number of the searched tag.
82  * @return  Corresponding element length; -1 if not found
83  */
84 int DocEntrySet::GetEntryLength(uint16_t group, uint16_t elem)
85 {
86    DocEntry *entry = GetDocEntry(group, elem);
87    if ( entry )
88       return entry->GetLength();
89    return -1;
90 }
91
92 /**
93  * \brief  Same as \ref Document::GetDocEntry except it returns a result 
94  *         only when the corresponding entry is of type DataEntry.
95  * @param   group  Group number of the searched Dicom Element 
96  * @param   elem Element number of the searched Dicom Element  
97  * @return When present, the corresponding DataEntry. 
98  */
99 DataEntry *DocEntrySet::GetDataEntry(uint16_t group, uint16_t elem)
100 {
101    DocEntry *currentEntry = GetDocEntry(group, elem);
102    if ( !currentEntry )
103       return NULL;
104
105    return dynamic_cast<DataEntry*>(currentEntry);
106 }
107
108 /**
109  * \brief  Same as \ref Document::GetDocEntry except it returns a result
110  *          only when the corresponding entry is of type SeqEntry.
111  * @param   group  Group number of the searched Dicom Element 
112  * @param   elem Element number of the searched Dicom Element  
113  * @return When present, the corresponding SeqEntry. 
114  */
115 SeqEntry *DocEntrySet::GetSeqEntry(uint16_t group, uint16_t elem)
116 {
117    DocEntry *currentEntry = GetDocEntry(group, elem);
118    if ( !currentEntry )
119       return NULL;
120       
121    return dynamic_cast<SeqEntry*>(currentEntry);
122 }
123
124 /**
125  * \brief   Accesses an existing DocEntry (i.e. a Dicom Element)
126  *          through it's (group, element) and modifies it's content with
127  *          the given value.
128  * @param   content new value (string) to substitute with
129  * @param   group  group number of the Dicom Element to modify
130  * @param   elem element number of the Dicom Element to modify
131  */
132 bool DocEntrySet::SetEntryString(std::string const &content, 
133                                  uint16_t group, uint16_t elem) 
134 {
135    DataEntry *entry = GetDataEntry(group, elem);
136    if (!entry )
137    {
138       gdcmWarningMacro( "No corresponding DataEntry " << std::hex << group <<
139                          "," << elem << " element (try promotion first).");
140       return false;
141    }
142    return SetEntryString(content,entry);
143 }
144
145 /**
146  * \brief   Accesses an existing DocEntry (i.e. a Dicom Element)
147  *          through it's (group, element) and modifies it's content with
148  *          the given value.
149  * @param   content new value (void*  -> uint8_t*) to substitute with
150  * @param   lgth new value length
151  * @param   group  group number of the Dicom Element to modify
152  * @param   elem element number of the Dicom Element to modify
153  */
154 bool DocEntrySet::SetEntryBinArea(uint8_t *content, int lgth, 
155                                   uint16_t group, uint16_t elem) 
156 {
157    DataEntry *entry = GetDataEntry(group, elem);
158    if (!entry )
159    {
160       gdcmWarningMacro( "No corresponding DataEntry " << std::hex << group <<
161                         "," << elem << " element (try promotion first).");
162       return false;
163    }
164
165    return SetEntryBinArea(content,lgth,entry);
166
167
168 /**
169  * \brief   Accesses an existing DocEntry (i.e. a Dicom Element)
170  *          and modifies it's content with the given value.
171  * @param  content new value (string) to substitute with
172  * @param  entry Entry to be modified
173  */
174 bool DocEntrySet::SetEntryString(std::string const &content, DataEntry *entry)
175 {
176    if (entry)
177    {
178       entry->SetString(content);
179       return true;
180    }
181    return false;
182 }
183
184 /**
185  * \brief   Accesses an existing DataEntry (i.e. a Dicom Element)
186  *          and modifies it's content with the given value.
187  * @param   content new value (void*  -> uint8_t*) to substitute with
188  * @param  entry Entry to be modified 
189  * @param  lgth new value length
190  */
191 bool DocEntrySet::SetEntryBinArea(uint8_t *content, int lgth, DataEntry *entry)
192 {
193    if (entry)
194    {
195       entry->SetLength(lgth);
196       entry->SetBinArea(content);  
197       return true;
198    }
199    return false;
200 }
201
202 /**
203  * \brief   Modifies the value of a given Doc Entry (Dicom Element)
204  *          when it exists. Create it with the given value when unexistant.
205  * @param   value (string) Value to be set
206  * @param   group   Group number of the Entry 
207  * @param   elem  Element number of the Entry
208  * @param   vr  V(alue) R(epresentation) of the Entry -if private Entry-
209  * \return  pointer to the modified/created Header Entry (NULL when creation
210  *          failed).
211  */ 
212 DataEntry *DocEntrySet::InsertEntryString(std::string const &value, 
213                                              uint16_t group, uint16_t elem,
214                                              VRKey const &vr )
215 {
216    DataEntry *dataEntry = 0;
217    DocEntry *currentEntry = GetDocEntry( group, elem );
218    
219    if (currentEntry)
220    {
221       dataEntry = dynamic_cast<DataEntry *>(currentEntry);
222
223       // Verify the VR
224       if ( dataEntry )
225          if ( dataEntry->GetVR()!=vr )
226             dataEntry = NULL;
227
228       // if currentEntry doesn't correspond to the requested dataEntry
229       if ( !dataEntry)
230       {
231          if ( !RemoveEntry(currentEntry) )
232          {
233             gdcmWarningMacro( "Removal of previous DocEntry failed.");
234             return NULL;
235          }
236       }
237    }
238
239    // Create a new dataEntry if necessary
240    if ( !dataEntry )
241    {
242       dataEntry = NewDataEntry( group, elem, vr );
243
244       if ( !AddEntry(dataEntry) )
245       {
246          gdcmWarningMacro("AddEntry failed although this is a creation.");
247          dataEntry->Delete();
248          return NULL;
249       }
250       dataEntry->Delete();
251    }
252
253    // Set the dataEntry value
254    SetEntryString(value, dataEntry); // The std::string value
255    return dataEntry;
256 }
257
258 /**
259  * \brief   Modifies the value of a given Header Entry (Dicom Element)
260  *          when it exists. Create it with the given value when unexistant.
261  *          A copy of the binArea is made to be kept in the Document.
262  * @param   binArea (binary) value to be set
263  * @param   lgth length of the Bin Area we want to set
264  * @param   group   Group number of the Entry 
265  * @param   elem  Element number of the Entry
266  * @param   vr  V(alue) R(epresentation) of the Entry -if private Entry-
267  * \return  pointer to the modified/created Header Entry (NULL when creation
268  *          failed).
269  */
270 DataEntry *DocEntrySet::InsertEntryBinArea(uint8_t *binArea, int lgth, 
271                                               uint16_t group, uint16_t elem,
272                                               VRKey const &vr )
273 {
274    DataEntry *dataEntry = 0;
275    DocEntry *currentEntry = GetDocEntry( group, elem );
276
277    // Verify the currentEntry
278    if (currentEntry)
279    {
280       dataEntry = dynamic_cast<DataEntry *>(currentEntry);
281
282       // Verify the VR
283       if ( dataEntry )
284          if ( dataEntry->GetVR()!=vr )
285             dataEntry = NULL;
286
287       // if currentEntry doesn't correspond to the requested dataEntry
288       if ( !dataEntry)
289       {
290          if ( !RemoveEntry(currentEntry) )
291          {
292             gdcmWarningMacro( "Removal of previous DocEntry failed.");
293             return NULL;
294          }
295       }
296    }
297
298    // Create a new dataEntry if necessary
299    if ( !dataEntry)
300    {
301       dataEntry = NewDataEntry(group, elem, vr);
302
303       if ( !AddEntry(dataEntry) )
304       {
305          gdcmWarningMacro( "AddEntry failed although this is a creation.");
306          dataEntry->Delete();
307          return NULL;
308       }
309       dataEntry->Delete();
310    }
311
312    // Set the dataEntry value
313    uint8_t *tmpArea;
314    if ( lgth>0 && binArea )
315    {
316       tmpArea = new uint8_t[lgth];
317       memcpy(tmpArea,binArea,lgth);
318    }
319    else
320    {
321       tmpArea = 0;
322    }
323    if ( !SetEntryBinArea(tmpArea,lgth,dataEntry) )
324    {
325       if ( tmpArea )
326       {
327          delete[] tmpArea;
328       }
329    }
330    return dataEntry;
331 }  
332
333 /**
334  * \brief   Creates a new gdcm::SeqEntry and adds it to the current DocEntrySet.
335  *          (remove any existing entry with same group,elem)
336  * @param   group   Group number of the Entry 
337  * @param   elem  Element number of the Entry
338  * \return  pointer to the created SeqEntry (NULL when creation
339  *          failed).
340  */
341 SeqEntry *DocEntrySet::InsertSeqEntry(uint16_t group, uint16_t elem)
342 {
343    SeqEntry *seqEntry = 0;
344    DocEntry *currentEntry = GetDocEntry( group, elem );
345
346    // Verify the currentEntry
347    if ( currentEntry )
348    {
349       seqEntry = dynamic_cast<SeqEntry *>(currentEntry);
350
351       // Verify the VR
352       if ( seqEntry )
353          seqEntry = NULL;
354
355       // if currentEntry doesn't correspond to the requested seqEntry
356       if ( !seqEntry )
357       {
358          if (!RemoveEntry(currentEntry))
359          {
360             gdcmWarningMacro( "Removal of previous DocEntry failed for ("
361                <<std::hex << group << "|" << elem <<")" );
362             return NULL;
363          }
364       }
365    }
366    // Create a new seqEntry if necessary
367    if ( !seqEntry )
368    {
369       seqEntry = NewSeqEntry(group, elem);
370
371       if ( !AddEntry(seqEntry) )
372       {
373          gdcmWarningMacro( "AddEntry failed although this is a creation for ("
374             <<std::hex << group << "|" << elem <<")" );
375          seqEntry->Delete();
376          return NULL;
377       }
378       seqEntry->Delete();
379    }
380    // Remark :
381    // SequenceDelimitationItem will be added at the end of the SeqEntry,
382    // at write time
383    return seqEntry;
384
385  
386 /**
387  * \brief   Checks if a given Dicom Element exists within the DocEntrySet
388  * @param   group   Group number of the searched Dicom Element 
389  * @param   elem  Element number of the searched Dicom Element 
390  * @return true is found
391  */
392 bool DocEntrySet::CheckIfEntryExist(uint16_t group, uint16_t elem )
393 {
394    return GetDocEntry(group,elem)!=NULL;
395 }
396
397 /**
398  * \brief   Build a new DataEntry from all the low level arguments. 
399  *          Check for existence of dictionary entry, and build
400  *          a default one when absent.
401  * @param   group Group number   of the new Entry
402  * @param   elem  Element number of the new Entry
403  * @param   vr    V(alue) R(epresentation) of the new Entry 
404  * \remarks The user of this method must destroy the DataEntry when unused
405  */
406 DataEntry *DocEntrySet::NewDataEntry(uint16_t group,uint16_t elem,
407                                      VRKey const &vr) 
408 {
409    DictEntry *dictEntry = GetDictEntry(group, elem, vr);
410
411    DataEntry *newEntry = DataEntry::New(dictEntry);
412    dictEntry->Unregister(); // GetDictEntry register it
413    if (!newEntry) 
414    {
415       gdcmWarningMacro( "Failed to allocate DataEntry for ("
416           <<std::hex << group << "|" << elem <<")" );
417       return 0;
418    }
419    return newEntry;
420 }
421
422 /**
423  * \brief   Build a new SeqEntry from all the low level arguments. 
424  *          Check for existence of dictionary entry, and build
425  *          a default one when absent.
426  * @param   group Group   number of the new Entry
427  * @param   elem  Element number of the new Entry
428  * \remarks The user of this method must destroy the SeqEntry when unused
429  */
430 SeqEntry* DocEntrySet::NewSeqEntry(uint16_t group, uint16_t elem) 
431 {
432    DictEntry *dictEntry = GetDictEntry(group, elem, "SQ");
433
434    SeqEntry *newEntry = SeqEntry::New( dictEntry );
435    dictEntry->Unregister(); // GetDictEntry register it
436    if (!newEntry)
437    {
438       gdcmWarningMacro( "Failed to allocate SeqEntry for ("
439          <<std::hex << group << "|" << elem <<")" );
440       return 0;
441    }
442    return newEntry;
443 }
444
445 //-----------------------------------------------------------------------------
446 // Protected
447 /**
448  * \brief   Searches [both] the public [and the shadow dictionary (when they
449  *          exist)] for the presence of the DictEntry with given
450  *          group and element. The public dictionary has precedence on the
451  *          shadow one(s), if any.
452  * @param   group  Group number of the searched DictEntry
453  * @param   elem Element number of the searched DictEntry
454  * @return  Corresponding DictEntry when it exists, NULL otherwise.
455  * \remarks The returned DictEntry is registered when existing
456  */
457 DictEntry *DocEntrySet::GetDictEntry(uint16_t group,uint16_t elem) 
458 {
459    DictEntry *found = 0;
460    Dict *pubDict = Global::GetDicts()->GetDefaultPubDict();
461    if (!pubDict) 
462    {
463       gdcmWarningMacro( "We SHOULD have a default dictionary");
464    }
465    else
466    {
467       found = pubDict->GetEntry(group, elem);
468       if( found )
469          found->Register();
470    }
471    return found;
472 }
473
474 /**
475  * \brief   Searches [both] the public [and the shadow dictionary (when they
476  *          exist)] for the presence of the DictEntry with given
477  *          group and element, and create a new virtual DictEntry if necessary
478  * @param   group  group number of the searched DictEntry
479  * @param   elem element number of the searched DictEntry
480  * @param   vr V(alue) R(epresentation) to use, if necessary 
481  * @return  Corresponding DictEntry when it exists, NULL otherwise.
482  * \remarks The returned DictEntry is registered
483  */
484 DictEntry *DocEntrySet::GetDictEntry(uint16_t group, uint16_t elem,
485                                      VRKey const &vr)
486 {
487    DictEntry *dictEntry = GetDictEntry(group,elem);
488    DictEntry *goodEntry = dictEntry;
489    VRKey goodVR = vr;
490    TagName vm;
491    if (elem == 0x0000) 
492       goodVR="UL";
493
494    if ( goodEntry )
495    {
496       if ( goodVR != goodEntry->GetVR()
497         && goodVR != GDCM_VRUNKNOWN )
498       { 
499          gdcmWarningMacro("For (" << std::hex << group << "|"
500             << elem << "), found VR : [" << vr << "]"
501             << " expected: [" << goodEntry->GetVR() << "]" ) ;
502         // avoid confusing further validator with "FIXME" VM
503         // when possible      
504          vm = dictEntry->GetVM();
505          goodEntry = NULL;
506       }
507       dictEntry->Unregister();
508    }
509    else
510    {
511       vm = "FIXME";
512    }
513    // Create a new virtual DictEntry if necessary
514    if (!goodEntry)
515    {
516       if (dictEntry)
517       {
518
519          goodEntry = DictEntry::New(group, elem, goodVR, vm,//"FIXME", 
520                                     dictEntry->GetName() );
521       }
522       else
523       {
524          goodEntry = DictEntry::New(group, elem, goodVR);
525       }
526    }
527    else
528    {
529       goodEntry->Register();
530    }
531    return goodEntry;
532 }
533
534 //-----------------------------------------------------------------------------
535 // Private
536
537 //-----------------------------------------------------------------------------
538 // Print
539
540 //-----------------------------------------------------------------------------
541 } // end namespace gdcm