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>
22 //-----------------------------------------------------------------------------
23 // For full DICOMDIR description, see:
24 // PS 3.3-2003, pages 731-750
25 //-----------------------------------------------------------------------------
27 // Constructor / Destructor
30 * \ingroup gdcmDicomDir
31 * \brief Constructor : Parses recursively the directory and creates the DicomDir
32 * \ or uses an already built DICOMDIR, depending on 'parseDir' value
33 * @param Name name of the root directory (parseDir = true)
34 * name of the DICOMDIR (parseDir = false)
35 * @param parseDir - true if user passed an entry point
36 * and wants to explore recursively the directories
37 * - false if user passed an already built DICOMDIR file
39 * @param exception_on_error whether we want to throw an exception or not
41 gdcmDicomDir::gdcmDicomDir(const char *Name, bool parseDir,
42 bool exception_on_error):
43 gdcmParser(Name,exception_on_error,true) // true : enable SeQuences
45 // que l'on ai passe un root directory ou un DICOMDIR
46 // et quelle que soit la valeur de parseDir,
47 // on a lance gdcmParser
52 startMethodArgDelete= NULL;
53 progressMethodArgDelete=NULL;
54 endMethodArgDelete= NULL;
64 // gdcmParser already executed
65 // if user passed a root directory, sure we didn't get anything
67 if( GetListEntry().begin()==GetListEntry().end() )
69 // if parseDir == false, it should be tagged as an error
70 dbg.Verbose(0, "gdcmDicomDir::gdcmDicomDir : entry list empty");
72 if(strlen(Name)==1 && Name[0]=='.') { // user passed '.' as Name
73 // we get current directory name
74 char*dummy=(char*) malloc(1000);
76 _getcwd(dummy,(size_t)1000);
78 getcwd(dummy,(size_t)1000);
80 SetFileName(dummy); // will be converted into a string
81 free(dummy); // no longer needed
86 dbg.Verbose(0, "gdcmDicomDir::gdcmDicomDir : Parse directory and create the DicomDir");
92 CheckBoundaries(); // to maintain consistency between
93 // home-made gdcmDicomDir
94 // and the ones comming from a DICOMDIR file
99 * \ingroup gdcmDicomDir
100 * \brief Constructor : creates an empty gdcmDicomDir
101 * @param exception_on_error whether we want to throw an exception or not
103 gdcmDicomDir::gdcmDicomDir(bool exception_on_error):
104 gdcmParser(exception_on_error)
107 progressMethod= NULL;
109 startMethodArgDelete= NULL;
110 progressMethodArgDelete=NULL;
111 endMethodArgDelete= NULL;
118 std::string pathBidon = ""; // Sorry, NULL not allowed ...
119 SetElement(pathBidon, GDCM_DICOMDIR_META, NULL); // Set the META elements
121 AddDicomDirMetaToEnd(listEntries.begin(),--listEntries.end());
126 * \ingroup gdcmDicomDir
127 * \brief Canonical destructor
129 gdcmDicomDir::~gdcmDicomDir()
131 SetStartMethod(NULL);
132 SetProgressMethod(NULL);
138 for(ListDicomDirPatient::iterator cc=patients.begin();cc!=patients.end();++cc)
144 //-----------------------------------------------------------------------------
147 * \ingroup gdcmDicomDir
148 * \brief Canonical Printer
150 void gdcmDicomDir::Print(std::ostream &os)
154 metaElems->SetPrintLevel(printLevel);
155 metaElems->Print(os);
157 for(ListDicomDirPatient::iterator cc=patients.begin();cc!=patients.end();++cc)
159 (*cc)->SetPrintLevel(printLevel);
164 //-----------------------------------------------------------------------------
167 * \ingroup gdcmDicomDir
168 * \brief This predicate, based on hopefully reasonable heuristics,
169 * decides whether or not the current header was properly parsed
170 * and contains the mandatory information for being considered as
171 * a well formed and usable DicomDir.
172 * @return true when gdcmParser is the one of a reasonable DicomDir,
175 bool gdcmDicomDir::IsReadable(void)
177 if(!gdcmParser::IsReadable())
181 if(patients.size()<=0)
188 * \ingroup gdcmDicomDir
189 * \brief fills the whole structure, starting from a root Directory
191 void gdcmDicomDir::ParseDirectory(void)
193 CreateDicomDirChainedList(GetFileName());
198 * \ingroup gdcmDicomDir
199 * \brief Set the start method to call when the parsing of the directory starts
200 * @param method Method to call
201 * @param arg Argument to pass to the method
202 * \warning In python : the arg parameter isn't considered
204 void gdcmDicomDir::SetStartMethod(gdcmMethod *method,void *arg,gdcmMethod *argDelete)
206 if((startArg)&&(startMethodArgDelete))
207 startMethodArgDelete(startArg);
211 startMethodArgDelete=argDelete;
215 * \ingroup gdcmDicomDir
216 * \brief Set the method to delete the argument
217 * The argument is destroyed when the method is changed or when the
219 * @param method Method to call to delete the argument
221 void gdcmDicomDir::SetStartMethodArgDelete(gdcmMethod *method)
223 startMethodArgDelete=method;
227 * \ingroup gdcmDicomDir
228 * \brief Set the progress method to call when the parsing of the directory progress
229 * @param method Method to call
230 * @param arg Argument to pass to the method
231 * \warning In python : the arg parameter isn't considered
233 void gdcmDicomDir::SetProgressMethod(gdcmMethod *method,void *arg,gdcmMethod *argDelete)
235 if((progressArg)&&(progressMethodArgDelete))
236 progressMethodArgDelete(progressArg);
238 progressMethod=method;
240 progressMethodArgDelete=argDelete;
244 * \ingroup gdcmDicomDir
245 * \brief Set the method to delete the argument
246 * The argument is destroyed when the method is changed or when the
248 * @param method Method to call to delete the argument
250 void gdcmDicomDir::SetProgressMethodArgDelete(gdcmMethod *method)
252 progressMethodArgDelete=method;
256 * \ingroup gdcmDicomDir
257 * \brief Set the end method to call when the parsing of the directory ends
258 * @param method Method to call
259 * @param arg Argument to pass to the method
260 * \warning In python : the arg parameter isn't considered
262 void gdcmDicomDir::SetEndMethod(gdcmMethod *method,void *arg,gdcmMethod *argDelete)
264 if((endArg)&&(endMethodArgDelete))
265 endMethodArgDelete(endArg);
269 endMethodArgDelete=argDelete;
273 * \ingroup gdcmDicomDir
274 * \brief Set the method to delete the argument
275 * The argument is destroyed when the method is changed or when the class
277 * @param method Method to call to delete the argument
279 void gdcmDicomDir::SetEndMethodArgDelete(gdcmMethod *method)
281 endMethodArgDelete=method;
285 * \ingroup gdcmDicomDir
286 * \brief writes on disc a DICOMDIR
287 * \ warning does NOT add the missing elements in the header :
288 * it's up to the user doing it !
289 * \todo : to be re-written using the DICOMDIR tree-like structure
290 * *not* the chained list
291 * (does NOT exist if the DICOMDIR is user-forged !)
292 * @param fileName file to be written to
293 * @return false only when fail to open
296 bool gdcmDicomDir::Write(std::string fileName)
300 fp1=fopen(fileName.c_str(),"wb");
303 printf("Failed to open(write) File [%s] \n",fileName.c_str());
308 filePreamble=(char*)calloc(128,1);
309 fwrite(filePreamble,128,1,fp1);
310 fwrite("DICM",4,1,fp1);
312 UpdateDirectoryRecordSequenceLength();
313 WriteDicomDirEntries(fp1);
320 * \ingroup gdcmParser
321 * \brief writes on disc according to the DICOMDIR format
322 * using the tree-like structure
323 * @param _fp already open file pointer
326 void gdcmDicomDir::WriteDicomDirEntries(FILE *_fp)
328 // TODO (?) tester les echecs en ecriture
329 // (apres chaque fwrite, dans le WriteEntry)
331 gdcmDicomDirMeta *ptrMeta;
332 ListDicomDirPatient::iterator itPatient;
333 ListDicomDirStudy::iterator itStudy;
334 ListDicomDirSerie::iterator itSerie;
335 ListDicomDirImage::iterator itImage;
338 ptrMeta= GetDicomDirMeta();
339 for(i=ptrMeta->debut();i!=ptrMeta->fin();++i) {
340 WriteEntry(*i,_fp,DICOMDIR);
343 itPatient = GetDicomDirPatients().begin();
344 while ( itPatient != GetDicomDirPatients().end() ) {
345 for(i=(*itPatient)->debut();i!=(*itPatient)->fin();++i) {
346 WriteEntry(*i,_fp,DICOMDIR);
348 itStudy = ((*itPatient)->GetDicomDirStudies()).begin();
349 while (itStudy != (*itPatient)->GetDicomDirStudies().end() ) {
350 for(i=(*itStudy)->debut();i!=(*itStudy)->fin();++i) {
351 WriteEntry(*i,_fp,DICOMDIR);
353 itSerie = ((*itStudy)->GetDicomDirSeries()).begin();
354 while (itSerie != (*itStudy)->GetDicomDirSeries().end() ) {
355 for(i=(*itSerie)->debut();i!=(*itSerie)->fin();++i) {
356 WriteEntry(*i,_fp,DICOMDIR);
358 itImage = ((*itSerie)->GetDicomDirImages()).begin();
359 while (itImage != (*itSerie)->GetDicomDirImages().end() ) {
360 for(i=(*itImage)->debut();i!=(*itImage)->fin();++i) {
361 WriteEntry(*i,_fp,DICOMDIR);
373 //-----------------------------------------------------------------------------
377 * \ingroup gdcmDicomDir
378 * \brief create a gdcmHeader-like chained list from a root Directory
379 * @param path entry point of the tree-like structure
381 void gdcmDicomDir::CreateDicomDirChainedList(std::string path)
385 gdcmDirList fileList(path,1); // gets recursively the file list
386 unsigned int count=0;
393 for(gdcmDirList::iterator it=fileList.begin();
397 progress=(float)(count+1)/(float)fileList.size();
398 CallProgressMethod();
402 header=new gdcmHeader(it->c_str());
403 if(header->IsReadable())
404 list.push_back(header); // adds the file header to the chained list
410 // sorts Patient/Study/Serie/
411 std::sort(list.begin(),list.end(),gdcmDicomDir::HeaderLessThan);
413 std::string tmp=fileList.GetDirName();
415 //for each Header of the chained list, add/update the Patient/Study/Serie/Image info
416 SetElements(tmp,list);
423 void gdcmDicomDir::CheckBoundaries()
425 ListDicomDirPatient::iterator itPatient;
426 ListDicomDirStudy::iterator itStudy;
427 ListDicomDirSerie::iterator itSerie;
428 ListDicomDirImage::iterator itImage;
429 ListTag::iterator i,j;
431 GetDicomDirMeta()->ResetBoundaries(0);
433 itPatient = GetDicomDirPatients().begin();
434 while ( itPatient != GetDicomDirPatients().end() ) {
435 (*itPatient)->ResetBoundaries(1);
436 itStudy = ((*itPatient)->GetDicomDirStudies()).begin();
437 while (itStudy != (*itPatient)->GetDicomDirStudies().end() ) {
438 (*itStudy)->ResetBoundaries(1);
439 itSerie = ((*itStudy)->GetDicomDirSeries()).begin();
440 while (itSerie != (*itStudy)->GetDicomDirSeries().end() ) {
441 (*itSerie)->ResetBoundaries(1);
442 itImage = ((*itSerie)->GetDicomDirImages()).begin();
443 while (itImage != (*itSerie)->GetDicomDirImages().end() ) {
444 (*itImage)->ResetBoundaries(1);
457 * \ingroup gdcmDicomDir
458 * \brief adds a new Patient to a partially created DICOMDIR
460 gdcmDicomDirPatient * gdcmDicomDir::NewPatient(void) {
461 std::list<gdcmElement> elemList;
462 std::list<gdcmElement>::iterator it;
464 gdcmDictEntry *dictEntry;
465 gdcmHeaderEntry *entry;
467 elemList=gdcmGlobal::GetDicomDirElements()->GetDicomDirPatientElements();
468 std::list<gdcmHeaderEntry *>::iterator debInsertion, finInsertion, i,j;
470 debInsertion = metaElems->fin();
472 finInsertion=debInsertion;
474 // for all the DicomDirPatient Elements
475 for(it=elemList.begin();it!=elemList.end();++it)
479 dictEntry=GetPubDict()->GetDictEntryByNumber(tmpGr,tmpEl);
480 entry=new gdcmHeaderEntry(dictEntry);
481 entry->SetOffset(0); // just to avoid missprinting
482 entry->SetValue(it->value);
484 if(dictEntry->GetGroup()==0xfffe)
486 entry->SetLength(entry->GetValue().length());
488 else if( (dictEntry->GetVR()=="UL") || (dictEntry->GetVR()=="SL") )
492 else if( (dictEntry->GetVR()=="US") || (dictEntry->GetVR()=="SS") )
496 else if(dictEntry->GetVR()=="SQ")
498 entry->SetLength(0xffffffff);
502 entry->SetLength(entry->GetValue().length());
505 tagHT.insert( PairHT(entry->GetKey(),entry) ); // add in the (multimap) H Table
506 listEntries.insert(debInsertion ,entry); // en tete de liste des Patients
513 gdcmDicomDirPatient *p = new gdcmDicomDirPatient(i, --debInsertion,
514 &tagHT, &listEntries);
515 patients.push_front(p);
520 * \ingroup gdcmDicomDir
521 * \brief CallStartMethod
523 void gdcmDicomDir::CallStartMethod(void)
528 startMethod(startArg);
531 * \ingroup gdcmDicomDir
532 * \brief CallProgressMethod
534 void gdcmDicomDir::CallProgressMethod(void)
537 progressMethod(progressArg);
540 * \ingroup gdcmDicomDir
541 * \brief CallEndMethod
543 void gdcmDicomDir::CallEndMethod(void)
550 //-----------------------------------------------------------------------------
553 * \ingroup gdcmDicomDir
554 * \brief create a 'gdcmDicomDir' from a DICOMDIR gdcmHeader
556 void gdcmDicomDir::CreateDicomDir()
558 // The list is parsed.
559 // When a DicomDir tag ("PATIENT", "STUDY", "SERIE", "IMAGE") is found :
560 // 1 - we save the beginning iterator
561 // 2 - we continue to parse
562 // 3 - we find an other tag
563 // + we create the object for the precedent tag
566 gdcmDicomDirType type=gdcmDicomDir::GDCM_DICOMDIR_META;
567 ListTag::iterator begin;
568 ListTag::iterator end, end2;
570 begin=listEntries.begin();
572 for(ListTag::iterator i=end;i !=listEntries.end();++i)
574 std::string v=(*i)->GetValue();
578 AddObjectToEnd(type,begin,--end2);
579 type=gdcmDicomDir::GDCM_DICOMDIR_PATIENT;
586 AddObjectToEnd(type,begin,--end2);
587 type=gdcmDicomDir::GDCM_DICOMDIR_STUDY;
594 AddObjectToEnd(type,begin,--end2);
595 type=gdcmDicomDir::GDCM_DICOMDIR_SERIE;
602 AddObjectToEnd(type,begin,--end2);
603 type=gdcmDicomDir::GDCM_DICOMDIR_IMAGE;
608 end=end2=listEntries.end();
610 AddObjectToEnd(type,begin,--end2);
613 * \ingroup gdcmDicomDir
614 * \brief AddObjectToEnd
619 void gdcmDicomDir::AddObjectToEnd(gdcmDicomDirType type,ListTag::iterator begin,ListTag::iterator end)
626 case gdcmDicomDir::GDCM_DICOMDIR_META:
627 AddDicomDirMetaToEnd(begin,end);
629 case gdcmDicomDir::GDCM_DICOMDIR_PATIENT:
630 AddDicomDirPatientToEnd(begin,end);
632 case gdcmDicomDir::GDCM_DICOMDIR_STUDY:
633 AddDicomDirStudyToEnd(begin,end);
635 case gdcmDicomDir::GDCM_DICOMDIR_SERIE:
636 AddDicomDirSerieToEnd(begin,end);
638 case gdcmDicomDir::GDCM_DICOMDIR_IMAGE:
639 AddDicomDirImageToEnd(begin,end);
645 * \ingroup gdcmDicomDir
646 * \brief Well ... Not realy to end, there is only one occurence
650 void gdcmDicomDir::AddDicomDirMetaToEnd(ListTag::iterator begin,ListTag::iterator end)
654 metaElems = new gdcmDicomDirMeta(begin,end,&tagHT,&listEntries);
658 * \ingroup gdcmDicomDir
659 * \brief AddDicomDirPatientToEnd
663 void gdcmDicomDir::AddDicomDirPatientToEnd(ListTag::iterator begin,ListTag::iterator end)
665 patients.push_back(new gdcmDicomDirPatient(begin,end,&tagHT, &listEntries));
669 * \ingroup gdcmDicomDir
670 * \brief AddDicomDirStudyToEnd
674 void gdcmDicomDir::AddDicomDirStudyToEnd(ListTag::iterator begin,ListTag::iterator end)
676 if(patients.size()>0)
678 ListDicomDirPatient::iterator itp=patients.end();
680 (*itp)->AddDicomDirStudy(new gdcmDicomDirStudy(begin,end,&tagHT, &listEntries));
684 * \ingroup gdcmDicomDir
685 * \brief AddDicomDirSerieToEnd
689 void gdcmDicomDir::AddDicomDirSerieToEnd(ListTag::iterator begin,ListTag::iterator end)
691 if(patients.size()>0)
693 ListDicomDirPatient::iterator itp=patients.end();
696 if((*itp)->GetDicomDirStudies().size()>0)
698 ListDicomDirStudy::iterator itst=(*itp)->GetDicomDirStudies().end();
700 (*itst)->AddDicomDirSerie(new gdcmDicomDirSerie(begin,end,&tagHT, &listEntries));
706 * \ingroup gdcmDicomDir
707 * \brief AddDicomDirImageToEnd
711 void gdcmDicomDir::AddDicomDirImageToEnd(ListTag::iterator begin,ListTag::iterator end)
713 if(patients.size()>0)
715 ListDicomDirPatient::iterator itp=patients.end();
718 if((*itp)->GetDicomDirStudies().size()>0)
720 ListDicomDirStudy::iterator itst=(*itp)->GetDicomDirStudies().end();
723 if((*itst)->GetDicomDirSeries().size()>0)
725 ListDicomDirSerie::iterator its=(*itst)->GetDicomDirSeries().end();
727 (*its)->AddDicomDirImage(new gdcmDicomDirImage(begin,end,&tagHT, &listEntries));
734 * \ingroup gdcmDicomDir
735 * \brief for each Header of the chained list, add/update the Patient/Study/Serie/Image info
736 * @param path path of the root directory
737 * @param list chained list of Headers
739 void gdcmDicomDir::SetElements(std::string &path, ListHeader &list)
741 std::string patPrevName="", patPrevID="";
742 std::string studPrevInstanceUID="", studPrevID="";
743 std::string serPrevInstanceUID="", serPrevID="";
745 std::string patCurName, patCurID;
746 std::string studCurInstanceUID, studCurID;
747 std::string serCurInstanceUID, serCurID;
749 SetElement(path,GDCM_DICOMDIR_META,NULL);
751 ListTag::iterator debPat=listEntries.begin();
752 for(ListHeader::iterator it=list.begin();it!=list.end();++it)
754 // get the current file characteristics
755 patCurName= (*it)->GetEntryByNumber(0x0010,0x0010);
756 patCurID= (*it)->GetEntryByNumber(0x0010,0x0011);
757 studCurInstanceUID=(*it)->GetEntryByNumber(0x0020,0x000d);
758 studCurID= (*it)->GetEntryByNumber(0x0020,0x0010);
759 serCurInstanceUID= (*it)->GetEntryByNumber(0x0020,0x000e);
760 serCurID= (*it)->GetEntryByNumber(0x0020,0x0011);
762 if(patCurName!=patPrevName || patCurID!=patPrevID)
763 SetElement(path,GDCM_DICOMDIR_PATIENT,*it);
765 // if new Study Deal with 'STUDY' Elements
766 if(studCurInstanceUID!=studPrevInstanceUID || studCurID!=studPrevID)
767 SetElement(path,GDCM_DICOMDIR_STUDY,*it);
769 // if new Serie Deal with 'SERIE' Elements
770 if(serCurInstanceUID!=serPrevInstanceUID || serCurID!=serPrevID)
771 SetElement(path,GDCM_DICOMDIR_SERIE,*it);
773 // Always Deal with 'IMAGE' Elements
774 SetElement(path,GDCM_DICOMDIR_IMAGE,*it);
776 patPrevName= patCurName;
778 studPrevInstanceUID=studCurInstanceUID;
779 studPrevID= studCurID;
780 serPrevInstanceUID= serCurInstanceUID;
786 * \ingroup gdcmDicomDir
787 * \brief adds to the HTable and at the end of the Chained List
788 * the gdcmEntries (Dicom Elements) corresponding to the given type
789 * @param path full path file name(only used when type = GDCM_DICOMDIR_IMAGE
790 * @param type gdcmObject type to create (GDCM_DICOMDIR_PATIENT, GDCM_DICOMDIR_STUDY, GDCM_DICOMDIR_SERIE ...)
791 * @param header gdcmHeader of the current file
793 void gdcmDicomDir::SetElement(std::string &path,gdcmDicomDirType type,gdcmHeader *header)
795 std::list<gdcmElement> elemList;
796 std::list<gdcmElement>::iterator it;
797 guint16 tmpGr, tmpEl;
798 gdcmDictEntry *dictEntry;
799 gdcmHeaderEntry *entry;
804 case GDCM_DICOMDIR_PATIENT:
805 elemList=gdcmGlobal::GetDicomDirElements()->GetDicomDirPatientElements();
807 case GDCM_DICOMDIR_STUDY:
808 elemList=gdcmGlobal::GetDicomDirElements()->GetDicomDirStudyElements();
810 case GDCM_DICOMDIR_SERIE:
811 elemList=gdcmGlobal::GetDicomDirElements()->GetDicomDirSerieElements();
813 case GDCM_DICOMDIR_IMAGE:
814 elemList=gdcmGlobal::GetDicomDirElements()->GetDicomDirImageElements();
816 case GDCM_DICOMDIR_META:
817 elemList=gdcmGlobal::GetDicomDirElements()->GetDicomDirMetaElements();
823 for(it=elemList.begin();it!=elemList.end();++it)
827 dictEntry=GetPubDict()->GetDictEntryByNumber(tmpGr,tmpEl);
828 entry=new gdcmHeaderEntry(dictEntry);
829 entry->SetOffset(0); // just to avoid missprinting
832 val=header->GetEntryByNumber(tmpGr,tmpEl);
836 if(val==GDCM_UNFOUND)
838 if((tmpGr==0x0004) &&(tmpEl==0x1130) ) // File-set ID
840 // force to the *end* File Name
843 else if( (tmpGr==0x0004) && (tmpEl==0x1500) ) // Only used for image
845 if(header->GetFileName().substr(0,path.length())!=path)
847 dbg.Verbose(0, "gdcmDicomDir::SetElement : the base path of file name is incorrect");
848 val=header->GetFileName();
851 val=&(header->GetFileName().c_str()[path.length()]);
861 if (header->GetEntryLengthByNumber(tmpGr,tmpEl)== 0)
865 entry->SetValue(val);
869 if(dictEntry->GetGroup()==0xfffe)
871 entry->SetLength(entry->GetValue().length());
873 else if( (dictEntry->GetVR()=="UL") || (dictEntry->GetVR()=="SL") )
877 else if( (dictEntry->GetVR()=="US") || (dictEntry->GetVR()=="SS") )
881 else if(dictEntry->GetVR()=="SQ")
883 entry->SetLength(0xffffffff);
887 entry->SetLength(entry->GetValue().length());
890 //AddHeaderEntry(entry); // both in H Table and in chained list
891 tagHT.insert( PairHT( entry->GetKey(),entry) );
892 listEntries.push_back(entry);
893 //wasUpdated = 1; // is private
897 bool gdcmDicomDir::HeaderLessThan(gdcmHeader *header1,gdcmHeader *header2)
899 return(*header1<*header2);
904 void gdcmDicomDir::UpdateDirectoryRecordSequenceLength() {
906 ListTag::iterator it;
909 for(it=listEntries.begin();it!=listEntries.end();++it) {
910 gr = (*it)->GetGroup();
911 el = (*it)->GetElement();
914 if ( (vr == "OB") || (vr == "OW") || (vr == "SQ") ) {
915 offset += 4; // explicit VR AND OB, OW, SQ : 4 more bytes
917 offset += 2 + 2 + 4 + (*it)->GetLength();
919 offset += 4; // delimiters don't have a value.
922 bool res=SetEntryLengthByNumber(offset, 0x0004, 0x1220); // Hope there is no dupps.
926 //-----------------------------------------------------------------------------