X-Git-Url: https://git.creatis.insa-lyon.fr/pubgit/?a=blobdiff_plain;ds=sidebyside;f=src%2FgdcmDocument.cxx;h=37966499bb038759d5d188a47fce182a6a0f29ab;hb=3fd520b58c8d1939994de2c63cc038c3e7ac9522;hp=36d1703c4d4548d6973ea45e747ad937fa2323db;hpb=ecac4d36edf15736ae8f516ef3f9d8a6396ed54c;p=gdcm.git diff --git a/src/gdcmDocument.cxx b/src/gdcmDocument.cxx index 36d1703c..37966499 100644 --- a/src/gdcmDocument.cxx +++ b/src/gdcmDocument.cxx @@ -3,8 +3,8 @@ Program: gdcm Module: $RCSfile: gdcmDocument.cxx,v $ Language: C++ - Date: $Date: 2004/08/01 03:20:23 $ - Version: $Revision: 1.63 $ + Date: $Date: 2004/08/26 15:29:53 $ + Version: $Revision: 1.68 $ Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image). All rights reserved. See Doc/License.txt or @@ -25,7 +25,6 @@ #include "gdcmUtil.h" #include "gdcmDebug.h" -#include #include // For nthos: @@ -83,21 +82,19 @@ const unsigned int gdcmDocument::MAX_SIZE_PRINT_ELEMENT_VALUE = 0x7fffffff; /** * \brief constructor * @param inFilename file to be opened for parsing - * @param exception_on_error whether we throw an exception or not */ -gdcmDocument::gdcmDocument( std::string const & filename, - bool exception_on_error) +gdcmDocument::gdcmDocument( std::string const & filename ) : gdcmElementSet(-1) { SetMaxSizeLoadEntry(MAX_SIZE_LOAD_ELEMENT_VALUE); Filename = filename; Initialise(); - if ( !OpenFile(exception_on_error)) + if ( !OpenFile() ) { return; } - + dbg.Verbose(0, "gdcmDocument::gdcmDocument: starting parsing of file: ", Filename.c_str()); rewind(Fp); @@ -137,7 +134,11 @@ gdcmDocument::gdcmDocument( std::string const & filename, CloseFile(); // -------------------------------------------------------------- - // Special Patch to allow gdcm to read ACR-LibIDO formated images + // Specific code to allow gdcm to read ACR-LibIDO formated images + // Note: ACR-LibIDO is an extension of the ACR standard that was + // used at CREATIS. For the time being (say a couple years) + // we keep this kludge to allow a smooth move to gdcm for + // CREATIS developpers (sorry folks). // // if recognition code tells us we deal with a LibIDO image // we switch lineNumber and columnNumber @@ -154,23 +155,20 @@ gdcmDocument::gdcmDocument( std::string const & filename, SetEntryByNumber(columns, 0x0028, 0x0010); SetEntryByNumber(rows , 0x0028, 0x0011); } - // ----------------- End of Special Patch ---------------- + // ----------------- End of ACR-LibIDO kludge ------------------ PrintLevel = 1; // 'Medium' print level by default } /** - * \brief constructor - * @param exception_on_error + * \brief This default constructor doesn't parse the file. You should + * then invoke \ref gdcmDocument::SetFileName and then the parsing. */ -gdcmDocument::gdcmDocument(bool exception_on_error) +gdcmDocument::gdcmDocument() :gdcmElementSet(-1) { - (void)exception_on_error; - SetMaxSizeLoadEntry(MAX_SIZE_LOAD_ELEMENT_VALUE); Initialise(); - PrintLevel = 1; // 'Medium' print level by default } @@ -262,8 +260,6 @@ bool gdcmDocument::IsReadable() { if( Filetype == gdcmUnknown) { - std::cout << " gdcmDocument::IsReadable: Filetype " << Filetype - << " " << "gdcmUnknown " << gdcmUnknown << std::endl; //JPR dbg.Verbose(0, "gdcmDocument::IsReadable: wrong filetype"); return false; } @@ -463,58 +459,46 @@ FileType gdcmDocument::GetFileType() } /** - * \brief opens the file - * @param exception_on_error - * @return + * \brief Tries to open the file \ref gdcmDocument::Filename and + * checks the preamble when existing. + * @return The FILE pointer on success. */ -FILE *gdcmDocument::OpenFile(bool exception_on_error) - throw(gdcmFileError) +FILE* gdcmDocument::OpenFile() { - Fp = fopen(Filename.c_str(),"rb"); + Fp = fopen(Filename.c_str(),"rb"); - if(!Fp) - { - if(exception_on_error) - { - throw gdcmFileError("gdcmDocument::gdcmDocument(const char *, bool)"); - } - else - { - dbg.Verbose(0, "gdcmDocument::OpenFile cannot open file: ", - Filename.c_str()); - return NULL; - } - } - - if ( Fp ) - { - uint16_t zero; - fread(&zero, (size_t)2, (size_t)1, Fp); - - //ACR -- or DICOM with no Preamble -- - if( zero == 0x0008 || zero == 0x0800 || zero == 0x0002 || zero == 0x0200 ) - { - return Fp; - } - - //DICOM - fseek(Fp, 126L, SEEK_CUR); - char dicm[4]; - fread(dicm, (size_t)4, (size_t)1, Fp); - if( memcmp(dicm, "DICM", 4) == 0 ) - { - return Fp; - } - - fclose(Fp); - dbg.Verbose(0, "gdcmDocument::OpenFile not DICOM/ACR", Filename.c_str()); - } - else - { - dbg.Verbose(0, "gdcmDocument::OpenFile cannot open file", Filename.c_str()); - } - - return 0; + if(!Fp) + { + dbg.Verbose( 0, + "gdcmDocument::OpenFile cannot open file: ", + Filename.c_str()); + return 0; + } + + uint16_t zero; + fread(&zero, (size_t)2, (size_t)1, Fp); + + //ACR -- or DICOM with no Preamble -- + if( zero == 0x0008 || zero == 0x0800 || zero == 0x0002 || zero == 0x0200 ) + { + return Fp; + } + + //DICOM + fseek(Fp, 126L, SEEK_CUR); + char dicm[4]; + fread(dicm, (size_t)4, (size_t)1, Fp); + if( memcmp(dicm, "DICM", 4) == 0 ) + { + return Fp; + } + + fclose(Fp); + dbg.Verbose( 0, + "gdcmDocument::OpenFile not DICOM/ACR (missing preamble)", + Filename.c_str()); + + return 0; } /** @@ -685,6 +669,35 @@ gdcmBinEntry * gdcmDocument::ReplaceOrCreateByNumber( return b; } + +/* + * \brief Modifies the value of a given Header Entry (Dicom Element) + * when it exists. Create it when unexistant. + * @param Group Group number of the Entry + * @param Elem Element number of the Entry + * \return pointer to the modified/created SeqEntry (NULL when creation + * failed). + */ +gdcmSeqEntry * gdcmDocument::ReplaceOrCreateByNumber( + uint16_t group, + uint16_t elem) +{ + gdcmSeqEntry* b = 0; + gdcmDocEntry* a = GetDocEntryByNumber( group, elem); + if (!a) + { + a = NewSeqEntryByNumber(group, elem); + if (!a) + { + return 0; + } + + b = new gdcmSeqEntry(a, 1); // FIXME : 1 (Depth) + AddEntry(b); + } + return b; +} + /** * \brief Set a new value if the invoked element exists * Seems to be useless !!! @@ -1221,7 +1234,7 @@ uint32_t gdcmDocument::SwapLong(uint32_t a) a=( ((a<< 8) & 0xff00ff00) | ((a>>8) & 0x00ff00ff) ); break; default : - std::cout << "swapCode= " << SwapCode << std::endl; + //std::cout << "swapCode= " << SwapCode << std::endl; dbg.Error(" gdcmDocument::SwapLong : unset swap code"); a = 0; } @@ -1386,7 +1399,6 @@ long gdcmDocument::ParseDES(gdcmDocEntrySet *set, } delete newDocEntry; } - return l; // Probably useless } @@ -1499,8 +1511,12 @@ void gdcmDocument::LoadDocEntry(gdcmDocEntry* entry) } // to be sure we are at the end of the value ... fseek(Fp, (long)entry->GetOffset()+(long)entry->GetLength(), SEEK_SET); - - return; //FIXME FIXME FIXME FIXME ???? + // Following return introduced by JPR on version 1.25. Since the + // treatement of a ValEntry is never executed (doh!) this means + // we were lucky up to now because we NEVER encountered a ValEntry + // whose length was bigger thant MaxSizeLoadEntry !? I can't believe + // this could ever work... + return; //FIXME FIXME FIXME FIXME JPR ???? // Be carefull : a BinEntry IS_A ValEntry ... if (gdcmValEntry* valEntryPtr = dynamic_cast< gdcmValEntry* >(entry) ) @@ -1531,7 +1547,7 @@ void gdcmDocument::LoadDocEntry(gdcmDocEntry* entry) if ( IsDocEntryAnInteger(entry) ) { uint32_t NewInt; - std::ostringstream s; + //std::ostringstream s; //shadow previous declaration int nbInt; // When short integer(s) are expected, read and convert the following // n *two characters properly i.e. consider them as short integers as @@ -1618,12 +1634,12 @@ void gdcmDocument::LoadDocEntry(gdcmDocEntry* entry) * \brief Find the value Length of the passed Header Entry * @param Entry Header Entry whose length of the value shall be loaded. */ -void gdcmDocument::FindDocEntryLength (gdcmDocEntry *entry) +void gdcmDocument::FindDocEntryLength( gdcmDocEntry *entry ) + throw ( gdcmFormatError ) { uint16_t element = entry->GetElement(); std::string vr = entry->GetVR(); - uint16_t length16; - + uint16_t length16; if ( Filetype == gdcmExplicitVR && !entry->IsImplicitVR() ) { @@ -1637,8 +1653,12 @@ void gdcmDocument::FindDocEntryLength (gdcmDocEntry *entry) if ( vr == "OB" && length32 == 0xffffffff ) { - uint32_t lengthOB = FindDocEntryLengthOB(); - if ( errno == 1 ) + uint32_t lengthOB; + try + { + lengthOB = FindDocEntryLengthOB(); + } + catch ( gdcmFormatUnexpected ) { // Computing the length failed (this happens with broken // files like gdcm-JPEG-LossLess3a.dcm). We still have a @@ -1650,7 +1670,6 @@ void gdcmDocument::FindDocEntryLength (gdcmDocEntry *entry) long lengthUntilEOF = ftell(Fp) - currentPosition; fseek(Fp, currentPosition, SEEK_SET); entry->SetLength(lengthUntilEOF); - errno = 0; return; } entry->SetLength(lengthOB); @@ -1694,8 +1713,8 @@ void gdcmDocument::FindDocEntryLength (gdcmDocEntry *entry) { if ( !IsExplicitVRBigEndianTransferSyntax() ) { - dbg.Verbose(0, "gdcmDocument::FindLength", "not explicit VR"); - errno = 1; + throw gdcmFormatError( "gdcmDocument::FindDocEntryLength()", + " not explicit VR." ); return; } length16 = 4; @@ -1719,11 +1738,10 @@ void gdcmDocument::FindDocEntryLength (gdcmDocEntry *entry) // Heuristic: well, some files are really ill-formed. if ( length16 == 0xffff) { + // 0xffff means that we deal with 'Unknown Length' Sequence length16 = 0; - // Length16= 0xffff means that we deal with - // 'Unknown Length' Sequence } - FixDocEntryFoundLength(entry, (uint32_t)length16); + FixDocEntryFoundLength( entry, (uint32_t)length16 ); return; } else @@ -1735,7 +1753,7 @@ void gdcmDocument::FindDocEntryLength (gdcmDocEntry *entry) // not coexist in a Data Set and Data Sets nested within it".] // Length is on 4 bytes. - FixDocEntryFoundLength(entry, ReadInt32()); + FixDocEntryFoundLength( entry, ReadInt32() ); return; } } @@ -2150,6 +2168,7 @@ bool gdcmDocument::IsDocEntryAnInteger(gdcmDocEntry *entry) */ uint32_t gdcmDocument::FindDocEntryLengthOB() + throw( gdcmFormatUnexpected ) { // See PS 3.5-2001, section A.4 p. 49 on encapsulation of encoded pixel data. long positionOnEntry = ftell(Fp); @@ -2158,26 +2177,33 @@ uint32_t gdcmDocument::FindDocEntryLengthOB() while ( !foundSequenceDelimiter ) { - uint16_t g = ReadInt16(); - uint16_t n = ReadInt16(); - if ( errno == 1 ) + uint16_t group; + uint16_t elem; + try { - return 0; + group = ReadInt16(); + elem = ReadInt16(); + } + catch ( gdcmFormatError ) + { + throw gdcmFormatError("gdcmDocument::FindDocEntryLengthOB()", + " group or element not present."); } // We have to decount the group and element we just read totalLength += 4; - if ( g != 0xfffe || ( n != 0xe0dd && n != 0xe000 ) ) + if ( group != 0xfffe || ( ( elem != 0xe0dd ) && ( elem != 0xe000 ) ) ) { - dbg.Verbose(1, "gdcmDocument::FindLengthOB: neither an Item tag " - "nor a Sequence delimiter tag."); + dbg.Verbose(1, "gdcmDocument::FindDocEntryLengthOB: neither an Item " + "tag nor a Sequence delimiter tag."); fseek(Fp, positionOnEntry, SEEK_SET); - errno = 1; - return 0; + throw gdcmFormatUnexpected("gdcmDocument::FindDocEntryLengthOB()", + "Neither an Item tag nor a Sequence " + "delimiter tag."); } - if ( n == 0xe0dd ) + if ( elem == 0xe0dd ) { foundSequenceDelimiter = true; } @@ -2202,6 +2228,7 @@ uint32_t gdcmDocument::FindDocEntryLengthOB() * @return read value */ uint16_t gdcmDocument::ReadInt16() + throw( gdcmFormatError ) { uint16_t g; size_t item_read = fread (&g, (size_t)2,(size_t)1, Fp); @@ -2209,12 +2236,10 @@ uint16_t gdcmDocument::ReadInt16() { if( ferror(Fp) ) { - dbg.Verbose(0, "gdcmDocument::ReadInt16", " File Error"); + throw gdcmFormatError( "gdcmDocument::ReadInt16()", " file error." ); } - errno = 1; - return 0; + throw gdcmFormatError( "gdcmDocument::ReadInt16()", "EOF." ); } - errno = 0; g = SwapShort(g); return g; } @@ -2225,6 +2250,7 @@ uint16_t gdcmDocument::ReadInt16() * @return read value */ uint32_t gdcmDocument::ReadInt32() + throw( gdcmFormatError ) { uint32_t g; size_t item_read = fread (&g, (size_t)4,(size_t)1, Fp); @@ -2232,12 +2258,10 @@ uint32_t gdcmDocument::ReadInt32() { if( ferror(Fp) ) { - dbg.Verbose(0, "gdcmDocument::ReadInt32", " File Error"); + throw gdcmFormatError( "gdcmDocument::ReadInt16()", " file error." ); } - errno = 1; - return 0; + throw gdcmFormatError( "gdcmDocument::ReadInt32()", "EOF." ); } - errno = 0; g = SwapLong(g); return g; } @@ -2524,28 +2548,39 @@ void gdcmDocument::SetMaxSizePrintEntry(long newSize) * gets the VR, gets the length, gets the offset value) * @return On succes the newly created DocEntry, NULL on failure. */ -gdcmDocEntry *gdcmDocument::ReadNextDocEntry() +gdcmDocEntry* gdcmDocument::ReadNextDocEntry() { - uint16_t g = ReadInt16(); - uint16_t n = ReadInt16(); + uint16_t group; + uint16_t elem; - if (errno == 1) + try + { + group = ReadInt16(); + elem = ReadInt16(); + } + catch ( gdcmFormatError e ) { // We reached the EOF (or an error occured) therefore // header parsing has to be considered as finished. + //std::cout << e; return 0; } - gdcmDocEntry *newEntry = NewDocEntryByNumber(g, n); + gdcmDocEntry *newEntry = NewDocEntryByNumber(group, elem); FindDocEntryVR(newEntry); - FindDocEntryLength(newEntry); - if (errno == 1) + try + { + FindDocEntryLength(newEntry); + } + catch ( gdcmFormatError e ) { // Call it quits + //std::cout << e; delete newEntry; return 0; } + newEntry->SetOffset(ftell(Fp)); return newEntry;