gdcmDocument.cxx

Go to the documentation of this file.
00001 /*=========================================================================
00002                                                                                 
00003   Program:   gdcm
00004   Module:    $RCSfile: gdcmDocument.cxx,v $
00005   Language:  C++
00006   Date:      $Date: 2007/08/21 12:51:09 $
00007   Version:   $Revision: 1.367 $
00008                                                                                 
00009   Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
00010   l'Image). All rights reserved. See Doc/License.txt or
00011   http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details.
00012                                                                                 
00013      This software is distributed WITHOUT ANY WARRANTY; without even
00014      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
00015      PURPOSE.  See the above copyright notices for more information.
00016                                                                                 
00017 =========================================================================*/
00018 
00019 #include "gdcmDocument.h"
00020 #include "gdcmSeqEntry.h"
00021 #include "gdcmGlobal.h"
00022 #include "gdcmUtil.h"
00023 #include "gdcmDebug.h"
00024 #include "gdcmTS.h"
00025 #include "gdcmDictSet.h"
00026 #include "gdcmDocEntrySet.h"
00027 #include "gdcmSQItem.h"
00028 #include "gdcmDataEntry.h"
00029 
00030 #include <vector>
00031 #include <iomanip>
00032 #include <fstream>
00033 #include <ctype.h>  // for isdigit
00034 #include <stdlib.h> // for atoi
00035 
00036 #if defined(__BORLANDC__)
00037    #include <mem.h> // for memset
00038 #endif 
00039 
00040 namespace GDCM_NAME_SPACE 
00041 {
00042 //-----------------------------------------------------------------------------
00043 
00044 // Refer to Document::SetMaxSizeLoadEntry()
00045 const unsigned int Document::MAX_SIZE_LOAD_ELEMENT_VALUE = 0xfff; // 4096
00046 
00047 //-----------------------------------------------------------------------------
00048 // Constructor / Destructor
00049 // Constructors and destructors are protected to avoid user to invoke directly
00050 
00056 Document::Document() 
00057          :ElementSet()
00058 {
00059    Fp = 0;
00060 
00061    SetMaxSizeLoadEntry(MAX_SIZE_LOAD_ELEMENT_VALUE);
00062    Initialize();
00063    SwapCode = 1234;
00064    Filetype = ExplicitVR;
00065    CurrentOffsetPosition = 0;
00066    // Load will set it to true if sucessfull
00067    Group0002Parsed = false;
00068    IsDocumentAlreadyLoaded = false;
00069    IsDocumentModified = true;
00070    LoadMode = LD_ALL; // default : load everything, later
00071    
00072    SetFileName("");
00073    changeFromUN=false;
00074    UnexpectedEOF=false;
00075 }
00076 
00080 Document::~Document ()
00081 {
00082    CloseFile();
00083 }
00084 
00085 //-----------------------------------------------------------------------------
00086 // Public
00092 bool Document::Load(  ) 
00093 {
00094    if ( GetFileName() == "" )
00095    {
00096       gdcmWarningMacro( "Use SetFileName, before !" );
00097       return false;
00098    }
00099    return DoTheLoadingDocumentJob( );
00100 }
00101 
00102 
00103 //#ifndef GDCM_LEGACY_REMOVE
00110  /*
00111 bool Document::Load( std::string const &fileName ) 
00112 {
00113    Filename = fileName;
00114    return DoTheLoadingDocumentJob( );
00115 }
00116 */
00117 //#endif
00118 
00124 bool Document::DoTheLoadingDocumentJob(  ) 
00125 {
00126    if ( ! IsDocumentModified ) // Nothing to do !
00127       return true;
00128 
00129    ClearEntry();
00130 
00131    Fp = 0;
00132    if ( !OpenFile() )
00133    {
00134       // warning already performed in OpenFile()
00135       Filetype = Unknown;
00136       return false;
00137    }
00138 
00139    Group0002Parsed = false;
00140 
00141    gdcmDebugMacro( "Starting parsing of file: " << Filename.c_str());
00142 
00143    // Computes the total length of the file
00144    Fp->seekg(0, std::ios::end);  // Once per Document !
00145    long lgt = Fp->tellg();       // Once per Document !   
00146    Fp->seekg(0, std::ios::beg);  // Once per Document !
00147 
00148    // CheckSwap returns a boolean 
00149    // (false if no swap info of any kind was found)
00150    if (! CheckSwap() )
00151    {
00152       gdcmWarningMacro( "Neither a DICOM V3 nor an ACR-NEMA file: " 
00153                    << Filename.c_str());
00154       CloseFile(); 
00155       return false;      
00156     }
00157 
00158    long beg = Fp->tellg();      // just after DICOM preamble (if any)
00159 
00160    lgt -= beg;                  // remaining length to parse    
00161 
00162    // Recursive call.
00163    // Loading is done during parsing
00164    ParseDES( this, beg, lgt, false); // delim_mode is first defaulted to false
00165 
00166    if ( IsEmpty() )
00167    { 
00168       gdcmErrorMacro( "No tag in internal hash table for: "
00169                         << Filename.c_str());
00170       CloseFile(); 
00171       return false;
00172    }
00173    IsDocumentAlreadyLoaded = true;
00174 
00175    //Fp->seekg(0, std::ios::beg);  // Once per Document!
00176    
00177    // Load 'non string' values
00178       
00179    std::string PhotometricInterpretation = GetEntryString(0x0028,0x0004);   
00180    if ( PhotometricInterpretation == "PALETTE COLOR " )
00181    {
00182    // FIXME
00183    // Probabely this line should be outside the 'if'
00184    // Try to find an image sample holding a 'gray LUT'
00185       LoadEntryBinArea(0x0028,0x1200);  // gray LUT
00186    
00209       
00210       // --> OB (byte aray) or OW (short int aray)
00211       // The actual VR has to be deduced from other entries.
00212       // Our way of loading them may fail in some cases :
00213       // We must or not SwapByte depending on other field values.
00214              
00215       LoadEntryBinArea(0x0028,0x1201);  // R    LUT
00216       LoadEntryBinArea(0x0028,0x1202);  // G    LUT
00217       LoadEntryBinArea(0x0028,0x1203);  // B    LUT
00218       
00219       // Segmented Red   Palette Color LUT Data
00220       LoadEntryBinArea(0x0028,0x1221);
00221       // Segmented Green Palette Color LUT Data
00222       LoadEntryBinArea(0x0028,0x1222);
00223       // Segmented Blue  Palette Color LUT Data
00224       LoadEntryBinArea(0x0028,0x1223);
00225    }
00226  
00227    //FIXME later : how to use it?
00228    SeqEntry *modLutSeq = GetSeqEntry(0x0028,0x3000); // Modality LUT Sequence
00229    if ( modLutSeq !=0 )
00230    {
00231       SQItem *sqi= modLutSeq->GetFirstSQItem();
00232       if ( sqi != 0 )
00233       {
00234          DataEntry *dataEntry = sqi->GetDataEntry(0x0028,0x3006); // LUT Data
00235          if ( dataEntry != 0 )
00236          {
00237             if ( dataEntry->GetLength() != 0 )
00238             {
00239                // FIXME : CTX dependent means : contexted dependant.
00240                //         see upper comment.
00241                LoadEntryBinArea(dataEntry);    //LUT Data (CTX dependent)
00242             }   
00243         }
00244      }      
00245    }
00246 
00247    // Force Loading some more elements if user asked to.
00248 
00249    GDCM_NAME_SPACE::DocEntry *d;
00250    for (ListElements::iterator it = UserForceLoadList.begin();  
00251                                it != UserForceLoadList.end();
00252                              ++it)
00253    {
00254       gdcmDebugMacro( "Force Load " << std::hex 
00255                        << (*it).Group << "|" <<(*it).Elem );
00256   
00257       d = GetDocEntry( (*it).Group, (*it).Elem);
00258   
00259       if ( d == NULL)
00260       {
00261          gdcmWarningMacro( "You asked to ForceLoad "  << std::hex
00262                           << (*it).Group <<"|"<< (*it).Elem
00263                           << " that doesn't exist" );
00264          continue;
00265       }
00266 
00267       LoadDocEntry(d, true);
00268    }
00269 
00270    CloseFile();
00271   
00272    // ----------------------------
00273    // Specific code to allow gdcm to read ACR-LibIDO formated images
00274    // Note: ACR-LibIDO is an extension of the ACR standard that was
00275    //       used at CREATIS. For the time being (say a couple of years)
00276    //       we keep this kludge to allow CREATIS users 
00277    //       reading their old images.
00278    //
00279    // if recognition code tells us we deal with a LibIDO image
00280    // we switch lineNumber and columnNumber
00281    //
00282    std::string RecCode;
00283    RecCode = GetEntryString(0x0008, 0x0010); // recognition code (RET)
00284    if (RecCode == "ACRNEMA_LIBIDO_1.1" ||
00285        RecCode == "CANRME_AILIBOD1_1." )  // for brain-damaged softwares
00286                                           // with "little-endian strings"
00287    {
00288          Filetype = ACR_LIBIDO; 
00289          std::string rows    = GetEntryString(0x0028, 0x0010);
00290          std::string columns = GetEntryString(0x0028, 0x0011);
00291          SetEntryString(columns, 0x0028, 0x0010);
00292          SetEntryString(rows   , 0x0028, 0x0011);
00293    }
00294    // --- End of ACR-LibIDO kludge --- 
00295    return true;
00296 }
00297 
00298 
00304 void Document::AddForceLoadElement (uint16_t group, uint16_t elem) 
00305 { 
00306    DicomElement el;
00307    el.Group = group;
00308    el.Elem  = elem;
00309    UserForceLoadList.push_back(el); 
00310 }
00314 Dict *Document::GetPubDict()
00315 {
00316    return RefPubDict;
00317 }
00318 
00322 Dict *Document::GetShaDict()
00323 {
00324    return RefShaDict;
00325 }
00326 
00331 bool Document::SetShaDict(Dict *dict)
00332 {
00333    RefShaDict = dict;
00334    return !RefShaDict;
00335 }
00336 
00341 bool Document::SetShaDict(DictKey const &dictName)
00342 {
00343    RefShaDict = Global::GetDicts()->GetDict(dictName);
00344    return !RefShaDict;
00345 }
00346 
00354 bool Document::IsParsable()
00355 {
00356    if ( Filetype == Unknown )
00357    {
00358       gdcmWarningMacro( "Wrong filetype for " << GetFileName());
00359       return false;
00360    }
00361 
00362    if ( IsEmpty() )
00363    { 
00364       gdcmWarningMacro( "No tag in internal hash table.");
00365       return false;
00366    }
00367 
00368    return true;
00369 }
00377 bool Document::IsReadable()
00378 {
00379    return IsParsable();
00380 }
00381 
00386 bool Document::IsDicomV3()
00387 {
00388    // Checking if Transfer Syntax exists is enough
00389    // Anyway, it's too late check if the 'Preamble' was found ...
00390    // And ... would it be a rich idea to check ?
00391    // (some 'no Preamble' DICOM images exist !)
00392    return GetDocEntry(0x0002, 0x0010) != NULL;
00393 }
00394 
00400 bool Document::IsPapyrus()
00401 {
00402    // check for Papyrus private Sequence
00403    DocEntry *e = GetDocEntry(0x0041, 0x1050);
00404    if ( !e )
00405       return false;
00406    // check if it's actually a Sequence
00407    if ( !dynamic_cast<SeqEntry*>(e) )
00408       return  false;
00409    return true;
00410 }
00411 
00417 FileType Document::GetFileType()
00418 {
00419    return Filetype;
00420 }
00421 
00429 std::string Document::GetTransferSyntax()
00430 {
00431    DocEntry *entry = GetDocEntry(0x0002, 0x0010);
00432    if ( !entry )
00433    {
00434       return GDCM_UNKNOWN;
00435    }
00436 
00437    // The entry might be present but not loaded (parsing and loading
00438    // happen at different stages): try loading and proceed with check...
00439    
00440    // Well ...
00441    // (parsing and loading happen at the very same stage!) 
00442    //LoadDocEntrySafe(entry); //JPRx
00443    if (DataEntry *dataEntry = dynamic_cast<DataEntry *>(entry) )
00444    {
00445       std::string transfer = dataEntry->GetString();
00446       // The actual transfer (as read from disk) might be padded. We
00447       // first need to remove the potential padding. We can make the
00448       // weak assumption that padding was not executed with digits...
00449       if  ( transfer.length() == 0 )
00450       {
00451          // for brain damaged headers
00452          gdcmWarningMacro( "Transfer Syntax has length = 0.");
00453          return GDCM_UNKNOWN;
00454       }
00455       while ( !isdigit((unsigned char)transfer[transfer.length()-1]) )
00456       {
00457          transfer.erase(transfer.length()-1, 1);
00458          if  ( transfer.length() == 0 )
00459          {
00460             // for brain damaged headers
00461             gdcmWarningMacro( "Transfer Syntax contains no valid character.");
00462             return GDCM_UNKNOWN;
00463          }
00464       }
00465       return transfer;
00466    }
00467    return GDCM_UNKNOWN;
00468 }
00469 
00474 std::string Document::GetTransferSyntaxName()
00475 {
00476    // use the TS (TS : Transfer Syntax)
00477    std::string transferSyntax = GetEntryString(0x0002,0x0010);
00478 
00479    if ( (transferSyntax.find(GDCM_NOTLOADED) < transferSyntax.length()) )
00480    {
00481       gdcmErrorMacro( "Transfer Syntax not loaded. " << std::endl
00482                << "Better you increase MAX_SIZE_LOAD_ELEMENT_VALUE" );
00483       return "Uncompressed ACR-NEMA";
00484    }
00485    if ( transferSyntax == GDCM_UNFOUND )
00486    {
00487       gdcmDebugMacro( "Unfound Transfer Syntax (0002,0010)");
00488       return "Uncompressed ACR-NEMA";
00489    }
00490 
00491    // we do it only when we need it
00492    const TSKey &tsName = Global::GetTS()->GetValue( transferSyntax );
00493 
00494    // Global::GetTS() is a global static you shall never try to delete it!
00495    return tsName;
00496 }
00497 //
00498 // --------------- Swap Code ------------------
00503 uint16_t Document::SwapShort(uint16_t a)
00504 {
00505    if ( SwapCode == 4321 || SwapCode == 2143 )
00506    {
00507       //a = ((( a << 8 ) & 0xff00 ) | (( a >> 8 ) & 0x00ff ) );
00508       // Save CPU time
00509       a = ( a << 8 ) | ( a >> 8 );
00510    }
00511    return a;
00512 }
00513 
00519 uint32_t Document::SwapLong(uint32_t a)
00520 {
00521    switch (SwapCode)
00522    {
00523       case 1234 :
00524          break;
00525       case 4321 :
00526 //         a=( ((a<<24) & 0xff000000) | ((a<<8)  & 0x00ff0000) | 
00527 //             ((a>>8)  & 0x0000ff00) | ((a>>24) & 0x000000ff) );
00528 // save CPU time
00529          a=( ( a<<24)               | ((a<<8)  & 0x00ff0000) | 
00530              ((a>>8)  & 0x0000ff00) |  (a>>24)                );
00531          break;   
00532       case 3412 :
00533 //       a=( ((a<<16) & 0xffff0000) | ((a>>16) & 0x0000ffff) );
00534          a=( (a<<16)                | (a>>16)  );
00535          break;  
00536       case 2143 :
00537          a=( ((a<< 8) & 0xff00ff00) | ((a>>8) & 0x00ff00ff)  );
00538       break;
00539       default :
00540          gdcmErrorMacro( "Unexpected swap code:" << SwapCode );
00541          a = 0;
00542    }
00543    return a;
00544 } 
00545 
00551 double Document::SwapDouble(double a)
00552 {
00553    switch (SwapCode)
00554    {
00555       // There were no 'double' at ACR-NEMA time.
00556       // We just have to deal with 'straight Little Endian' and 
00557       // 'straight Big Endian'
00558       case 1234 :
00559          break;
00560       case 4321 :
00561          {
00562          char *beg = (char *)&a;
00563          char *end = beg + 7;
00564          char t;
00565          for (unsigned int i = 0; i<7; i++)
00566          {
00567             t    = *beg;
00568             *beg = *end;
00569             *end = t;
00570             beg++,
00571             end--;  
00572          }
00573          }
00574          break;   
00575       default :
00576          gdcmErrorMacro( "Unexpected swap code:" << SwapCode );
00577          a = 0.;
00578    }
00579    return a;
00580 } 
00581 
00582 //
00583 // -----------------File I/O ---------------
00590 std::ifstream *Document::OpenFile()
00591 {
00592    HasDCMPreamble = false;
00593    if (Filename.length() == 0) 
00594    {
00595       return 0;
00596    }
00597 
00598    if ( Fp )
00599    {
00600       gdcmDebugMacro( "File already open: " << Filename.c_str());
00601       CloseFile();
00602    }
00603 
00604    Fp = new std::ifstream(Filename.c_str(), std::ios::in | std::ios::binary);
00605    if ( ! *Fp )
00606    {
00607    // Don't user gdcmErrorMacro :
00608    // a spurious message will appear when you use, for instance 
00609    // gdcm::FileHelper *fh = new gdcm::FileHelper( outputFileName );
00610    // to create outputFileName.
00611    
00612    // FIXME : if the upper comment is still usefull 
00613    //         --> the constructor is not so good ...
00614    
00615       gdcmWarningMacro( "Cannot open file: " << Filename.c_str());
00616       delete Fp;
00617       Fp = 0;
00618       return 0;
00619       //exit(1); // No function is allowed to leave the application instead
00620                  // of warning the caller
00621    }
00622  
00623    uint16_t zero = 0;
00624    Fp->read((char*)&zero, (size_t)2);
00625    if ( Fp->eof() )
00626    {
00627       CloseFile();
00628       return 0;
00629    }
00630  
00631    //-- DICOM --
00632    Fp->seekg(126L, std::ios::cur);  // Once per Document
00633    char dicm[4]; // = {' ',' ',' ',' '};
00634    Fp->read(dicm,  (size_t)4);
00635    if ( Fp->eof() )
00636    {
00637       CloseFile();
00638       return 0;
00639    }
00640    
00641    if ( memcmp(dicm, "DICM", 4) == 0 )
00642    {
00643       HasDCMPreamble = true;
00644       return Fp;
00645    }
00646 
00647    //-- Broken ACR or DICOM (?) with no Preamble; may start with a Shadow Group --
00648    // FIXME : We cannot be sure the preable is only zeroes..
00649    //         (see ACUSON-24-YBR_FULL-RLE.dcm )
00650    if ( 
00651        zero == 0x0001 || zero == 0x0100 || zero == 0x0002 || zero == 0x0200 ||
00652        zero == 0x0003 || zero == 0x0300 || zero == 0x0004 || zero == 0x0400 ||
00653        zero == 0x0005 || zero == 0x0500 || zero == 0x0006 || zero == 0x0600 ||
00654        zero == 0x0007 || zero == 0x0700 || zero == 0x0008 || zero == 0x0800 ||
00655        zero == 0x0028 || 0x2800    // worse : some ACR-NEMA like files 
00656                                    // start 00028 group ?!?      
00657        )
00658    {
00659       std::string msg = Util::Format(
00660         "ACR/DICOM starting by 0x(%04x) at the beginning of the file\n", zero);
00661       // FIXME : is it a Warning message, or a Debug message?
00662       gdcmWarningMacro( msg.c_str() );
00663       return Fp;
00664    }
00665    
00666    // -- Neither ACR/No Preamble Dicom nor DICOMV3 file
00667    CloseFile();
00668    // Don't user Warning nor Error, not to pollute the output
00669    // while directory recursive parsing ...
00670    gdcmDebugMacro( "Neither ACR/No Preamble Dicom nor DICOMV3 file: "
00671                       << Filename.c_str()); 
00672    return 0;
00673 }
00674 
00679 bool Document::CloseFile()
00680 {
00681    if ( Fp )
00682    {
00683       Fp->close();
00684       delete Fp;
00685       Fp = 0;
00686    }
00687    return true;
00688 }
00689 
00696 void Document::WriteContent(std::ofstream *fp, FileType filetype)
00697 {
00698    // Skip if user wants to write an ACR-NEMA file
00699 
00700    if ( filetype == ImplicitVR || filetype == ExplicitVR ||
00701         filetype == JPEG || filetype == JPEG2000 )
00702    {
00703       // writing Dicom File Preamble
00704       char filePreamble[128];
00705       memset(filePreamble, 0, 128);
00706       fp->write(filePreamble, 128);
00707       fp->write("DICM", 4);
00708    }
00709    /*
00710     * \todo rewrite later, if really usefull
00711     *       - 'Group Length' element is optional in DICOM
00712     *       - but un-updated odd groups lengthes can causes pb
00713     *         (xmedcon breaker)
00714     *
00715     * if ( (filetype == ImplicitVR) || (filetype == ExplicitVR) )
00716     *    UpdateGroupLength(false,filetype);
00717     * if ( filetype == ACR)
00718     *    UpdateGroupLength(true,ACR);
00719     *
00720     * --> Computing group length for groups with embeded Sequences
00721     * --> was too much tricky / we were [in a hurry / too lazy]
00722     * --> We don't write the element 0x0000 (group length)
00723     */
00724 
00725    ElementSet::WriteContent(fp, filetype, false); // This one is recursive
00726 }
00727 
00728 // -----------------------------------------
00729 // Content entries 
00736 void Document::LoadEntryBinArea(uint16_t group, uint16_t elem)
00737 {
00738    // Search the corresponding DocEntry
00739    DocEntry *docEntry = GetDocEntry(group, elem);
00740    if ( !docEntry )
00741    {
00742       gdcmDebugMacro(std::hex << group << "|" << elem 
00743                        <<  " doesn't exist" );
00744       return;
00745    }
00746    DataEntry *dataEntry = dynamic_cast<DataEntry *>(docEntry);
00747    if ( !dataEntry )
00748    {
00749       gdcmWarningMacro(std::hex << group << "|" << elem 
00750                        <<  " is NOT a DataEntry");
00751       return;
00752    }
00753    LoadEntryBinArea(dataEntry);
00754 }
00755 
00761 void Document::LoadEntryBinArea(DataEntry *entry) 
00762 { 
00763    if( entry->GetBinArea() )
00764       return;
00765 
00766    bool openFile = !Fp;
00767    if ( openFile )
00768       OpenFile();
00769 
00770    //size_t o =(size_t)entry->GetOffset();
00771    Fp->seekg((size_t)entry->GetOffset(), std::ios::beg);  // FIXME : for each DataEntry !
00772 
00773    size_t l = entry->GetLength();
00774    uint8_t *data = new uint8_t[l];
00775    if ( !data )
00776    {
00777       gdcmWarningMacro(  "Cannot allocate DataEntry content for : "
00778                        << std::hex << entry->GetGroup() 
00779                        << "|" << entry->GetElement() );
00780       return;
00781    }
00782 
00783    // Read the data
00784    Fp->read((char*)data, l);
00785    if ( Fp->fail() || Fp->eof() )
00786    {
00787       delete[] data;
00788       entry->SetState(DataEntry::STATE_UNREAD);
00789       return;
00790    }
00791 
00792    // Swap the data content if necessary
00793    uint32_t i;
00794    unsigned short vrLgth = 
00795                         Global::GetVR()->GetAtomicElementLength(entry->GetVR());
00796 
00797 // FIXME : trouble expected if we read an ... OW Entry (LUT, etc ..)
00798 //   if( entry->GetVR() == "OW" )
00799 //      vrLgth = 1;
00800 
00801    switch(vrLgth)
00802    {
00803       case 1:
00804       {
00805          break;
00806       }     
00807       case 2:
00808       {
00809          uint16_t *data16 = (uint16_t *)data;
00810          for(i=0;i<l/vrLgth;i++)
00811             data16[i] = SwapShort(data16[i]);
00812          break;
00813       }
00814       case 4:
00815       {
00816          uint32_t *data32 = (uint32_t *)data;
00817          for(i=0;i<l/vrLgth;i++)
00818             data32[i] = SwapLong(data32[i]);
00819          break;
00820       }
00821       case 8:
00822       {
00823          double *data64 = (double *)data;
00824          for(i=0;i<l/vrLgth;i++)
00825             data64[i] = SwapDouble(data64[i]);
00826          break;
00827       }
00828    }
00829    
00830    entry->SetBinArea(data);
00831 
00832    if ( openFile ) // The file is left in the state (open/close) it was at entrance
00833       CloseFile();
00834 }
00835 
00843 //void Document::LoadDocEntrySafe(DocEntry *entry)
00844 //{
00845 //   if ( Fp )
00846 //   {
00847 //      long PositionOnEntry = Fp->tellg();        // LoadDocEntrySafe is not used
00848 //      LoadDocEntry(entry);
00849 //      Fp->seekg(PositionOnEntry, std::ios::beg); // LoadDocEntrySafe is not used
00850 //   }
00851 //}
00852 
00860 bool Document::operator<(Document &document)
00861 {
00862    // Patient Name
00863    std::string s1 = GetEntryString(0x0010,0x0010);
00864    std::string s2 = document.GetEntryString(0x0010,0x0010);
00865    if (s1 < s2)
00866    {
00867       return true;
00868    }
00869    else if ( s1 > s2 )
00870    {
00871       return false;
00872    }
00873    else
00874    {
00875       // Patient ID
00876       s1 = GetEntryString(0x0010,0x0020);
00877       s2 = document.GetEntryString(0x0010,0x0020);
00878       if ( s1 < s2 )
00879       {
00880          return true;
00881       }
00882       else if ( s1 > s2 )
00883       {
00884          return false;
00885       }
00886       else
00887       {
00888          // Study Instance UID
00889          s1 = GetEntryString(0x0020,0x000d);
00890          s2 = document.GetEntryString(0x0020,0x000d);
00891          if ( s1 < s2 )
00892          {
00893             return true;
00894          }
00895          else if ( s1 > s2 )
00896          {
00897             return false;
00898          }
00899          else
00900          {
00901             // Serie Instance UID
00902             s1 = GetEntryString(0x0020,0x000e);
00903             s2 = document.GetEntryString(0x0020,0x000e);    
00904             if ( s1 < s2 )
00905             {
00906                return true;
00907             }
00908             else if ( s1 > s2 )
00909             {
00910                return false;
00911             }
00912          }
00913       }
00914    }
00915    return false;
00916 }
00917 
00918 //-----------------------------------------------------------------------------
00919 // Protected
00920 
00926 void Document::ReadBegBuffer(size_t l)
00927    throw( FormatError )
00928 {   
00929    Fp->read (BegBuffer, (size_t)l);
00930    if ( Fp->fail() )
00931    {
00932       throw FormatError( "Document::ReadBegBuffer()", " file error." );
00933    }
00934    if ( Fp->eof() )
00935    {
00936       throw FormatError( "Document::ReadBegBuffer()", "EOF." );
00937    }
00938    PtrBegBuffer = BegBuffer;
00939    CurrentOffsetPosition+=l;
00940 }
00946 uint16_t Document::ReadInt16()
00947    throw( FormatError )
00948 {
00949    uint16_t g;
00950    Fp->read ((char*)&g, (size_t)2);
00951    if ( Fp->fail() )
00952    {
00953       throw FormatError( "Document::ReadInt16()", " file error." );
00954    }
00955    if ( Fp->eof() )
00956    {
00957       throw FormatError( "Document::ReadInt16()", "EOF." );
00958    }
00959    g = SwapShort(g); 
00960    return g;
00961 }
00962 
00968 uint16_t Document::GetInt16()
00969 {
00970    uint16_t g = *((uint16_t*)PtrBegBuffer);
00971    g = SwapShort(g);
00972    PtrBegBuffer+=2; 
00973    return g;
00974 }
00980 uint32_t Document::ReadInt32()
00981    throw( FormatError )
00982 {
00983    uint32_t g;
00984    Fp->read ((char*)&g, (size_t)4);
00985    if ( Fp->fail() )
00986    {
00987       throw FormatError( "Document::ReadInt32()", " file error." );
00988    }
00989    if ( Fp->eof() )
00990    {
00991       throw FormatError( "Document::ReadInt32()", "EOF." );
00992    }
00993    g = SwapLong(g);
00994    return g;
00995 }
00996 
01002 uint32_t Document::GetInt32()
01003 {
01004    uint32_t g = *((uint32_t*)PtrBegBuffer);
01005    g = SwapLong(g); 
01006    PtrBegBuffer+=4;
01007    return g;
01008 }
01009 
01013 int Document::ComputeGroup0002Length( ) 
01014 {
01015    uint16_t gr;
01016    VRKey vr;
01017    
01018    int groupLength = 0;
01019    bool found0002 = false;   
01020   
01021    // for each zero-level Tag in the DCM Header
01022    DocEntry *entry = GetFirstEntry();
01023    while( entry )
01024    {
01025       gr = entry->GetGroup();
01026 
01027       if ( gr == 0x0002 )
01028       {
01029          found0002 = true;
01030 
01031          if ( entry->GetElement() != 0x0000 )
01032          {
01033             vr = entry->GetVR();
01034 
01035             //if ( (vr == "OB")||(vr == "OW")||(vr == "UT")||(vr == "SQ"))
01036             // (no SQ, OW, UT in group 0x0002;)
01037                if ( vr == "OB" ) 
01038                {
01039                   // explicit VR AND (OB, OW, SQ, UT) : 4 more bytes
01040                   groupLength +=  4;
01041                }
01042             groupLength += 2 + 2 + 4 + entry->GetLength();   
01043          }
01044       }
01045       else if (found0002 )
01046          break;
01047 
01048       entry = GetNextEntry();
01049    }
01050    return groupLength; 
01051 }
01052 
01056 void Document::CallStartMethod()
01057 {
01058    Progress = 0.0f;
01059    Abort    = false;
01060    CommandManager::ExecuteCommand(this,CMD_STARTPROGRESS);
01061 }
01062 
01066 void Document::CallProgressMethod()
01067 {
01068    CommandManager::ExecuteCommand(this,CMD_PROGRESS);
01069 }
01070 
01074 void Document::CallEndMethod()
01075 {
01076    Progress = 1.0f;
01077    CommandManager::ExecuteCommand(this,CMD_ENDPROGRESS);
01078 }
01079 
01080 //-----------------------------------------------------------------------------
01081 // Private
01086 void Document::Initialize() 
01087 {
01088    RefPubDict = Global::GetDicts()->GetDefaultPubDict();
01089    RefShaDict = NULL;
01090    Filetype   = Unknown;
01091 }
01092 
01100 void Document::ParseDES(DocEntrySet *set, long offset, 
01101                         long l_max, bool delim_mode)
01102 {
01103    DocEntry *newDocEntry;
01104    DataEntry *newDataEntry;
01105    SeqEntry *newSeqEntry;
01106    //VRKey vr;
01107    bool used; // will be set to false when something wrong happens to an Entry.
01108               // (Entry will then be deleted)
01109    bool delim_mode_intern = delim_mode;
01110    bool first = true;
01111    gdcmDebugMacro( "Enter in ParseDES, delim-mode " <<  delim_mode
01112                      << " at offset " << std::hex << "0x(" << offset << ")" );    
01113    while (true)
01114    {
01115    
01118 
01119 // Uncomment to track the bug
01120 /*   
01121    if( Debug::GetDebugFlag() )   
01122       std::cout << std::dec <<"(long)(Fp->tellg()) " << (long)(Fp->tellg()) // in Debug mode
01123                 << std::hex << " 0x(" <<(long)(Fp->tellg()) <<  ")" << std::endl;
01124  */ 
01125  
01126    // if ( !delim_mode && ((long)(Fp->tellg())-offset) >= l_max) // Once per DocEntry   
01127       if ( !delim_mode ) // 'and then' doesn't exist in C++ :-(
01128          if ( ((long)(Fp->tellg())-offset) >= l_max) // Once per DocEntry, when no delim mode
01129          {
01130             break;
01131          }
01132 
01133       newDocEntry = ReadNextDocEntry( );
01134 
01135       if ( !newDocEntry )
01136       {
01137          break;
01138       }
01139       
01140       // Uncoment this cerr line to be able to 'follow' the DocEntries
01141       // when something *very* strange happens
01142       if( Debug::GetDebugFlag() ) 
01143          std::cerr<<newDocEntry->GetKey()<<" "<<newDocEntry->GetVR()<<std::endl;
01144 
01145        // an Item Starter found elsewhere but in the first position
01146        // of a SeqEntry means previous entry was a Sequence
01147        // but we didn't get it (private Sequence + Implicit VR)
01148        // we have to backtrack.
01149       if ( !first && newDocEntry->IsItemStarter() )
01150       {
01151          // Debug message within the method !
01152          newDocEntry = Backtrack(newDocEntry);
01153       }
01154       else
01155       { 
01156          PreviousDocEntry = newDocEntry; 
01157       }
01158  
01159       used = true;
01160       newDataEntry = dynamic_cast<DataEntry*>(newDocEntry);
01161 
01162       if ( newDataEntry )  
01163       {
01165  
01166          //vr = newDocEntry->GetVR(); // useless ?
01167 
01168          if ( !set->AddEntry( newDataEntry ) )
01169          {
01170             gdcmDebugMacro( "in ParseDES : cannot add a DataEntry "
01171                                  << newDataEntry->GetKey()
01172                                  << " (at offset : 0x(" 
01173                                  << newDataEntry->GetOffset() << ") )" );
01174             used=false;
01175          }
01176          else
01177          {
01178             newDataEntry->Delete();
01179             // Load only if we can add (not a duplicate key)
01180             LoadDocEntry( newDataEntry );
01181          }
01182          if ( newDataEntry->GetElement() == 0x0000 ) // if on group length
01183          {
01184             if ( newDataEntry->GetGroup()%2 != 0 )   // if Shadow Group
01185             {
01186                if ( LoadMode & LD_NOSHADOW ) // if user asked to skip shad.gr
01187                {
01188                   std::string strLgrGroup = newDataEntry->GetString();
01189 
01190                   int lgrGroup;
01191                   //if ( newDataEntry->IsUnfound() ) /?!? JPR
01192                   {
01193                      lgrGroup = atoi(strLgrGroup.c_str());
01194                      Fp->seekg(lgrGroup, std::ios::cur); // Once per Shadow group, when NOSHADOW
01195                      RemoveEntry( newDocEntry );  // Remove and delete
01196                      continue;
01197                   }
01198                }
01199             }
01200          }
01201 
01202          bool delimitor = newDataEntry->IsItemDelimitor(); 
01203          bool outOfBounds = false;
01204          if (!delim_mode )
01205             if ( ((long)(Fp->tellg())-offset) >= l_max ) //Once per DataEntry when no delim mode
01206                outOfBounds = true;
01207 
01208   //       'and then', 'or else' don't exist in C++ :-(
01209   //       if ( (delimitor) || 
01210   //             (!delim_mode && ((long)(Fp->tellg())-offset) >= l_max) ) // Once per DataEntry
01211 
01212          if ( delimitor || outOfBounds )
01213          {
01214             if ( !used )
01215                newDocEntry->Delete();
01216             break;
01217          }
01218 
01219          // Just to make sure we are at the beginning of next entry.
01220          SkipToNextDocEntry(newDocEntry); // FIXME : once per DocEntry, segfault if commented out
01221       }
01222       else
01223       {
01225 
01226          unsigned long l = newDocEntry->GetReadLength();          
01227          if ( l != 0 ) // don't mess the delim_mode for 'zero-length sequence'
01228          {
01229             if ( l == 0xffffffff )
01230             {
01231               delim_mode_intern = true;
01232             }
01233             else
01234             {
01235               delim_mode_intern = false;
01236             }
01237          }
01238 
01239          if ( (LoadMode & LD_NOSHADOWSEQ) && ! delim_mode_intern )
01240          { 
01241            // User asked to skip SeQuences *only* if they belong to Shadow Group
01242             if ( newDocEntry->GetGroup()%2 != 0 )
01243             {
01244                 Fp->seekg( l, std::ios::cur);  // once per SQITEM, when NOSHADOWSEQ
01245                 newDocEntry->Delete();  // Delete, not in the set 
01246                 continue;  
01247             } 
01248          } 
01249          if ( (LoadMode & LD_NOSEQ) && ! delim_mode_intern ) 
01250          {
01251            // User asked to skip *any* SeQuence
01252             Fp->seekg( l, std::ios::cur); // Once per SQ, when NOSEQ
01253             newDocEntry->Delete(); // Delete, not in the set
01254             continue;
01255          }
01256          // delay the dynamic cast as late as possible
01257          newSeqEntry = dynamic_cast<SeqEntry*>(newDocEntry);
01258          
01259          // no other way to create the Delimitor ...
01260          newSeqEntry->SetDelimitorMode( delim_mode_intern );
01261 
01262          // At the top of the hierarchy, stands a Document. When "set"
01263          // is a Document, then we are building the first depth level.
01264          // Hence the SeqEntry we are building simply has a depth
01265          // level of one:
01266         if ( set == this ) // ( dynamic_cast< Document* > ( set ) )
01267          {
01268             newSeqEntry->SetDepthLevel( 1 );
01269          }
01270          // But when "set" is already a SQItem, we are building a nested
01271          // sequence, and hence the depth level of the new SeqEntry
01272          // we are building, is one level deeper:
01273 
01274          // time waste hunting
01275          else if (SQItem *parentSQItem = dynamic_cast< SQItem* > ( set ) )
01276          {
01277             newSeqEntry->SetDepthLevel( parentSQItem->GetDepthLevel() + 1 );
01278          }
01279 
01280          if ( l != 0 )
01281          {  // Don't try to parse zero-length sequences
01282 
01283             gdcmDebugMacro( "Entry in ParseSQ, delim " << delim_mode_intern
01284                                << " at offset 0x(" << std::hex
01285                                << newDocEntry->GetOffset() << ")");
01286 
01287             bool res = ParseSQ( newSeqEntry, 
01288                          newDocEntry->GetOffset(),
01289                          l, delim_mode_intern);
01290 
01291             gdcmDebugMacro( "Exit from ParseSQ, delim " << delim_mode_intern << " -->return : " << res);
01292          }
01293          if ( !set->AddEntry( newSeqEntry ) )
01294          {
01295             gdcmWarningMacro( "in ParseDES : cannot add a SeqEntry "
01296                                 << newSeqEntry->GetKey()
01297                                 << " (at offset : 0x(" 
01298                                 << newSeqEntry->GetOffset() << ") )" ); 
01299             used = false;
01300          }
01301          else
01302          {
01303             newDocEntry->Delete();
01304          }
01305 
01306       // if ( !delim_mode && ((long)(Fp->tellg())-offset) >= l_max) // Once per SeqEntry
01307  
01308          if ( !delim_mode ) // 'and then' doesn't exist in C++ :-(
01309             if ( ((long)(Fp->tellg())-offset) >= l_max) // Once per SeqEntry when no delim mode
01310      
01311          {
01312             if ( !used )
01313                newDocEntry->Delete();
01314             break;
01315          }
01316       }  // end SeqEntry : VR = "SQ"
01317 
01318       if ( !used )
01319       {
01320          newDocEntry->Delete();
01321       }
01322       first = false;
01323       
01324       if (UnexpectedEOF) // some terminator was missing
01325          break;
01326    }                               // end While
01327    gdcmDebugMacro( "Exit from ParseDES, delim-mode " << delim_mode );
01328 }
01329 
01334 bool Document::ParseSQ( SeqEntry *seqEntry,
01335                         long offset, long l_max, bool delim_mode)
01336 {
01337    int SQItemNumber = 0;
01338    bool dlm_mod;
01339    long offsetStartCurrentSQItem = offset;
01340 
01341    while (true)
01342    {
01343       // the first time, we read the fff0,e000 of the first SQItem
01344       DocEntry *newDocEntry = ReadNextDocEntry();
01345 
01346       if ( !newDocEntry )
01347       { 
01348          // The most frequent is when a SQ terminator is missing (?!?)
01349          gdcmWarningMacro("in ParseSQ : should never get here!");
01350          UnexpectedEOF = true;
01351          return false;
01352       }
01353       if ( delim_mode )
01354       {
01355          if ( newDocEntry->IsSequenceDelimitor() )
01356          {
01357             seqEntry->SetDelimitationItem( newDocEntry ); 
01358             newDocEntry->Delete();
01359             break;
01360          }
01361       }
01362       else // ! delim_mode
01363       {
01364          if ( ((long)(Fp->tellg())-offset) >= l_max) // Once per SQItem when no delim mode
01365          {
01366             newDocEntry->Delete();
01367             break;
01368          }
01369       }
01370       // create the current SQItem
01371       SQItem *itemSQ = SQItem::New( seqEntry->GetDepthLevel() );
01372       unsigned int l = newDocEntry->GetReadLength();
01373       
01374       if ( l == 0xffffffff )
01375       {
01376          dlm_mod = true;
01377       }
01378       else
01379       {
01380          dlm_mod = false;
01381       }
01382             
01383       // fill up the current SQItem, starting at the beginning of fff0,e000
01384       
01385       Fp->seekg(offsetStartCurrentSQItem, std::ios::beg);        // Once per SQItem
01386       ParseDES(itemSQ, offsetStartCurrentSQItem, l+8, dlm_mod);
01387       offsetStartCurrentSQItem = Fp->tellg();                    // Once per SQItem
01388  
01389       seqEntry->AddSQItem( itemSQ, SQItemNumber ); 
01390       itemSQ->Delete();
01391       newDocEntry->Delete();
01392       SQItemNumber++;
01393       //if ( !delim_mode && ((long)(Fp->tellg())-offset ) >= l_max ) //JPRx
01394       if ( !delim_mode && (offsetStartCurrentSQItem-offset ) >= l_max )
01395       {
01396          break;
01397       }
01398    }
01399    return true;
01400 }
01401 
01408 DocEntry *Document::Backtrack(DocEntry *docEntry)
01409 {
01410    // delete the Item Starter, built erroneously out of any Sequence
01411    // it's not yet in the HTable/chained list
01412    docEntry->Delete();
01413 
01414    // Get all info we can from PreviousDocEntry
01415    uint16_t group = PreviousDocEntry->GetGroup();
01416    uint16_t elem  = PreviousDocEntry->GetElement();
01417    uint32_t lgt   = PreviousDocEntry->GetLength();
01418    long offset    = PreviousDocEntry->GetOffset();
01419 
01420    gdcmDebugMacro( "Backtrack :" << std::hex << group 
01421                                  << "|" << elem
01422                                  << " at offset 0x(" <<offset << ")" );
01423    RemoveEntry( PreviousDocEntry );
01424 
01425    // forge the Seq Entry
01426    DocEntry *newEntry = NewSeqEntry(group, elem);
01427    newEntry->SetLength(lgt);
01428    newEntry->SetOffset(offset);
01429 
01430    // Move back to the beginning of the Sequence
01431 
01432    Fp->seekg(offset, std::ios::beg); // Only for Shadow Implicit VR SQ
01433    return newEntry;
01434 }
01435 
01442 void Document::LoadDocEntry(DocEntry *entry, bool forceLoad)
01443 {
01444    uint16_t group   = entry->GetGroup();
01445    uint16_t elem    = entry->GetElement();
01446    const VRKey  &vr = entry->GetVR();
01447    uint32_t length  = entry->GetLength();
01448 
01449  //  Fp->seekg((long)entry->GetOffset(), std::ios::beg); // JPRx
01450 
01451    // A SeQuence "contains" a set of Elements.  
01452    //          (fffe e000) tells us an Element is beginning
01453    //          (fffe e00d) tells us an Element just ended
01454    //          (fffe e0dd) tells us the current SeQuence just ended
01455    //          (fffe 0000) is an 'impossible' tag value, 
01456    //                                    found in MR-PHILIPS-16-Multi-Seq.dcm
01457    
01458    if ( (group == 0xfffe && elem != 0x0000 ) || vr == "SQ" )
01459    {
01460       // NO more value field for SQ !
01461       return;
01462    }
01463 
01464    DataEntry *dataEntryPtr = dynamic_cast< DataEntry* >(entry);
01465    if( !dataEntryPtr )
01466    {
01467       return;
01468    }
01469 
01470    // When the length is zero things are easy:
01471    if ( length == 0 )
01472    {
01473       dataEntryPtr->SetBinArea(NULL,true);
01474       return;
01475    }
01476 
01477    // The elements whose length is bigger than the specified upper bound
01478    // are not loaded.
01479 
01480    if (!forceLoad)
01481    {
01482       if (length > MaxSizeLoadEntry)
01483       {
01484          dataEntryPtr->SetBinArea(NULL,true);
01485          dataEntryPtr->SetState(DataEntry::STATE_NOTLOADED);
01486 
01487        // to be sure we are at the end of the value ...
01488        //  Fp->seekg((long)entry->GetOffset()+(long)entry->GetLength(),
01489        //           std::ios::beg);  //JPRx
01490          return;
01491       }
01492    }
01493    
01500    
01501    LoadEntryBinArea(dataEntryPtr); // last one, not to erase length !
01502 }
01503 
01508 void Document::FindDocEntryLength( DocEntry *entry )
01509    throw ( FormatError )
01510 {
01511    const VRKey &vr  = entry->GetVR();
01512    uint16_t length16;       
01513    if ( Filetype == ExplicitVR && !entry->IsImplicitVR() ) 
01514    {
01515    
01516    // WARNING :
01517    //
01518    // For some images, length of UN elements is coded on 2 bytes (instead of 4)
01519    // There are *not* readable !
01520    // You can make a quick and dirty patch, commenting out 
01521    //| vr == "UN"
01522    // in the following line.
01523    // (the 'straight' images will no longer be readable ...)
01524    
01525       if ( vr == "OB" || vr == "OW" || vr == "SQ" || vr == "UT" 
01526                                                           || vr == "UN" || changeFromUN == true)
01527       {
01528          changeFromUN = false;
01529          // The following reserved two bytes (see PS 3.5-2003, section
01530          // "7.1.2 Data element structure with explicit vr", p 27) must be
01531          // skipped before proceeding on reading the length on 4 bytes.
01532 
01533          //Fp->seekg( 2L, std::ios::cur); // Once per OW,OB,SQ DocEntry
01534          uint32_t length32 = ReadInt32(); // Once per OW,OB,SQ DocEntry
01535          CurrentOffsetPosition+=4;
01536          if ( (vr == "OB" || vr == "OW") && length32 == 0xffffffff ) 
01537          {
01538             uint32_t lengthOB;
01539             try 
01540             {
01541                lengthOB = FindDocEntryLengthOBOrOW();// for encapsulation of encoded pixel 
01542             }
01543             catch ( FormatUnexpected )
01544             {
01545                // Computing the length failed (this happens with broken
01546                // files like gdcm-JPEG-LossLess3a.dcm). We still have a
01547                // chance to get the pixels by deciding the element goes
01548                // until the end of the file. Hence we artificially fix the
01549                // the length and proceed.
01550                gdcmWarningMacro( " Computing the length failed for " << 
01551                                    entry->GetKey() <<" in " <<GetFileName());
01552 
01553                long currentPosition = Fp->tellg(); // Only for gdcm-JPEG-LossLess3a.dcm-like
01554                Fp->seekg(0L,std::ios::end);        // Only for gdcm-JPEG-LossLess3a.dcm-like
01555 
01556                long lengthUntilEOF = (long)(Fp->tellg())-currentPosition; // Only for gdcm-JPEG-LossLess3a.dcm-like
01557                Fp->seekg(currentPosition, std::ios::beg);                 // Only for gdcm-JPEG-LossLess3a.dcm-like
01558 
01559                entry->SetReadLength(lengthUntilEOF);
01560                entry->SetLength(lengthUntilEOF);
01561                return;
01562             }
01563             entry->SetReadLength(lengthOB);
01564             entry->SetLength(lengthOB);
01565             return;
01566          }
01567          FixDocEntryFoundLength(entry, length32); 
01568          return;
01569       }
01570       // Length is encoded on 2 bytes.
01571       //length16 = ReadInt16();
01572       length16 = GetInt16();
01573       // 0xffff means that we deal with 'No Length' Sequence 
01574       //        or 'No Length' SQItem
01575       if ( length16 == 0xffff) 
01576       {           
01577          length16 = 0;
01578       }
01579       FixDocEntryFoundLength( entry, (uint32_t)length16 );
01580       return;
01581    }
01582    else
01583    {
01584       // Either implicit VR or a non DICOM conformal (see note below) explicit
01585       // VR that ommited the VR of (at least) this element. Farts happen.
01586       // [Note: according to the part 5, PS 3.5-2001, section 7.1 p25
01587       // on Data elements "Implicit and Explicit VR Data Elements shall
01588       // not coexist in a Data Set and Data Sets nested within it".]
01589       // Length is on 4 bytes.
01590 
01591      // Well ... group 0002 is always coded in 'Explicit VR Litle Endian'
01592      // even if Transfer Syntax is 'Implicit VR ...'
01593      // --> Except for 'Implicit VR Big Endian Transfer Syntax GE Private' 
01594      //     where Group 0x0002 is *also* encoded in Implicit VR !
01595 
01596       FixDocEntryFoundLength( entry, GetInt32() /*ReadInt32()*/ );
01597       return;
01598    }
01599 }
01600 
01606 uint32_t Document::FindDocEntryLengthOBOrOW()
01607    throw( FormatUnexpected )
01608 {
01609    // See PS 3.5-2001, section A.4 p. 49 on encapsulation of encoded pixel data.
01610    
01611    long positionOnEntry = Fp->tellg(); // Only for OB,OW DataElements
01612 
01613    bool foundSequenceDelimiter = false;
01614    uint32_t totalLength = 0;
01615 
01616    while ( !foundSequenceDelimiter )
01617    {
01618       uint16_t group;
01619       uint16_t elem;
01620 
01621       try
01622       {
01623          //group = ReadInt16(); // Once per fragment (if any) of OB,OW DataElements
01624          //elem  = ReadInt16(); // Once per fragment (if any) of OB,OW DataElements 
01625          ReadBegBuffer(4); // Once per fragment (if any) of OB,OW DataElements
01626       }
01627       catch ( FormatError )
01628       {
01629          throw FormatError("Unexpected end of file encountered during ",
01630                            "Document::FindDocEntryLengthOBOrOW()");
01631       }
01632       group = GetInt16();
01633       elem  = GetInt16();
01634 
01635       // We have to decount the group and element we just read
01636       totalLength += 4;     
01637       if ( group != 0xfffe || ( ( elem != 0xe0dd ) && ( elem != 0xe000 ) ) )
01638       {
01639          gdcmWarningMacro( 
01640               "Neither an Item tag nor a Sequence delimiter tag on :" 
01641            << std::hex << group << " , " << elem 
01642            << ")" );
01643   
01644          Fp->seekg(positionOnEntry, std::ios::beg); // Once per fragment (if any) of OB,OW DataElements
01645          throw FormatUnexpected( 
01646                "Neither an Item tag nor a Sequence delimiter tag.");
01647       }
01648       if ( elem == 0xe0dd )
01649       {
01650          foundSequenceDelimiter = true;
01651       }
01652       uint32_t itemLength = ReadInt32(); // Once per fragment (if any) of OB,OW DataElements
01653       // We add 4 bytes since we just read the ItemLength with ReadInt32
01654       totalLength += itemLength + 4;
01655       SkipBytes(itemLength);
01656       
01657       if ( foundSequenceDelimiter )
01658       {
01659          break;
01660       }
01661    }
01662    Fp->seekg( positionOnEntry, std::ios::beg); // Only once for OB,OW DataElements
01663    return totalLength;
01664 }
01665 
01670 VRKey Document::FindDocEntryVR()
01671 {
01672    if ( Filetype != ExplicitVR )
01673    {
01674       return GDCM_VRUNKNOWN;
01675    }
01676 
01677    // Delimiters (0xfffe), are not explicit VR ... 
01678    if ( CurrentGroup == 0xfffe )
01679       return GDCM_VRUNKNOWN;
01680          
01681    //long positionOnEntry;     
01682    //if( Debug::GetWarningFlag() ) 
01683    //  positionOnEntry = Fp->tellg(); // Only in Warning Mode
01684    
01685    // Warning: we believe this is explicit VR (Value Representation) because
01686    // we used a heuristic that found "UL" in the first tag and/or
01687    // 'Transfer Syntax' told us it is.
01688    // Alas this doesn't guarantee that all the tags will be in explicit VR. 
01689    // In some cases one finds implicit VR tags mixed within an explicit VR file
01690    // Well...
01691    // 'Normaly' the only case is : group 0002 Explicit, and other groups Implicit
01692    //
01693    // Hence we make sure the present tag is in explicit VR and try to fix things
01694    // if it happens not to be the case.
01695 
01696    VRKey vr;
01697    //Fp->read(&(vr[0]),(size_t)2);
01698    vr[0] = *PtrBegBuffer++;
01699    vr[1] = *PtrBegBuffer++;
01700    
01701    //if ( !CheckDocEntryVR(vr) ) // avoid useless function call
01702    if ( !Global::GetVR()->IsValidVR(vr) )
01703    {
01704 /*   
01705 //      std::cout << "================================================================Unknown VR" 
01706                << std::hex << "0x(" 
01707                         << (unsigned int)vr[0] << "|" << (unsigned int)vr[1] 
01708                         << ")" << "for : " <<  CurrentGroup
01709                         << " at offset : 0x(" << positionOnEntry << ")"
01710                         << std::endl;
01711 */
01712       gdcmWarningMacro( "Unknown VR " << std::hex << "0x(" 
01713                         << (unsigned int)vr[0] << "|" << (unsigned int)vr[1] 
01714                         << ")"  
01715                         << " at offset : 0x(" << CurrentOffsetPosition-4<< ") for group " << CurrentGroup
01716                         );
01717 
01718       //Fp->seekg(positionOnEntry, std::ios::beg); //JPRx
01719       //Fp->seekg((long)-2, std::ios::cur);// only for unrecognized VR (?!?) 
01720                                          //see :MR_Philips_Intera_PrivateSequenceExplicitVR.dcm
01721       PtrBegBuffer-=2;
01722       return GDCM_VRUNKNOWN;
01723    }
01724    return vr;
01725 }
01726 
01735 bool Document::CheckDocEntryVR(const VRKey &vr)
01736 {
01737    return Global::GetVR()->IsValidVR(vr);
01738 }
01739 
01744 void Document::SkipDocEntry(DocEntry *entry) 
01745 {
01746    SkipBytes(entry->GetLength());
01747 }
01748 
01753 void Document::SkipToNextDocEntry(DocEntry *currentDocEntry) 
01754 {
01755    long l = currentDocEntry->GetReadLength();
01756    if ( l == -1 ) // length = 0xffff shouldn't appear here ...
01757                   // ... but PMS imagers happen !
01758       return;
01759    Fp->seekg((size_t)(currentDocEntry->GetOffset()), std::ios::beg); //FIXME :each DocEntry
01760    if (currentDocEntry->GetGroup() != 0xfffe)  // for fffe pb
01761    {
01762       Fp->seekg( l,std::ios::cur);                                 //FIXME :each DocEntry
01763    }
01764 }
01765 
01773 void Document::FixDocEntryFoundLength(DocEntry *entry,
01774                                       uint32_t foundLength)
01775 {
01776    entry->SetReadLength( foundLength );// will be updated only if a bug is found
01777    
01778    if ( foundLength == 0xffffffff)
01779    {
01780       //foundLength = 0;
01781       //entry->SetLength(foundLength);
01782       entry->SetLength(0);
01783       return;  // return ASAP; don't waist time on useless tests
01784    }
01785       
01786    uint16_t gr   = entry->GetGroup();
01787    uint16_t elem = entry->GetElement(); 
01788      
01789    if ( foundLength % 2)
01790    {
01791       gdcmWarningMacro( "Warning : Tag with uneven length " << foundLength
01792         <<  " in x(" << std::hex << gr << "," << elem <<")");
01793    }
01794       
01796    // Allthough not recent many such GE corrupted images are still present
01797    // on Creatis hard disks. Hence this fix shall remain when such images
01798    // are no longer in use (we are talking a few years, here)...
01799    // Note: XMedCon probably uses such a trick since it is able to read
01800    //       those pesky GE images ...
01801    if ( foundLength == 13)
01802    {
01803       // Only happens for this length !
01804       if ( gr != 0x0008 || ( elem != 0x0070 && elem != 0x0080 ) )
01805       {
01806          foundLength = 10;
01807          entry->SetReadLength(10); // a bug is to be fixed !?
01808       }
01809    }
01810 
01812    // Occurence of such images is quite low (unless one leaves close to a
01813    // 'Leonardo' source. Hence, one might consider commenting out the
01814    // following fix on efficiency reasons.
01815    else if ( gr == 0x0009 && ( elem == 0x1113 || elem == 0x1114 ) )
01816    { 
01817    // Ideally we should check we are in Explicit and double check
01818    // that VR=UL... this is done properly in gdcm2
01819       if( foundLength == 6 )
01820       {
01821          gdcmWarningMacro( "Replacing Length from 6 into 4" );
01822          foundLength = 4;
01823          entry->SetReadLength(4); // a bug is to be fixed !
01824       } 
01825       else if ( foundLength%4 )
01826       {
01827         gdcmErrorMacro( "This looks like to a buggy Siemens DICOM file."
01828         "The length of this tag seems to be wrong" );
01829       }
01830    }
01831 
01832    else if ( entry->GetVR() == "SQ" )
01833    {
01834       foundLength = 0;      // ReadLength is unchanged
01835    }
01836 
01838    // "fffe|xxxx" which is just a marker. Delimiters length should not be
01839    // taken into account.
01840    else if ( gr == 0xfffe )
01841    {
01842      // According to the norm, fffe|0000 shouldn't exist. BUT the Philips
01843      // image gdcmData/gdcm-MR-PHILIPS-16-Multi-Seq.dcm happens to
01844      // causes extra troubles...
01845      if ( elem != 0x0000 )
01846      {
01847         foundLength = 0;
01848      }
01849      else
01850      {
01851         foundLength=12; // to skip the mess that follows this bugged Tag !
01852      }
01853    }
01854    entry->SetLength(foundLength);
01855 }
01856 
01863 bool Document::IsDocEntryAnInteger(DocEntry *entry)
01864 {
01865    uint16_t elem         = entry->GetElement();
01866    uint16_t group        = entry->GetGroup();
01867    const VRKey &vr       = entry->GetVR();
01868    uint32_t length       = entry->GetLength();
01869 
01870    // When we have some semantics on the element we just read, and if we
01871    // a priori know we are dealing with an integer, then we shall be
01872    // able to swap its element value properly.
01873    if ( elem == 0 )  // This is the group length of the group
01874    {  
01875       if ( length == 4 )
01876       {
01877          return true;
01878       }
01879       else 
01880       {
01881          // Although this should never happen, still some images have a
01882          // corrupted group length [e.g. have a glance at offset x(8336) of
01883          // gdcmData/gdcm-MR-PHILIPS-16-Multi-Seq.dcm.
01884          // Since for dicom compliant and well behaved headers, the present
01885          // test is useless (and might even look a bit paranoid), when we
01886          // encounter such an ill-formed image, we simply display a warning
01887          // message and proceed on parsing (while crossing fingers).
01888          long filePosition = Fp->tellg(); // Only when elem 0x0000 length is not 4 (?!?)
01889          (void)filePosition;
01890          gdcmWarningMacro( "Erroneous Group Length element length  on : (" 
01891            << std::hex << group << " , " << elem
01892            << ") -before- position x(" << filePosition << ")"
01893            << "lgt : " << length );
01894       }
01895    }
01896 
01897    if ( vr == "UL" || vr == "US" || vr == "SL" || vr == "SS" )
01898    {
01899       return true;
01900    }   
01901    return false;
01902 }
01903 
01912 bool Document::CheckSwap()
01913 {   
01914    uint32_t  s32;
01915    uint16_t  s16;
01916        
01917    char deb[256];
01918     
01919    // First, compare HostByteOrder and NetworkByteOrder in order to
01920    // determine if we shall need to swap bytes (i.e. the Endian type).
01921    bool net2host = Util::IsCurrentProcessorBigEndian();
01922          
01923    // The easiest case is the one of a 'true' DICOM header, we just have
01924    // to look for the string "DICM" inside the file preamble.
01925    Fp->read(deb, 256);
01926    
01927    char *entCur = deb + 128;
01928    if ( memcmp(entCur, "DICM", (size_t)4) == 0 )
01929    {
01930       gdcmDebugMacro( "Looks like DICOM Version3 (preamble + DCM)" );
01931       
01932       // Group 0002 should always be VR, and the first element 0000
01933       // Let's be carefull (so many wrong headers ...)
01934       // and determine the value representation (VR) : 
01935       // Let's skip to the first element (0002,0000) and check there if we find
01936       // "UL"  - or "OB" if the 1st one is (0002,0001) -,
01937       // in which case we (almost) know it is explicit VR.
01938       // WARNING: if it happens to be implicit VR then what we will read
01939       // is the length of the group. If this ascii representation of this
01940       // length happens to be "UL" then we shall believe it is explicit VR.
01941       // We need to skip :
01942       // * the 128 bytes of File Preamble (often padded with zeroes),
01943       // * the 4 bytes of "DICM" string,
01944       // * the 4 bytes of the first tag (0002, 0000),or (0002, 0001)
01945       // i.e. a total of  136 bytes.
01946       entCur = deb + 136;
01947      
01948       // group 0x0002 *is always* Explicit VR Sometimes,
01949       // even if elem 0002,0010 (Transfer Syntax) tells us the file is
01950       // *Implicit* VR  (see former 'gdcmData/icone.dcm')
01951       
01952       if ( memcmp(entCur, "UL", (size_t)2) == 0 ||
01953            memcmp(entCur, "OB", (size_t)2) == 0 ||
01954            memcmp(entCur, "UI", (size_t)2) == 0 ||
01955            memcmp(entCur, "CS", (size_t)2) == 0 )  // CS, to remove later
01956                                                    // when Write DCM *adds*
01957       // FIXME
01958       // Use Document::dicom_vr to test all the possibilities
01959       // instead of just checking for UL, OB and UI !? group 0000 
01960       {
01961          Filetype = ExplicitVR;
01962          gdcmDebugMacro( "Group 0002 : Explicit Value Representation");
01963       } 
01964       else 
01965       {
01966          Filetype = ImplicitVR;
01967          gdcmWarningMacro( "Group 0002 :Not an explicit Value Representation;"
01968                         << "Looks like a bugged Header!");
01969       }
01970       
01971       // Here, we assume that the file IS kosher Dicom !
01972       // (The meta elements - group 0x0002 - ARE little endian !)
01973       if ( net2host )
01974       {
01975          SwapCode = 4321;
01976          gdcmDebugMacro( "HostByteOrder != NetworkByteOrder, SwapCode = 4321");
01977       }
01978       else 
01979       {
01980          SwapCode = 1234;
01981          gdcmDebugMacro( "HostByteOrder = NetworkByteOrder, SwapCode = 1234");
01982       }
01983       
01984       // Position the file position indicator at first tag 
01985       // (i.e. after the file preamble and the "DICM" string).
01986 
01987       Fp->seekg ( 132L, std::ios::beg); // Once per Document
01988       CurrentOffsetPosition = 132;
01989       return true;
01990    } // ------------------------------- End of DicomV3 ----------------
01991 
01992    // Alas, this is not a DicomV3 file and whatever happens there is no file
01993    // preamble. We can reset the file position indicator to where the data
01994    // is (i.e. the beginning of the file).
01995 
01996    gdcmWarningMacro( "Not a Kosher DICOM Version3 file (no preamble)");
01997 
01998    Fp->seekg(0, std::ios::beg); // Once per ACR-NEMA Document
01999    CurrentOffsetPosition = 0;
02000    // Let's check 'No Preamble Dicom File' :
02001    // Should start with group 0x0002
02002    // and be Explicit Value Representation
02003 
02004    s16 = *((uint16_t *)(deb));
02005    SwapCode = 0;     
02006    switch ( s16 )
02007    {
02008       case 0x0002 :
02009          SwapCode = 1234;
02010          entCur = deb + 4;
02011          break;
02012       case 0x0200 :
02013          SwapCode = 4321;
02014          entCur = deb + 6;
02015     } 
02016 
02017    if ( SwapCode != 0 )
02018    {
02019       if ( memcmp(entCur, "UL", (size_t)2) == 0 ||
02020            memcmp(entCur, "OB", (size_t)2) == 0 ||
02021            memcmp(entCur, "UI", (size_t)2) == 0 ||
02022            memcmp(entCur, "SH", (size_t)2) == 0 ||
02023            memcmp(entCur, "AE", (size_t)2) == 0 ||
02024            memcmp(entCur, "OB", (size_t)2) == 0 )
02025          {
02026             Filetype = ExplicitVR;  // FIXME : not enough to say it's Explicit
02027                                     // Wait untill reading Transfer Syntax
02028             gdcmDebugMacro( "Group 0002 : Explicit Value Representation");
02029             return true;
02030           }
02031     }
02032 // ------------------------------- End of 'No Preamble' DicomV3 -------------
02033 
02034    // Our next best chance would be to be considering a 'clean' ACR/NEMA file.
02035    // By clean we mean that the length of the first group is written down.
02036    // If this is the case and since the length of the first group HAS to be
02037    // four (bytes), then determining the proper swap code is straightforward.
02038 
02039    entCur = deb + 4;
02040    // We assume the array of char we are considering contains the binary
02041    // representation of a 32 bits integer. Hence the following dirty
02042    // trick :
02043    s32 = *((uint32_t *)(entCur));
02044    switch( s32 )
02045    {
02046       case 0x00040000 :
02047          SwapCode = 3412;
02048          Filetype = ACR;
02049          return true;
02050       case 0x04000000 :
02051          SwapCode = 4321;
02052          Filetype = ACR;
02053          return true;
02054       case 0x00000400 :
02055          SwapCode = 2143;
02056          Filetype = ACR;
02057          return true;
02058       case 0x00000004 :
02059          SwapCode = 1234;
02060          Filetype = ACR;
02061          return true;
02062       default :
02063          // We are out of luck. It is not a DicomV3 nor a 'clean' ACR/NEMA file.
02064          // It is time for despaired wild guesses. 
02065          // So, let's check if this file wouldn't happen to be 'dirty' ACR/NEMA,
02066          //  i.e. the 'group length' element is not present :     
02067          
02068          //  check the supposed-to-be 'group number'
02069          //  in ( 0x0001 .. 0x0008 )
02070          //  to determine ' SwapCode' value .
02071          //  Only 0 or 4321 will be possible 
02072          //  (no oportunity to check for the formerly well known
02073          //  ACR-NEMA 'Bad Big Endian' or 'Bad Little Endian' 
02074          //  if unsuccessfull (i.e. neither 0x0002 nor 0x0200 etc-3, 4, ..., 8-)
02075          //  the file IS NOT ACR-NEMA nor DICOM V3
02076          //  Find a trick to tell it the caller...
02077       
02078          s16 = *((uint16_t *)(deb));
02079  
02080          gdcmDebugMacro("not a DicomV3 nor a 'clean' ACR/NEMA;"
02081                      << " (->despaired wild guesses !)");       
02082          switch ( s16 )
02083          {
02084             case 0x0001 :
02085             case 0x0002 :
02086             case 0x0003 :
02087             case 0x0004 :
02088             case 0x0005 :
02089             case 0x0006 :
02090             case 0x0007 :
02091             case 0x0008 :
02092             case 0x0028 :
02093                SwapCode = 1234;
02094                Filetype = ACR;
02095                return true;
02096             case 0x0100 :
02097             case 0x0200 :
02098             case 0x0300 :
02099             case 0x0400 :
02100             case 0x0500 :
02101             case 0x0600 :
02102             case 0x0700 :
02103             case 0x0800 :
02104             case 0x2800 :
02105                SwapCode = 4321;
02106                Filetype = ACR;
02107                return true;
02108             default :
02109     
02110                s16 = *((uint16_t *)(deb));
02111                if (s16 != 0x0000)
02112                    return false;
02113                s16 = *((uint16_t *)(deb+2));
02114 
02115                Fp->seekg ( 0L, std::ios::beg); // Once per Document
02116                CurrentOffsetPosition = 0;
02117                switch(s16)  // try an other trick!
02118                             // -> to be able to decode 0029|1010 DataElement
02119                             // -> and be not less cleaver than dcmdump ;-)
02120                {
02121                   case 0x0004 :
02122                      SwapCode = 1234; 
02123                      break;
02124                   case 0x0400 :
02125                      SwapCode = 3412;
02126                      break;      
02127                   default:
02128                      gdcmWarningMacro("ACR/NEMA unfound swap info (Hopeless !)");
02129                      Filetype = Unknown;
02130                      return false;
02131                }
02132                // Check if next 2 bytes are a VR
02133                // Probabely something more time-consuming exists with std::string
02134                const char VRvalues[] = "AEASCSDADSFLFDISLOLTPNSHSLSSSTTMUIULUSUTOBOWOFATUNSQ";
02135                int nbVal = 26;
02136                const char *pt = VRvalues;
02137                for (int i=0;i<nbVal;i++)
02138                {
02139                   if(*(deb+4) == *pt++)
02140                   if(*(deb+5) == *pt++) {
02141                      Filetype = ExplicitVR;
02142                      return true;       
02143                   }
02144 
02145               }
02146               Filetype = ImplicitVR;
02147               return true;       
02148          }
02149    }
02150 }
02151 
02155 void Document::SwitchByteSwapCode() 
02156 {
02157    gdcmDebugMacro( "Switching Byte Swap code from "<< SwapCode
02158                      << " at: 0x" << std::hex << Fp->tellg() );  // Only when DEBUG
02159    if ( SwapCode == 1234 ) 
02160    {
02161       SwapCode = 4321;
02162    }
02163    else if ( SwapCode == 4321 ) 
02164    {
02165       SwapCode = 1234;
02166    }
02167    else if ( SwapCode == 3412 ) 
02168    {
02169       SwapCode = 2143;
02170    }
02171    else if ( SwapCode == 2143 )
02172    {
02173       SwapCode = 3412;
02174    }
02175    gdcmDebugMacro( " Into: "<< SwapCode );
02176 }
02177 
02182 void Document::SetMaxSizeLoadEntry(long newSize)
02183 {
02184    if ( newSize < 0 )
02185    {
02186       return;
02187    }
02188    if ((uint32_t)newSize >= (uint32_t)0xffffffff )
02189    {
02190       MaxSizeLoadEntry = 0xffffffff;
02191       return;
02192    }
02193    MaxSizeLoadEntry = newSize;
02194 }
02195 
02203 DocEntry *Document::ReadNextDocEntry()
02204 {
02205    try
02206    {
02207       ReadBegBuffer(8); // Avoid to many time consuming freads
02208       //CurrentGroup = ReadInt16();
02209       //CurrentElem  = ReadInt16();
02210    }
02211    catch ( FormatError )
02212    {
02213       // We reached the EOF (or an error occured) therefore
02214       // header parsing has to be considered as finished.
02215       return 0;
02216    }
02217    
02218    changeFromUN = false;
02219    CurrentGroup = GetInt16();
02220    CurrentElem  = GetInt16();
02221       
02222    // In 'true DICOM' files Group 0002 is always little endian
02223    if ( HasDCMPreamble )
02224    {
02225       if ( !Group0002Parsed && CurrentGroup != 0x0002) // avoid calling a function when useless
02226          HandleOutOfGroup0002(CurrentGroup, CurrentElem);
02227       else
02228          // Sometimes file contains groups of tags with reversed endianess.
02229          HandleBrokenEndian(CurrentGroup, CurrentElem);
02230     }
02231 
02232    VRKey vr = FindDocEntryVR();
02233    VRKey realVR = vr;
02234 
02235    if ( vr == GDCM_VRUNKNOWN )
02236    {
02237       if ( CurrentElem == 0x0000 ) // Group Length
02238       {
02239          realVR = "UL";     // must be UL
02240       }
02241       else if (CurrentGroup == 0xfffe) // Don't get DictEntry for Delimitors
02242       {
02243          realVR = "UL";
02244       }
02245 
02246       // Was commented out in order not to generate 'Shadow Groups' where some 
02247       // Data Elements are Explicit VR and some other ones Implicit VR
02248       // -> Better we fix the problem at Write time
02249      
02250       else if (CurrentGroup%2 == 1 )
02251       { 
02252          if (CurrentElem >= 0x0010 && CurrentElem <=0x00ff )
02253             // DICOM PS 3-5 7.8.1 a) states that :
02254             // Private Creator Data Elements numbered (gggg,0010-00FF) (gggg is odd)
02255             // attributes have to be LO (Long String) and the VM shall be equal to 1
02256             realVR = "LO";
02257     
02258             // Seems not to be true
02259             // Still in gdcmtk, David Clunnie disagrees, Marco Eichelberg says it's OK ...
02260             // We let it for a while? 
02261             //(We should check length==4, for more security, but we don't have it yet !)
02262          else if ( CurrentElem == 0x0001)
02263             realVR = "UL"; // Private Group Length To End      
02264       }
02265       
02266       else
02267       {
02268          DictEntry *dictEntry = GetDictEntry(CurrentGroup,CurrentElem);//only when ImplicitVR
02269          if ( dictEntry )
02270          {
02271             realVR = dictEntry->GetVR();
02272             dictEntry->Unregister(); // GetDictEntry registered it 
02273          }
02274       }
02275    }
02276 
02277    // if UN found, let's check the dictionary, and trust it!
02278    // (maybe a private dictionary exists?)    
02279    else if (vr == "UN")
02280    {
02281       DictEntry *dictEntry = GetDictEntry(CurrentGroup,CurrentElem);
02282       if ( dictEntry )
02283       {
02284          realVR = dictEntry->GetVR(); 
02285          dictEntry->Unregister(); // GetDictEntry registered it
02286 
02287          // for VR = "UN", length is always stored on 4 bytes.
02288          changeFromUN=true;
02293       }   
02294    }
02295 
02296 
02297    DocEntry *newEntry;
02298    //if ( Global::GetVR()->IsVROfSequence(realVR) )
02299    if (realVR == "SQ")
02300    {
02301       newEntry = NewSeqEntry(CurrentGroup, CurrentElem);
02302    }
02303    else
02304    {
02305       newEntry = NewDataEntry(CurrentGroup, CurrentElem, realVR);
02306       static_cast<DataEntry *>(newEntry)->SetState(DataEntry::STATE_NOTLOADED);
02307    }
02308 
02309    if ( vr == GDCM_VRUNKNOWN )
02310    {
02311       if ( Filetype == ExplicitVR )
02312       {
02313          // We thought this was explicit VR, but we end up with an
02314          // implicit VR tag. Let's backtrack.
02315  
02316          //if ( newEntry->GetGroup() != 0xfffe ) 
02317          if (CurrentGroup != 0xfffe)
02318          { 
02319             int offset = Fp->tellg();//Only when heuristic for Explicit/Implicit was wrong
02320 
02321             gdcmWarningMacro("Entry (" << newEntry->GetKey() << ") at x("
02322                      <<  offset << ") should be Explicit VR");
02323           }
02324       }
02325       newEntry->SetImplicitVR();
02326    }
02327 
02328    try
02329    {
02330       FindDocEntryLength(newEntry);
02331    }
02332    catch ( FormatError )
02333    {
02334       // Call it quits
02335       newEntry->Delete();
02336       return 0;
02337    }
02338 
02339    newEntry->SetOffset(Fp->tellg());  // for each DocEntry
02340    return newEntry;
02341 }
02342 
02349 void Document::HandleBrokenEndian(uint16_t &group, uint16_t &elem)
02350 {
02351  // for strange PMS Gyroscan Intera images
02352  // Item 'starter' has a tag : 0x3f3f,0x3f00, for no apparent reason
02353  
02354  // --- Feel free to remove this test *on your own coy of gdcm*
02355  //     if you are sure you'll never face this problem.
02356  
02357    if ((group == 0x3f3f) && (elem == 0x3f00))
02358    {
02359      // start endian swap mark for group found
02360      gdcmDebugMacro( " delimiter 0x3f3f  found." );
02361      // fix the tag
02362      group = 0xfffe;
02363      elem  = 0xe000;
02364      return;
02365    }
02366    // --- End of removable code
02367    
02368    // Endian reversion. 
02369    // Some files contain groups of tags with reversed endianess.
02370    static int reversedEndian = 0;
02371    // try to fix endian switching in the middle of headers
02372    if ((group == 0xfeff) && (elem == 0x00e0))
02373    {
02374      // start endian swap mark for group found
02375      gdcmDebugMacro( "Start endian swap mark found." );
02376      reversedEndian++;
02377      SwitchByteSwapCode();
02378      // fix the tag
02379      group = 0xfffe;
02380      elem  = 0xe000;
02381    } 
02382    else if (group == 0xfffe && elem == 0xe00d && reversedEndian) 
02383    {
02384      // end of reversed endian group
02385      gdcmDebugMacro( "End of reversed endian." );
02386      reversedEndian--;
02387      SwitchByteSwapCode();
02388    }
02389    else if (group == 0xfeff && elem == 0xdde0) 
02390    {
02391      // reversed Sequence Terminator found
02392      // probabely a bug in the header !
02393      // Do what you want, it breaks !
02394      //reversedEndian--;
02395      //SwitchByteSwapCode();
02396      gdcmWarningMacro( "Should never get here! reversed Sequence Terminator!" );
02397      // fix the tag
02398       group = 0xfffe;
02399       elem  = 0xe0dd;  
02400    }
02401    else if (group == 0xfffe && elem == 0xe0dd) 
02402    {
02403       gdcmDebugMacro( "Straight Sequence Terminator." );  
02404    }
02405 }
02406 
02412 void Document::HandleOutOfGroup0002(uint16_t &group, uint16_t &elem)
02413 {
02414    // Endian reversion. 
02415    // Some files contain groups of tags with reversed endianess.
02416    
02417       Group0002Parsed = true;
02418       // we just came out of group 0002
02419       // if Transfer Syntax is Big Endian we have to change CheckSwap
02420 
02421       std::string ts = GetTransferSyntax();
02422       TS::SpecialType s = Global::GetTS()->GetSpecialTransferSyntax(ts);
02423 
02424       // Group 0002 is always 'Explicit ...' 
02425       // even when Transfer Syntax says 'Implicit ..." 
02426 
02427       if ( s == TS::ImplicitVRLittleEndian 
02428         ||
02429           s == TS::ImplicitVRBigEndianPrivateGE  
02430          )
02431       {
02432          Filetype = ImplicitVR;
02433       }
02434        
02435       // FIXME Strangely, this works with 
02436       //'Implicit VR BigEndian Transfer Syntax' (GE Private)
02437       //
02438       // --> Probabely normal, since we considered we never have 
02439       // to trust manufacturers.
02440       // (we often find 'Implicit VR' tag, 
02441       // even when Transfer Syntax tells us it's Explicit ...
02442       
02443        // NEVER trust the meta elements!
02444        // (see what ezDICOM does ...)
02445              
02446       /*
02447       if ( s ==  TS::ExplicitVRBigEndian )
02448       {
02449          gdcmDebugMacro("Transfer Syntax Name = [" 
02450                         << GetTransferSyntaxName() << "]" );
02451          SwitchByteSwapCode();
02452          group = SwapShort(group);
02453          elem  = SwapShort(elem);
02454       }
02455       */
02456     //-- Broken ACR  may start with a Shadow Group --
02457     // worse : some ACR-NEMA like files start 00028 group ?!? 
02458     if ( !( (group >= 0x0001 && group <= 0x0008) || group == 0x0028 ) )
02459     {
02460        // We trust what we see.
02461        SwitchByteSwapCode();
02462        group = SwapShort(group);
02463        elem  = SwapShort(elem); 
02464        // not what we where told (by meta elements) !
02465        gdcmDebugMacro("Transfer Syntax Name = ["       
02466                        << GetTransferSyntaxName() << "]" );         
02467     }
02468       
02470             
02471       if ( s == TS::DeflatedExplicitVRLittleEndian)
02472       {
02473            gdcmWarningMacro("Transfer Syntax [" 
02474                         << GetTransferSyntaxName() << "] :"
02475                         << " not yet dealt with ");
02476            return;       
02477       }
02478       
02479       // The following shouldn't occur very often
02480       // Let's check at the very end.
02481 
02482       if ( ts == GDCM_UNKNOWN )
02483       {
02484          gdcmDebugMacro("True DICOM File, with NO Transfer Syntax (?!) " );
02485          return;      
02486       }
02487       
02488       if ( !Global::GetTS()->IsTransferSyntax(ts) )
02489       {
02490          gdcmWarningMacro("True DICOM File, with illegal Transfer Syntax: [" 
02491                           << ts << "]");
02492          return;
02493       }      
02494 }
02495 
02496 //-----------------------------------------------------------------------------
02497 // Print
02498 
02499 //-----------------------------------------------------------------------------
02500 } // end namespace gdcm

Generated on Fri Aug 24 12:59:30 2007 for gdcm by  doxygen 1.4.6