/*========================================================================= Program: GDCM (Grassroots DICOM). A DICOM library Copyright (c) 2006-2011 Mathieu Malaterre All rights reserved. See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ #include "gdcmPresentationContextGenerator.h" #include "gdcmReader.h" #include "gdcmTransferSyntax.h" #include // std::find namespace gdcm { std::string PresentationContextGenerator::DefaultTransferSyntax = "1.2.840.10008.1.2"; const char *PresentationContextGenerator::GetDefaultTransferSyntax() const { return DefaultTransferSyntax.c_str(); } void PresentationContextGenerator::SetDefaultTransferSyntax( const TransferSyntax &ts ) { DefaultTransferSyntax = ts.GetString(); } PresentationContextGenerator::PresentationContextGenerator() = default; //bool PresentationContextGenerator::GenerateFromQuery(BaseRootQuery *query) //{ //} bool PresentationContextGenerator::GenerateFromUID(UIDs::TSName asname) { PresContext.clear(); const char *asnamestr = UIDs::GetUIDString( asname ); const char *tsnamestr = GetDefaultTransferSyntax(); // There is a special case for MOVE operations. Need to have alternate FIND operations if( asname == UIDs::PatientRootQueryRetrieveInformationModelMOVE ) { const char *asnamestr0 = UIDs::GetUIDString( UIDs::PatientRootQueryRetrieveInformationModelFIND ); AddPresentationContext( asnamestr0, tsnamestr ); } else if( asname == UIDs::StudyRootQueryRetrieveInformationModelMOVE ) { const char *asnamestr0 = UIDs::GetUIDString( UIDs::StudyRootQueryRetrieveInformationModelFIND ); AddPresentationContext( asnamestr0, tsnamestr ); } // Always set the *MOVE after the *FIND one AddPresentationContext( asnamestr, tsnamestr ); return true; } bool PresentationContextGenerator::AddFromFile(const File &file) { Tag sopclass(0x8,0x16); DataSet const & ds = file.GetDataSet(); if( ds.FindDataElement( sopclass ) ) { // by design gdcmscu will not send/retrieve a dataset that cannot be read // this should not be too restricitive const TransferSyntax &fmits = file.GetHeader().GetDataSetTransferSyntax(); const char *tsuidvalue = fmits.GetString(); const DataElement &tsde = ds.GetDataElement( sopclass ); // Passing pointer directly. We do not try to analyze what Media Storage // it is. We should be able to support to send/receive unknown media storage const ByteValue *bv = tsde.GetByteValue(); std::string buffer( bv->GetPointer(), bv->GetLength() ); const char *sopclassvalue = buffer.c_str(); AddPresentationContext( sopclassvalue, tsuidvalue ); return true; } return false; } bool PresentationContextGenerator::GenerateFromFilenames(const Directory::FilenamesType &filenames) { PresContext.clear(); // By design GDCM C-STORE implementation only setup the association for any dataset we are // about to send. This is therefore very important to gather all possible SOP Class // we are about to send otherwise the other end will simply disconnect us // this imply that C-STORE will refuse any DataSet without SOP Class or SOP Instances Tag tsuid(0x2,0x10); Tag mediasopclass(0x2,0x2); Tag sopclass(0x8,0x16); Directory::FilenamesType::const_iterator file = filenames.begin(); std::set skiptags; for(; file != filenames.end(); ++file) { // I cannot use gdcm::Scanner as I need the TS of the file. When the file // only contains the DataSet I cannot know if this is Explicit or Implicit // Instead re-use the lower level bricks of gdcm::Scanner here: const char *fn = file->c_str(); Reader reader; reader.SetFileName( fn ); // NOTE: There is a small overhead right here: what if we are sending Deflated // TS encoded file. We should not need to read up to tag 8,16 ... if( reader.ReadUpToTag( sopclass, skiptags ) ) { AddFromFile( reader.GetFile() ); } else { gdcmErrorMacro( "Could not read: " << fn ); } } return true; } bool PresentationContextGenerator::AddPresentationContext( const char *as, const char * ts ) { // \precondition assert( as ); assert( ts ); SizeType n = PresContext.size(); PresentationContext pc; pc.SetAbstractSyntax( as ); SizeType idn = 2*n + 1; assert( idn <= std::numeric_limits::max() ); pc.SetPresentationContextID( (uint8_t)idn ); pc.AddTransferSyntax( ts ); PresentationContextArrayType::const_iterator it = std::find( PresContext.begin(), PresContext.end(), pc ); // default mode it to only append when pc is not present already: // warning dcmtk 3.5.4 will segfault if no PresentationContext is found // (fixed in 3.6.0) if( it == PresContext.end() ) { PresContext.push_back( pc ); } return true; } void PresentationContextGenerator::SetMergeModeToAbstractSyntax() { } void PresentationContextGenerator::SetMergeModeToTransferSyntax() { assert( 0 && "TODO" ); } } // end namespace gdcm