1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
|
/*=========================================================================
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 <algorithm> // 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() {}
//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::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 Clas or SOP Instances
Tag tsuid(0x2,0x10);
Tag mediasopclass(0x2,0x2);
Tag sopclass(0x8,0x16);
#if 0
Scanner sc;
sc.AddTag( tsuid );
sc.AddTag( mediasopclass );
sc.AddTag( sopclass );
if( !sc.Scan( filenames ) )
{
gdcmErrorMacro( "Could not scan filenames" );
return 1;
}
#endif
Directory::FilenamesType::const_iterator file = filenames.begin();
std::set<Tag> 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 ) )
{
DataSet const & ds = reader.GetFile().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 = reader.GetFile().GetHeader().GetDataSetTransferSyntax();
//const char *tsuidvalue = sc.GetValue(fn, tsuid);
const char *tsuidvalue = fmits.GetString();
//const char *sopclassvalue = sc.GetValue(fn, sopclass );
const DataElement &tsde = ds.GetDataElement( sopclass );
//const char *sopclassvalue = sc.GetValue(fn, sopclass );
// Passing pointer directly. We do not try to analyze what Media Storage
// it is. We should be able to support to send/receive unknwon media storage
const ByteValue *bv = tsde.GetByteValue();
std::string buffer( bv->GetPointer(), bv->GetLength() );
const char *sopclassvalue = buffer.c_str();
AddPresentationContext( sopclassvalue, tsuidvalue );
}
}
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<uint8_t>::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
|