2 //-----------------------------------------------------------------------------
3 #include "gdcmDicomDir.h"
4 #include "gdcmDicomDirStudy.h"
5 #include "gdcmDicomDirSerie.h"
6 #include "gdcmDicomDirImage.h"
7 #include "gdcmDirList.h"
13 #include <sys/types.h>
17 //-----------------------------------------------------------------------------
18 // For full DICOMDIR description, see:
19 // PS 3.3-2003, pages 731-750
20 //-----------------------------------------------------------------------------
21 // Constructor / Destructor
23 * \ingroup gdcmDicomDir
24 * \brief Constructor : Parses recursively the directory and creates the DicomDir
25 * \ or uses an already built DICOMDIR, depending on 'parseDir' value
26 * @param Name name of the root directory (parseDir = true)
27 * name of the DICOMDIR (parseDir = false)
28 * @param parseDir - true if user passed an entry point
29 * and wants to explore recursively the directories
30 * - false if user passed an already built DICOMDIR file
32 * @param exception_on_error whether we want to throw an exception or not
34 gdcmDicomDir::gdcmDicomDir(const char *Name, bool parseDir,
35 bool exception_on_error):
36 gdcmParser(Name,exception_on_error,true) // true : enable SeQuences
38 // que l'on ai passe un root directory ou un DICOMDIR
39 // et quelle que soit la valeur de parseDir,
40 // on a lance gdcmParser
45 startMethodArgDelete= NULL;
46 progressMethodArgDelete=NULL;
47 endMethodArgDelete= NULL;
57 // gdcmParser already executed
58 // if user passed a root directory, sure we didn't get anything
60 if( GetListEntry().begin()==GetListEntry().end() )
62 // if parseDir == false, it should be tagged as an error
63 dbg.Verbose(0, "gdcmDicomDir::gdcmDicomDir : entry list empty");
65 if(strlen(Name)==1 && Name[0]=='.') { // user passed '.' as Name
66 // we get current directory name
67 char*dummy=(char*) malloc(1000); // TODO : check with Windoze // JPR
68 getcwd(dummy,(size_t)1000);
69 SetFileName(dummy); // will be converted into a string
70 free(dummy); // no longer needed
75 dbg.Verbose(0, "gdcmDicomDir::gdcmDicomDir : Parse directory and create the DicomDir");
81 CheckBoundaries(); // to maintain consistency between
82 // home-made gdcmDicomDir
83 // and the ones comming from a DICOMDIR file
88 * \ingroup gdcmDicomDir
89 * \brief Constructor : creates an empty gdcmDicomDir
90 * @param exception_on_error whether we want to throw an exception or not
92 gdcmDicomDir::gdcmDicomDir(bool exception_on_error):
93 gdcmParser(exception_on_error)
98 startMethodArgDelete= NULL;
99 progressMethodArgDelete=NULL;
100 endMethodArgDelete= NULL;
107 std::string pathBidon = ""; // Sorry, NULL not allowed ...
108 SetElement(pathBidon, GDCM_DICOMDIR_META, NULL); // Set the META elements
110 AddDicomDirMetaToEnd(listEntries.begin(),--listEntries.end());
115 * \ingroup gdcmDicomDir
116 * \brief Canonical destructor
118 gdcmDicomDir::~gdcmDicomDir()
120 SetStartMethod(NULL);
121 SetProgressMethod(NULL);
127 for(ListDicomDirPatient::iterator cc=patients.begin();cc!=patients.end();++cc)
133 //-----------------------------------------------------------------------------
136 * \ingroup gdcmDicomDir
137 * \brief Canonical Printer
139 void gdcmDicomDir::Print(std::ostream &os)
143 metaElems->SetPrintLevel(printLevel);
144 metaElems->Print(os);
146 for(ListDicomDirPatient::iterator cc=patients.begin();cc!=patients.end();++cc)
148 (*cc)->SetPrintLevel(printLevel);
153 //-----------------------------------------------------------------------------
156 * \ingroup gdcmDicomDir
157 * \brief This predicate, based on hopefully reasonable heuristics,
158 * decides whether or not the current header was properly parsed
159 * and contains the mandatory information for being considered as
160 * a well formed and usable DicomDir.
161 * @return true when gdcmParser is the one of a reasonable DicomDir,
164 bool gdcmDicomDir::IsReadable(void)
166 if(!gdcmParser::IsReadable())
170 if(patients.size()<=0)
177 * \ingroup gdcmDicomDir
178 * \brief fills the whole structure, starting from a root Directory
180 void gdcmDicomDir::ParseDirectory(void)
182 CreateDicomDirChainedList(GetFileName());
187 * \ingroup gdcmDicomDir
188 * \brief Set the start method to call when the parsing of the directory starts
189 * @param method Method to call
190 * @param arg Argument to pass to the method
191 * \warning In python : the arg parameter isn't considered
193 void gdcmDicomDir::SetStartMethod(gdcmMethod *method,void *arg,gdcmMethod *argDelete)
195 if((startArg)&&(startMethodArgDelete))
196 startMethodArgDelete(startArg);
200 startMethodArgDelete=argDelete;
204 * \ingroup gdcmDicomDir
205 * \brief Set the method to delete the argument
206 * The argument is destroyed when the method is changed or when the
208 * @param method Method to call to delete the argument
210 void gdcmDicomDir::SetStartMethodArgDelete(gdcmMethod *method)
212 startMethodArgDelete=method;
216 * \ingroup gdcmDicomDir
217 * \brief Set the progress method to call when the parsing of the directory progress
218 * @param method Method to call
219 * @param arg Argument to pass to the method
220 * \warning In python : the arg parameter isn't considered
222 void gdcmDicomDir::SetProgressMethod(gdcmMethod *method,void *arg,gdcmMethod *argDelete)
224 if((progressArg)&&(progressMethodArgDelete))
225 progressMethodArgDelete(progressArg);
227 progressMethod=method;
229 progressMethodArgDelete=argDelete;
233 * \ingroup gdcmDicomDir
234 * \brief Set the method to delete the argument
235 * The argument is destroyed when the method is changed or when the
237 * @param method Method to call to delete the argument
239 void gdcmDicomDir::SetProgressMethodArgDelete(gdcmMethod *method)
241 progressMethodArgDelete=method;
245 * \ingroup gdcmDicomDir
246 * \brief Set the end method to call when the parsing of the directory ends
247 * @param method Method to call
248 * @param arg Argument to pass to the method
249 * \warning In python : the arg parameter isn't considered
251 void gdcmDicomDir::SetEndMethod(gdcmMethod *method,void *arg,gdcmMethod *argDelete)
253 if((endArg)&&(endMethodArgDelete))
254 endMethodArgDelete(endArg);
258 endMethodArgDelete=argDelete;
262 * \ingroup gdcmDicomDir
263 * \brief Set the method to delete the argument
264 * The argument is destroyed when the method is changed or when the class
266 * @param method Method to call to delete the argument
268 void gdcmDicomDir::SetEndMethodArgDelete(gdcmMethod *method)
270 endMethodArgDelete=method;
274 * \ingroup gdcmDicomDir
275 * \brief writes on disc a DICOMDIR
276 * \ warning does NOT add the missing elements in the header :
277 * it's up to the user doing it !
278 * \todo : to be re-written using the DICOMDIR tree-like structure
279 * *not* the chained list
280 * (does NOT exist if the DICOMDIR is user-forged !)
281 * @param fileName file to be written to
282 * @return false only when fail to open
285 bool gdcmDicomDir::Write(std::string fileName)
289 fp1=fopen(fileName.c_str(),"wb");
292 printf("Failed to open(write) File [%s] \n",fileName.c_str());
297 filePreamble=(char*)calloc(128,1);
298 fwrite(filePreamble,128,1,fp1);
299 fwrite("DICM",4,1,fp1);
301 //UpdateDirectoryRecordSequenceLength(); // a reecrire en utilisant JPR
302 // la structure arborescente JPR
303 WriteDicomDirEntries(fp1);
310 * \ingroup gdcmParser
311 * \brief writes on disc according to the DICOMDIR format
312 * using the tree-like structure
313 * @param _fp already open file pointer
316 void gdcmDicomDir::WriteDicomDirEntries(FILE *_fp)
318 // TODO (?) tester les echecs en ecriture
319 // (apres chaque fwrite, dans le WriteEntry)
321 gdcmDicomDirMeta *ptrMeta;
322 ListDicomDirPatient::iterator itPatient;
323 ListDicomDirStudy::iterator itStudy;
324 ListDicomDirSerie::iterator itSerie;
325 ListDicomDirImage::iterator itImage;
328 ptrMeta= GetDicomDirMeta();
329 for(i=ptrMeta->debut();i!=ptrMeta->fin();++i) {
330 WriteEntry(*i,_fp,DICOMDIR);
333 itPatient = GetDicomDirPatients().begin();
334 while ( itPatient != GetDicomDirPatients().end() ) {
335 for(i=(*itPatient)->debut();i!=(*itPatient)->fin();++i) {
336 WriteEntry(*i,_fp,DICOMDIR);
338 itStudy = ((*itPatient)->GetDicomDirStudies()).begin();
339 while (itStudy != (*itPatient)->GetDicomDirStudies().end() ) {
340 for(i=(*itStudy)->debut();i!=(*itStudy)->fin();++i) {
341 WriteEntry(*i,_fp,DICOMDIR);
343 itSerie = ((*itStudy)->GetDicomDirSeries()).begin();
344 while (itSerie != (*itStudy)->GetDicomDirSeries().end() ) {
345 for(i=(*itSerie)->debut();i!=(*itSerie)->fin();++i) {
346 WriteEntry(*i,_fp,DICOMDIR);
348 itImage = ((*itSerie)->GetDicomDirImages()).begin();
349 while (itImage != (*itSerie)->GetDicomDirImages().end() ) {
350 for(i=(*itImage)->debut();i!=(*itImage)->fin();++i) {
351 WriteEntry(*i,_fp,DICOMDIR);
363 //-----------------------------------------------------------------------------
367 * \ingroup gdcmDicomDir
368 * \brief create a gdcmHeader-like chained list from a root Directory
369 * @param path entry point of the tree-like structure
371 void gdcmDicomDir::CreateDicomDirChainedList(std::string path)
375 gdcmDirList fileList(path,1); // gets recursively the file list
376 unsigned int count=0;
383 for(gdcmDirList::iterator it=fileList.begin();
387 progress=(float)(count+1)/(float)fileList.size();
388 CallProgressMethod();
392 header=new gdcmHeader(it->c_str());
393 if(header->IsReadable())
394 list.push_back(header); // adds the file header to the chained list
400 // sorts Patient/Study/Serie/
401 std::sort(list.begin(),list.end(),gdcmDicomDir::HeaderLessThan);
403 std::string tmp=fileList.GetDirName();
405 //for each Header of the chained list, add/update the Patient/Study/Serie/Image info
406 SetElements(tmp,list);
413 void gdcmDicomDir::CheckBoundaries()
416 cout <<"entree ds CheckBoundaries " <<endl;
417 ListDicomDirPatient::iterator itPatient;
418 ListDicomDirStudy::iterator itStudy;
419 ListDicomDirSerie::iterator itSerie;
420 ListDicomDirImage::iterator itImage;
421 ListTag::iterator i,j;
423 GetDicomDirMeta()->ResetBoundaries(0);
425 itPatient = GetDicomDirPatients().begin();
426 while ( itPatient != GetDicomDirPatients().end() ) {
427 (*itPatient)->ResetBoundaries(1);
428 itStudy = ((*itPatient)->GetDicomDirStudies()).begin();
429 while (itStudy != (*itPatient)->GetDicomDirStudies().end() ) {
430 (*itStudy)->ResetBoundaries(1);
431 itSerie = ((*itStudy)->GetDicomDirSeries()).begin();
432 while (itSerie != (*itStudy)->GetDicomDirSeries().end() ) {
433 (*itSerie)->ResetBoundaries(1);
434 itImage = ((*itSerie)->GetDicomDirImages()).begin();
435 while (itImage != (*itSerie)->GetDicomDirImages().end() ) {
436 (*itImage)->ResetBoundaries(1);
449 * \ingroup gdcmDicomDir
450 * \brief adds a new Patient to a partially created DICOMDIR
452 gdcmDicomDirPatient * gdcmDicomDir::NewPatient(void) {
453 std::list<gdcmElement> elemList;
454 std::list<gdcmElement>::iterator it;
456 gdcmDictEntry *dictEntry;
457 gdcmHeaderEntry *entry;
459 elemList=gdcmGlobal::GetDicomDirElements()->GetDicomDirPatientElements();
460 std::list<gdcmHeaderEntry *>::iterator debInsertion, finInsertion, i,j;
462 debInsertion = metaElems->fin();
464 finInsertion=debInsertion;
466 // for all the DicomDirPatient Elements
467 for(it=elemList.begin();it!=elemList.end();++it)
471 dictEntry=GetPubDict()->GetDictEntryByNumber(tmpGr,tmpEl);
472 entry=new gdcmHeaderEntry(dictEntry);
473 entry->SetOffset(0); // just to avoid missprinting
474 entry->SetValue(it->value);
476 if(dictEntry->GetGroup()==0xfffe)
478 entry->SetLength(entry->GetValue().length());
480 else if( (dictEntry->GetVR()=="UL") || (dictEntry->GetVR()=="SL") )
484 else if( (dictEntry->GetVR()=="US") || (dictEntry->GetVR()=="SS") )
488 else if(dictEntry->GetVR()=="SQ")
490 entry->SetLength(0xffffffff);
494 entry->SetLength(entry->GetValue().length());
497 tagHT.insert( PairHT(entry->GetKey(),entry) ); // add in the (multimap) H Table
498 listEntries.insert(debInsertion ,entry); // en tete de liste des Patients
505 gdcmDicomDirPatient *p = new gdcmDicomDirPatient(i, --debInsertion,
506 &tagHT, &listEntries);
507 patients.push_front(p);
512 * \ingroup gdcmDicomDir
513 * \brief CallStartMethod
515 void gdcmDicomDir::CallStartMethod(void)
520 startMethod(startArg);
523 * \ingroup gdcmDicomDir
524 * \brief CallProgressMethod
526 void gdcmDicomDir::CallProgressMethod(void)
529 progressMethod(progressArg);
532 * \ingroup gdcmDicomDir
533 * \brief CallEndMethod
535 void gdcmDicomDir::CallEndMethod(void)
542 //-----------------------------------------------------------------------------
545 * \ingroup gdcmDicomDir
546 * \brief create a 'gdcmDicomDir' from a DICOMDIR gdcmHeader
548 void gdcmDicomDir::CreateDicomDir()
550 // The list is parsed.
551 // When a DicomDir tag ("PATIENT", "STUDY", "SERIE", "IMAGE") is found :
552 // 1 - we save the beginning iterator
553 // 2 - we continue to parse
554 // 3 - we find an other tag
555 // + we create the object for the precedent tag
558 gdcmDicomDirType type=gdcmDicomDir::GDCM_DICOMDIR_META;
559 ListTag::iterator begin;
560 ListTag::iterator end, end2;
562 begin=listEntries.begin();
564 for(ListTag::iterator i=end;i !=listEntries.end();++i)
566 std::string v=(*i)->GetValue();
570 AddObjectToEnd(type,begin,--end2);
571 type=gdcmDicomDir::GDCM_DICOMDIR_PATIENT;
578 AddObjectToEnd(type,begin,--end2);
579 type=gdcmDicomDir::GDCM_DICOMDIR_STUDY;
586 AddObjectToEnd(type,begin,--end2);
587 type=gdcmDicomDir::GDCM_DICOMDIR_SERIE;
594 AddObjectToEnd(type,begin,--end2);
595 type=gdcmDicomDir::GDCM_DICOMDIR_IMAGE;
600 end=end2=listEntries.end();
602 AddObjectToEnd(type,begin,--end2);
605 * \ingroup gdcmDicomDir
606 * \brief AddObjectToEnd
611 void gdcmDicomDir::AddObjectToEnd(gdcmDicomDirType type,ListTag::iterator begin,ListTag::iterator end)
618 case gdcmDicomDir::GDCM_DICOMDIR_META:
619 AddDicomDirMetaToEnd(begin,end);
621 case gdcmDicomDir::GDCM_DICOMDIR_PATIENT:
622 AddDicomDirPatientToEnd(begin,end);
624 case gdcmDicomDir::GDCM_DICOMDIR_STUDY:
625 AddDicomDirStudyToEnd(begin,end);
627 case gdcmDicomDir::GDCM_DICOMDIR_SERIE:
628 AddDicomDirSerieToEnd(begin,end);
630 case gdcmDicomDir::GDCM_DICOMDIR_IMAGE:
631 AddDicomDirImageToEnd(begin,end);
637 * \ingroup gdcmDicomDir
638 * \brief Well ... Not realy to end, there is only one occurence
642 void gdcmDicomDir::AddDicomDirMetaToEnd(ListTag::iterator begin,ListTag::iterator end)
646 metaElems = new gdcmDicomDirMeta(begin,end,&tagHT,&listEntries);
650 * \ingroup gdcmDicomDir
651 * \brief AddDicomDirPatientToEnd
655 void gdcmDicomDir::AddDicomDirPatientToEnd(ListTag::iterator begin,ListTag::iterator end)
657 patients.push_back(new gdcmDicomDirPatient(begin,end,&tagHT, &listEntries));
661 * \ingroup gdcmDicomDir
662 * \brief AddDicomDirStudyToEnd
666 void gdcmDicomDir::AddDicomDirStudyToEnd(ListTag::iterator begin,ListTag::iterator end)
668 if(patients.size()>0)
670 ListDicomDirPatient::iterator itp=patients.end();
672 (*itp)->AddDicomDirStudy(new gdcmDicomDirStudy(begin,end,&tagHT, &listEntries));
676 * \ingroup gdcmDicomDir
677 * \brief AddDicomDirSerieToEnd
681 void gdcmDicomDir::AddDicomDirSerieToEnd(ListTag::iterator begin,ListTag::iterator end)
683 if(patients.size()>0)
685 ListDicomDirPatient::iterator itp=patients.end();
688 if((*itp)->GetDicomDirStudies().size()>0)
690 ListDicomDirStudy::iterator itst=(*itp)->GetDicomDirStudies().end();
692 (*itst)->AddDicomDirSerie(new gdcmDicomDirSerie(begin,end,&tagHT, &listEntries));
698 * \ingroup gdcmDicomDir
699 * \brief AddDicomDirImageToEnd
703 void gdcmDicomDir::AddDicomDirImageToEnd(ListTag::iterator begin,ListTag::iterator end)
705 if(patients.size()>0)
707 ListDicomDirPatient::iterator itp=patients.end();
710 if((*itp)->GetDicomDirStudies().size()>0)
712 ListDicomDirStudy::iterator itst=(*itp)->GetDicomDirStudies().end();
715 if((*itst)->GetDicomDirSeries().size()>0)
717 ListDicomDirSerie::iterator its=(*itst)->GetDicomDirSeries().end();
719 (*its)->AddDicomDirImage(new gdcmDicomDirImage(begin,end,&tagHT, &listEntries));
726 * \ingroup gdcmDicomDir
727 * \brief for each Header of the chained list, add/update the Patient/Study/Serie/Image info
728 * @param path path of the root directory
729 * @param list chained list of Headers
731 void gdcmDicomDir::SetElements(std::string &path, ListHeader &list)
733 std::string patPrevName="", patPrevID="";
734 std::string studPrevInstanceUID="", studPrevID="";
735 std::string serPrevInstanceUID="", serPrevID="";
737 std::string patCurName, patCurID;
738 std::string studCurInstanceUID, studCurID;
739 std::string serCurInstanceUID, serCurID;
741 SetElement(path,GDCM_DICOMDIR_META,NULL);
743 ListTag::iterator debPat=listEntries.begin();
744 for(ListHeader::iterator it=list.begin();it!=list.end();++it)
746 // get the current file characteristics
747 patCurName= (*it)->GetEntryByNumber(0x0010,0x0010);
748 patCurID= (*it)->GetEntryByNumber(0x0010,0x0011);
749 studCurInstanceUID=(*it)->GetEntryByNumber(0x0020,0x000d);
750 studCurID= (*it)->GetEntryByNumber(0x0020,0x0010);
751 serCurInstanceUID= (*it)->GetEntryByNumber(0x0020,0x000e);
752 serCurID= (*it)->GetEntryByNumber(0x0020,0x0011);
754 if(patCurName!=patPrevName || patCurID!=patPrevID)
755 SetElement(path,GDCM_DICOMDIR_PATIENT,*it);
757 // if new Study Deal with 'STUDY' Elements
758 if(studCurInstanceUID!=studPrevInstanceUID || studCurID!=studPrevID)
759 SetElement(path,GDCM_DICOMDIR_STUDY,*it);
761 // if new Serie Deal with 'SERIE' Elements
762 if(serCurInstanceUID!=serPrevInstanceUID || serCurID!=serPrevID)
763 SetElement(path,GDCM_DICOMDIR_SERIE,*it);
765 // Always Deal with 'IMAGE' Elements
766 SetElement(path,GDCM_DICOMDIR_IMAGE,*it);
768 patPrevName= patCurName;
770 studPrevInstanceUID=studCurInstanceUID;
771 studPrevID= studCurID;
772 serPrevInstanceUID= serCurInstanceUID;
778 * \ingroup gdcmDicomDir
779 * \brief adds to the HTable and at the end of the Chained List
780 * the gdcmEntries (Dicom Elements) corresponding to the given type
781 * @param path full path file name(only used when type = GDCM_DICOMDIR_IMAGE
782 * @param type gdcmObject type to create (GDCM_DICOMDIR_PATIENT, GDCM_DICOMDIR_STUDY, GDCM_DICOMDIR_SERIE ...)
783 * @param header gdcmHeader of the current file
785 void gdcmDicomDir::SetElement(std::string &path,gdcmDicomDirType type,gdcmHeader *header)
787 std::list<gdcmElement> elemList;
788 std::list<gdcmElement>::iterator it;
789 guint16 tmpGr, tmpEl;
790 gdcmDictEntry *dictEntry;
791 gdcmHeaderEntry *entry;
796 case GDCM_DICOMDIR_PATIENT:
797 elemList=gdcmGlobal::GetDicomDirElements()->GetDicomDirPatientElements();
799 case GDCM_DICOMDIR_STUDY:
800 elemList=gdcmGlobal::GetDicomDirElements()->GetDicomDirStudyElements();
802 case GDCM_DICOMDIR_SERIE:
803 elemList=gdcmGlobal::GetDicomDirElements()->GetDicomDirSerieElements();
805 case GDCM_DICOMDIR_IMAGE:
806 elemList=gdcmGlobal::GetDicomDirElements()->GetDicomDirImageElements();
808 case GDCM_DICOMDIR_META:
809 elemList=gdcmGlobal::GetDicomDirElements()->GetDicomDirMetaElements();
815 for(it=elemList.begin();it!=elemList.end();++it)
819 dictEntry=GetPubDict()->GetDictEntryByNumber(tmpGr,tmpEl);
820 entry=new gdcmHeaderEntry(dictEntry);
821 entry->SetOffset(0); // just to avoid missprinting
824 val=header->GetEntryByNumber(tmpGr,tmpEl);
828 if(val==GDCM_UNFOUND)
830 if((tmpGr==0x0004) &&(tmpEl==0x1130) ) // File-set ID
832 // force to the *end* File Name
835 else if( (tmpGr==0x0004) && (tmpEl==0x1500) ) // Only used for image
837 if(header->GetFileName().substr(0,path.length())!=path)
839 dbg.Verbose(0, "gdcmDicomDir::SetElement : the base path of file name is incorrect");
840 val=header->GetFileName();
843 val=&(header->GetFileName().c_str()[path.length()]);
853 if (header->GetEntryLengthByNumber(tmpGr,tmpEl)== 0)
857 entry->SetValue(val);
861 if(dictEntry->GetGroup()==0xfffe)
863 entry->SetLength(entry->GetValue().length());
865 else if( (dictEntry->GetVR()=="UL") || (dictEntry->GetVR()=="SL") )
869 else if( (dictEntry->GetVR()=="US") || (dictEntry->GetVR()=="SS") )
873 else if(dictEntry->GetVR()=="SQ")
875 entry->SetLength(0xffffffff);
879 entry->SetLength(entry->GetValue().length());
882 //AddHeaderEntry(entry); // both in H Table and in chained list
883 tagHT.insert( PairHT( entry->GetKey(),entry) );
884 listEntries.push_back(entry);
885 //wasUpdated = 1; // is private
889 bool gdcmDicomDir::HeaderLessThan(gdcmHeader *header1,gdcmHeader *header2)
891 return(*header1<*header2);
896 void gdcmDicomDir::UpdateDirectoryRecordSequenceLength() {
898 ListTag::iterator it;
901 for(it=listEntries.begin();it!=listEntries.end();++it) {
902 gr = (*it)->GetGroup();
903 el = (*it)->GetElement();
906 if ( (vr == "OB") || (vr == "OW") || (vr == "SQ") ) {
907 offset += 4; // explicit VR AND OB, OW, SQ : 4 more bytes
909 offset += 2 + 2 + 4 + (*it)->GetLength();
911 offset += 4; // delimiters don't have a value.
914 bool res=SetEntryLengthByNumber(offset, 0x0004, 0x1220); // Hope there is no dupps.
918 //-----------------------------------------------------------------------------