X-Git-Url: https://git.creatis.insa-lyon.fr/pubgit/?a=blobdiff_plain;f=src%2FgdcmDocument.cxx;h=c9e7bddc598844cb4249e082b8e982e7d28352af;hb=f07febbce9f70fd0faee0f3ce3df674c1e7f8a13;hp=8ac4b2296ae0d43209ef487b7bfed0319bf1e90c;hpb=880f6dfe2e061712fafbf75ab9547aadf170fc40;p=gdcm.git diff --git a/src/gdcmDocument.cxx b/src/gdcmDocument.cxx index 8ac4b229..c9e7bddc 100644 --- a/src/gdcmDocument.cxx +++ b/src/gdcmDocument.cxx @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmDocument.cxx,v $ Language: C++ - Date: $Date: 2006/05/05 22:13:55 $ - Version: $Revision: 1.347 $ + Date: $Date: 2006/07/10 09:41:46 $ + Version: $Revision: 1.353 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -62,11 +62,13 @@ Document::Document() Initialize(); SwapCode = 1234; Filetype = ExplicitVR; + CurrentOffsetPosition = 0; // Load will set it to true if sucessfull Group0002Parsed = false; IsDocumentAlreadyLoaded = false; IsDocumentModified = true; LoadMode = LD_ALL; // default : load everything, later + SetFileName(""); } @@ -95,19 +97,22 @@ bool Document::Load( ) return DoTheLoadingDocumentJob( ); } -#ifndef GDCM_LEGACY_REMOVE + +//#ifndef GDCM_LEGACY_REMOVE /** * \brief Loader. (DEPRECATED : not to break the API) * @param fileName 'Document' (File or DicomDir) to be open for parsing * @return false if file cannot be open or no swap info was found, * or no tag was found. */ + /* bool Document::Load( std::string const &fileName ) { Filename = fileName; return DoTheLoadingDocumentJob( ); } -#endif +*/ +//#endif /** * \brief Performs the Loading Job (internal use only) @@ -260,7 +265,7 @@ bool Document::DoTheLoadingDocumentJob( ) LoadDocEntry(d, true); } - CloseFile(); + CloseFile(); // ---------------------------- // Specific code to allow gdcm to read ACR-LibIDO formated images @@ -621,7 +626,6 @@ std::ifstream *Document::OpenFile() } //-- Broken ACR or DICOM with no Preamble; may start with a Shadow Group -- - // FIXME : We cannot be sure the preable is only zeroes.. // (see ACUSON-24-YBR_FULL-RLE.dcm ) if ( @@ -687,7 +691,7 @@ void Document::WriteContent(std::ofstream *fp, FileType filetype) // Skip if user wants to write an ACR-NEMA file if ( filetype == ImplicitVR || filetype == ExplicitVR || - filetype == JPEG ) + filetype == JPEG || filetype == JPEG2000 ) { // writing Dicom File Preamble char filePreamble[128]; @@ -906,6 +910,27 @@ bool Document::operator<(Document &document) //----------------------------------------------------------------------------- // Protected + +/** + * \brief Reads a given length of bytes + * (in order to avoid to many CPU time consuming fread-s) + * @param l length to read + */ +void Document::ReadBegBuffer(size_t l) + throw( FormatError ) +{ + Fp->read (BegBuffer, (size_t)l); + if ( Fp->fail() ) + { + throw FormatError( "Document::ReadBegBuffer()", " file error." ); + } + if ( Fp->eof() ) + { + throw FormatError( "Document::ReadBegBuffer()", "EOF." ); + } + PtrBegBuffer = BegBuffer; + CurrentOffsetPosition+=l; +} /** * \brief Reads a supposed to be 16 Bits integer * (swaps it depending on processor endianness) @@ -928,6 +953,18 @@ uint16_t Document::ReadInt16() return g; } +/** + * \brief Gets from BegBuffer a supposed to be 16 Bits integer + * (swaps it depending on processor endianness) + * @return read value + */ +uint16_t Document::GetInt16() +{ + uint16_t g = *((uint16_t*)PtrBegBuffer); + g = SwapShort(g); + PtrBegBuffer+=2; + return g; +} /** * \brief Reads a supposed to be 32 Bits integer * (swaps it depending on processor endianness) @@ -950,6 +987,19 @@ uint32_t Document::ReadInt32() return g; } +/** + * \brief Gets from BegBuffer a supposed to be 32 Bits integer + * (swaps it depending on processor endianness) + * @return read value + */ +uint32_t Document::GetInt32() +{ + uint32_t g = *((uint32_t*)PtrBegBuffer); + g = SwapLong(g); + PtrBegBuffer+=4; + return g; +} + /** * \brief Re-computes the length of the Dicom group 0002. */ @@ -1046,7 +1096,7 @@ void Document::ParseDES(DocEntrySet *set, long offset, DocEntry *newDocEntry; DataEntry *newDataEntry; SeqEntry *newSeqEntry; - VRKey vr; + //VRKey vr; bool used; // will be set to false when something wrong happens to an Entry. // (Entry will then be deleted) bool delim_mode_intern = delim_mode; @@ -1064,7 +1114,7 @@ void Document::ParseDES(DocEntrySet *set, long offset, if( Debug::GetDebugFlag() ) std::cout << std::dec <<"(long)(Fp->tellg()) " << (long)(Fp->tellg()) // in Debug mode << std::hex << " 0x(" <<(long)(Fp->tellg()) << ")" << std::endl; -*/ + */ // if ( !delim_mode && ((long)(Fp->tellg())-offset) >= l_max) // Once per DocEntry if ( !delim_mode ) // 'and then' doesn't exist in C++ :-( @@ -1072,19 +1122,20 @@ void Document::ParseDES(DocEntrySet *set, long offset, { break; } - newDocEntry = ReadNextDocEntry( ); - // Uncoment this cerr line to be able to 'follow' the DocEntries - // when something *very* strange happens - if( Debug::GetDebugFlag() ) - std::cerr<GetKey()<<" "<GetVR()<GetKey()<<" "<GetVR()<GetVR(); + //vr = newDocEntry->GetVR(); // useless ? if ( !set->AddEntry( newDataEntry ) ) { @@ -1377,10 +1428,10 @@ DocEntry *Document::Backtrack(DocEntry *docEntry) */ void Document::LoadDocEntry(DocEntry *entry, bool forceLoad) { - uint16_t group = entry->GetGroup(); - uint16_t elem = entry->GetElement(); + uint16_t group = entry->GetGroup(); + uint16_t elem = entry->GetElement(); const VRKey &vr = entry->GetVR(); - uint32_t length = entry->GetLength(); + uint32_t length = entry->GetLength(); // Fp->seekg((long)entry->GetOffset(), std::ios::beg); // JPRx @@ -1456,9 +1507,9 @@ void Document::FindDocEntryLength( DocEntry *entry ) // "7.1.2 Data element structure with explicit vr", p 27) must be // skipped before proceeding on reading the length on 4 bytes. - Fp->seekg( 2L, std::ios::cur); // Once per OW,OB,SQ DocEntry - uint32_t length32 = ReadInt32(); - + //Fp->seekg( 2L, std::ios::cur); // Once per OW,OB,SQ DocEntry + uint32_t length32 = ReadInt32(); // Once per OW,OB,SQ DocEntry + CurrentOffsetPosition+=4; if ( (vr == "OB" || vr == "OW") && length32 == 0xffffffff ) { uint32_t lengthOB; @@ -1495,8 +1546,9 @@ void Document::FindDocEntryLength( DocEntry *entry ) } // Length is encoded on 2 bytes. - length16 = ReadInt16(); - + //length16 = ReadInt16(); + length16 = GetInt16(); + // 0xffff means that we deal with 'No Length' Sequence // or 'No Length' SQItem if ( length16 == 0xffff) @@ -1519,8 +1571,8 @@ void Document::FindDocEntryLength( DocEntry *entry ) // even if Transfer Syntax is 'Implicit VR ...' // --> Except for 'Implicit VR Big Endian Transfer Syntax GE Private' // where Group 0x0002 is *also* encoded in Implicit VR ! - - FixDocEntryFoundLength( entry, ReadInt32() ); + + FixDocEntryFoundLength( entry, GetInt32() /*ReadInt32()*/ ); return; } } @@ -1534,6 +1586,7 @@ uint32_t Document::FindDocEntryLengthOBOrOW() throw( FormatUnexpected ) { // See PS 3.5-2001, section A.4 p. 49 on encapsulation of encoded pixel data. + long positionOnEntry = Fp->tellg(); // Only for OB,OW DataElements bool foundSequenceDelimiter = false; @@ -1543,16 +1596,21 @@ uint32_t Document::FindDocEntryLengthOBOrOW() { uint16_t group; uint16_t elem; + try { - group = ReadInt16(); - elem = ReadInt16(); + //group = ReadInt16(); // Once per fragment (if any) of OB,OW DataElements + //elem = ReadInt16(); // Once per fragment (if any) of OB,OW DataElements + ReadBegBuffer(4); // Once per fragment (if any) of OB,OW DataElements } catch ( FormatError ) { throw FormatError("Unexpected end of file encountered during ", "Document::FindDocEntryLengthOBOrOW()"); } + group = GetInt16(); + elem = GetInt16(); + // We have to decount the group and element we just read totalLength += 4; if ( group != 0xfffe || ( ( elem != 0xe0dd ) && ( elem != 0xe000 ) ) ) @@ -1570,7 +1628,7 @@ uint32_t Document::FindDocEntryLengthOBOrOW() { foundSequenceDelimiter = true; } - uint32_t itemLength = ReadInt32(); + uint32_t itemLength = ReadInt32(); // Once per fragment (if any) of OB,OW DataElements // We add 4 bytes since we just read the ItemLength with ReadInt32 totalLength += itemLength + 4; SkipBytes(itemLength); @@ -1580,7 +1638,7 @@ uint32_t Document::FindDocEntryLengthOBOrOW() break; } } - Fp->seekg( positionOnEntry, std::ios::beg); // Only for OB,OW DataElements + Fp->seekg( positionOnEntry, std::ios::beg); // Only once for OB,OW DataElements return totalLength; } @@ -1599,9 +1657,9 @@ VRKey Document::FindDocEntryVR() if ( CurrentGroup == 0xfffe ) return GDCM_VRUNKNOWN; - long positionOnEntry; - if( Debug::GetWarningFlag() ) - positionOnEntry = Fp->tellg(); // Only in Warning Mode + //long positionOnEntry; + //if( Debug::GetWarningFlag() ) + // positionOnEntry = Fp->tellg(); // Only in Warning Mode // Warning: we believe this is explicit VR (Value Representation) because // we used a heuristic that found "UL" in the first tag and/or @@ -1615,9 +1673,12 @@ VRKey Document::FindDocEntryVR() // if it happens not to be the case. VRKey vr; - Fp->read(&(vr[0]),(size_t)2); - - if ( !CheckDocEntryVR(vr) ) + //Fp->read(&(vr[0]),(size_t)2); + vr[0] = *PtrBegBuffer++; + vr[1] = *PtrBegBuffer++; + + //if ( !CheckDocEntryVR(vr) ) // avoid useless function call + if ( !Global::GetVR()->IsValidVR(vr) ) { /* // std::cout << "================================================================Unknown VR" @@ -1630,12 +1691,13 @@ VRKey Document::FindDocEntryVR() gdcmWarningMacro( "Unknown VR " << std::hex << "0x(" << (unsigned int)vr[0] << "|" << (unsigned int)vr[1] << ")" - << " at offset : 0x(" << positionOnEntry<< ") for group " << CurrentGroup + << " at offset : 0x(" << CurrentOffsetPosition-4<< ") for group " << CurrentGroup ); //Fp->seekg(positionOnEntry, std::ios::beg); //JPRx - Fp->seekg((long)-2, std::ios::cur);// only for unrecognized VR (?!?) + //Fp->seekg((long)-2, std::ios::cur);// only for unrecognized VR (?!?) //see :MR_Philips_Intera_PrivateSequenceExplicitVR.dcm + PtrBegBuffer-=2; return GDCM_VRUNKNOWN; } return vr; @@ -1803,6 +1865,7 @@ bool Document::IsDocEntryAnInteger(DocEntry *entry) // encounter such an ill-formed image, we simply display a warning // message and proceed on parsing (while crossing fingers). long filePosition = Fp->tellg(); // Only when elem 0x0000 length is not 4 (?!?) + (void)filePosition; gdcmWarningMacro( "Erroneous Group Length element length on : (" << std::hex << group << " , " << elem << ") -before- position x(" << filePosition << ")" @@ -1899,6 +1962,7 @@ bool Document::CheckSwap() // (i.e. after the file preamble and the "DICM" string). Fp->seekg ( 132L, std::ios::beg); // Once per Document + CurrentOffsetPosition = 132; return true; } // ------------------------------- End of DicomV3 ---------------- @@ -1909,7 +1973,7 @@ bool Document::CheckSwap() gdcmWarningMacro( "Not a Kosher DICOM Version3 file (no preamble)"); Fp->seekg(0, std::ios::beg); // Once per ACR-NEMA Document - + CurrentOffsetPosition = 0; // Let's check 'No Preamble Dicom File' : // Should start with group 0x0002 // and be Explicit Value Representation @@ -1989,6 +2053,9 @@ bool Document::CheckSwap() // Find a trick to tell it the caller... s16 = *((uint16_t *)(deb)); + + gdcmDebugMacro("not a DicomV3 nor a 'clean' ACR/NEMA;" + << " (->despaired wild guesses !)"); switch ( s16 ) { @@ -2077,8 +2144,9 @@ DocEntry *Document::ReadNextDocEntry() { try { - CurrentGroup = ReadInt16(); - CurrentElem = ReadInt16(); + ReadBegBuffer(8); // Avoid to many time consuming freads + //CurrentGroup = ReadInt16(); + //CurrentElem = ReadInt16(); } catch ( FormatError ) { @@ -2086,7 +2154,10 @@ DocEntry *Document::ReadNextDocEntry() // header parsing has to be considered as finished. return 0; } - + + CurrentGroup = GetInt16(); + CurrentElem = GetInt16(); + // In 'true DICOM' files Group 0002 is always little endian if ( HasDCMPreamble ) { @@ -2153,8 +2224,8 @@ DocEntry *Document::ReadNextDocEntry() // We thought this was explicit VR, but we end up with an // implicit VR tag. Let's backtrack. - //if ( newEntry->GetGroup() != 0xfffe ) - if (CurrentGroup != 0xfffe ) + //if ( newEntry->GetGroup() != 0xfffe ) + if (CurrentGroup != 0xfffe) { int offset = Fp->tellg();//Only when heuristic for Explicit/Implicit was wrong @@ -2177,7 +2248,6 @@ DocEntry *Document::ReadNextDocEntry() } newEntry->SetOffset(Fp->tellg()); // for each DocEntry - return newEntry; } @@ -2189,6 +2259,23 @@ DocEntry *Document::ReadNextDocEntry() */ void Document::HandleBrokenEndian(uint16_t &group, uint16_t &elem) { + // for strange PMS Gyroscan Intera images + // Item 'starter' has a tag : 0x3f3f,0x3f00, for no apparent reason + + // --- Feel free to remove this test *on your own coy of gdcm* + // if you are sure you'll never face this problem. + + if ((group == 0x3f3f) && (elem == 0x3f00)) + { + // start endian swap mark for group found + gdcmDebugMacro( " delimiter 0x3f3f found." ); + // fix the tag + group = 0xfffe; + elem = 0xe000; + return; + } + // --- End of removable code + // Endian reversion. // Some files contain groups of tags with reversed endianess. static int reversedEndian = 0;