1 /*=========================================================================
2
3 Program: GDCM (Grassroots DICOM). A DICOM library
4
5 Copyright (c) 2006-2011 Mathieu Malaterre
6 All rights reserved.
7 See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details.
8
9 This software is distributed WITHOUT ANY WARRANTY; without even
10 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
11 PURPOSE. See the above copyright notice for more information.
12
13 =========================================================================*/
14 #include "gdcmAAssociateACPDU.h"
15 #include "gdcmSwapper.h"
16 #include "gdcmAAssociateRQPDU.h"
17
18 namespace gdcm
19 {
20 namespace network
21 {
22 const uint8_t AAssociateACPDU::ItemType = 0x02; // PDUType ?
23 const uint8_t AAssociateACPDU::Reserved2 = 0x00;
24 const uint16_t AAssociateACPDU::ProtocolVersion = 0x01; // big endian
25 const uint16_t AAssociateACPDU::Reserved9_10 = 0x0000;
26 //const uint8_t AAssociateACPDU::Reserved11_26[16] = { };
27 //const uint8_t AAssociateACPDU::Reserved27_42[16] = { };
28 //const uint8_t AAssociateACPDU::Reserved43_74[32] = { };
29
AAssociateACPDU()30 AAssociateACPDU::AAssociateACPDU()
31 {
32 PDULength = 0; // len of
33 memset(Reserved11_26, ' ', sizeof(Reserved11_26));
34 memset(Reserved27_42, ' ', sizeof(Reserved27_42));
35 memset(Reserved43_74, ' ', sizeof(Reserved43_74));
36
37 PDULength = (uint32_t)(Size() - 6);
38 }
39
SetCalledAETitle(const char calledaetitle[16])40 void AAssociateACPDU::SetCalledAETitle(const char calledaetitle[16])
41 {
42 //size_t len = strlen( calledaetitle );
43 //assert( len <= 16 ); // since forwarded from AA-RQ no reason to be invalid
44 memcpy(Reserved11_26, calledaetitle, 16 );
45 }
46
SetCallingAETitle(const char callingaetitle[16])47 void AAssociateACPDU::SetCallingAETitle(const char callingaetitle[16])
48 {
49 //size_t len = strlen( callingaetitle );
50 //assert( len <= 16 ); // since forwarded from AA-RQ no reason to be invalid
51 memcpy(Reserved27_42, callingaetitle, 16 );
52 }
53
Read(std::istream & is)54 std::istream &AAssociateACPDU::Read(std::istream &is)
55 {
56 //uint8_t itemtype = 0;
57 //is.read( (char*)&itemtype, sizeof(ItemType) );
58 //assert( itemtype == ItemType );
59 assert( is.good() );
60 uint8_t reserved2;
61 is.read( (char*)&reserved2, sizeof(Reserved2) );
62 uint32_t pdulength = 0;
63 is.read( (char*)&pdulength, sizeof(PDULength) );
64 SwapperDoOp::SwapArray(&pdulength,1);
65 PDULength = pdulength;
66 uint16_t protocolversion;
67 is.read( (char*)&protocolversion, sizeof(ProtocolVersion) );
68 SwapperDoOp::SwapArray(&protocolversion,1);
69 if( protocolversion != ProtocolVersion )
70 {
71 gdcmErrorMacro( "Improper Protocol Version: " << protocolversion );
72 }
73 uint16_t reserved9_10;
74 is.read( (char*)&reserved9_10, sizeof(Reserved9_10) );
75 SwapperDoOp::SwapArray(&reserved9_10,1);
76 char reserved11_26[16];
77 memset( reserved11_26, 0, sizeof(reserved11_26));
78 is.read( (char*)&reserved11_26, sizeof(Reserved11_26) ); // called
79 memcpy( Reserved11_26, reserved11_26, sizeof(Reserved11_26) );
80 char reserved27_42[16];
81 memset( reserved27_42, 0, sizeof(reserved27_42));
82 is.read( (char*)&reserved27_42, sizeof(Reserved27_42) ); // calling
83 memcpy( Reserved27_42, reserved27_42, sizeof(Reserved27_42) );
84 uint8_t reserved43_74[32];
85 memset( reserved43_74, 0, sizeof(reserved43_74));
86 is.read( (char*)&reserved43_74, sizeof(Reserved43_74) ); // 0 (32 times)
87 memcpy( Reserved43_74, reserved43_74, sizeof(Reserved43_74) );
88
89 uint8_t itemtype2 = 0x0;
90 size_t curlen = 0;
91 while( curlen + 68 < PDULength )
92 {
93 is.read( (char*)&itemtype2, sizeof(ItemType) );
94 switch ( itemtype2 )
95 {
96 case 0x10: // ApplicationContext ItemType
97 AppContext.Read( is );
98 curlen += AppContext.Size();
99 break;
100 case 0x21: // PresentationContextAC ItemType
101 {
102 PresentationContextAC pcac;
103 pcac.Read( is );
104 PresContextAC.push_back( pcac );
105 curlen += pcac.Size();
106 }
107 break;
108 case 0x50: // UserInformation ItemType
109 UserInfo.Read( is );
110 curlen += UserInfo.Size();
111 break;
112 default:
113 gdcmErrorMacro( "Unknown ItemType: " << std::hex << (int) itemtype2 );
114 curlen = PDULength; // make sure to exit
115 break;
116 }
117 // WARNING: I cannot simply call Size() since UserInfo is initialized with GDCM
118 // own parameter, this will bias the computation. Instead compute relative
119 // length of remaining bytes to read.
120 //curlen = Size();
121 }
122 assert( curlen + 68 == PDULength );
123 assert( PDULength + 4 + 1 + 1 == Size() );
124
125 return is;
126 }
127
Write(std::ostream & os) const128 const std::ostream &AAssociateACPDU::Write(std::ostream &os) const
129 {
130 os.write( (const char*)&ItemType, sizeof(ItemType) );
131 os.write( (const char*)&Reserved2, sizeof(Reserved2) );
132 //os.write( (const char*)&PDULength, sizeof(PDULength) );
133 uint32_t copy = PDULength;
134 SwapperDoOp::SwapArray(©,1);
135 os.write( (const char*)©, sizeof(PDULength) );
136 uint16_t protocolversion = ProtocolVersion;
137 SwapperDoOp::SwapArray(&protocolversion,1);
138 os.write( (const char*)&protocolversion, sizeof(ProtocolVersion) );
139 os.write( (const char*)&Reserved9_10, sizeof(Reserved9_10) );
140 os.write( (const char*)&Reserved11_26, sizeof(Reserved11_26) );
141 //const char calling[] = "ANY-SCP ";
142 //os.write( calling, 16 );
143
144 os.write( (const char*)&Reserved27_42, sizeof(Reserved27_42) );
145 //const char called[] = "STORESCU ";
146 //const char called[] = "ECHOSCU ";
147 //os.write( called, 16 );
148 os.write( (const char*)&Reserved43_74, sizeof(Reserved43_74) );
149 AppContext.Write( os );
150 gdcmAssertAlwaysMacro( PresContextAC.size() );
151 std::vector<PresentationContextAC>::const_iterator it = PresContextAC.begin();
152 for( ; it != PresContextAC.end(); ++it )
153 {
154 it->Write( os );
155 }
156 UserInfo.Write( os );
157
158 assert( PDULength + 4 + 1 + 1 == Size() );
159
160 return os;
161 }
162
Size() const163 size_t AAssociateACPDU::Size() const
164 {
165 size_t ret = 0;
166 ret += sizeof(ItemType);
167 ret += sizeof(Reserved2);
168 ret += sizeof(PDULength);
169 ret += sizeof(ProtocolVersion);
170 ret += sizeof(Reserved9_10);
171 ret += sizeof(Reserved11_26);
172 ret += sizeof(Reserved27_42);
173 ret += sizeof(Reserved43_74);
174 ret += AppContext.Size();
175 std::vector<PresentationContextAC>::const_iterator it = PresContextAC.begin();
176 for( ; it != PresContextAC.end(); ++it )
177 {
178 ret += it->Size();
179 }
180 ret += UserInfo.Size();
181 return ret;
182 }
183
AddPresentationContextAC(PresentationContextAC const & pcac)184 void AAssociateACPDU::AddPresentationContextAC( PresentationContextAC const &pcac )
185 {
186 PresContextAC.push_back( pcac );
187 PDULength = (uint32_t)(Size() - 6);
188 assert( PDULength + 4 + 1 + 1 == Size() );
189 }
190
Print(std::ostream & os) const191 void AAssociateACPDU::Print(std::ostream &os) const
192 {
193 os << "ProtocolVersion: " << std::hex << ProtocolVersion << std::dec << std::endl;
194 os << "Reserved9_10: " << std::hex << Reserved9_10 << std::dec << std::endl;
195 os << "Reserved11_26: [" << std::string(Reserved11_26,sizeof(Reserved11_26)) << "]" << std::endl;
196 os << "Reserved27_42: [" << std::string(Reserved27_42,sizeof(Reserved27_42)) << "]" << std::endl;
197 /*os << "Reserved43_74: [" << std::string(Reserved43_74,sizeof(Reserved43_74)) << "]" << std::endl;*/
198 os << "Application Context Name: ";
199 AppContext.Print( os );
200 os << "List of PresentationContextAC: " << std::endl;
201 std::vector<PresentationContextAC>::const_iterator it = PresContextAC.begin();
202 for( ; it != PresContextAC.end(); ++it )
203 {
204 it->Print(os);
205 }
206 os << "User Information: ";
207 UserInfo.Print( os );
208 }
209
InitFromRQ(AAssociateRQPDU const & rqpdu)210 void AAssociateACPDU::InitFromRQ( AAssociateRQPDU const & rqpdu )
211 {
212 // Table 9-17 ASSOCIATE-AC PDU fields
213 // This reserved field shall be sent with a value identical to the value
214 // received in the same field of the A-ASSOCIATE-RQ PDU
215 const std::string called = rqpdu.GetCalledAETitle();
216 SetCalledAETitle( rqpdu.GetCalledAETitle().c_str() );
217 const std::string calling = rqpdu.GetCallingAETitle();
218 SetCallingAETitle( rqpdu.GetCallingAETitle().c_str() );
219 const std::string reserved = rqpdu.GetReserved43_74();
220 memcpy( Reserved43_74, reserved.c_str(), sizeof(Reserved43_74) );
221
222 assert( ProtocolVersion == 0x01 );
223 assert( Reserved9_10 == 0x0 );
224 assert( memcmp( Reserved11_26, called.c_str(), sizeof( Reserved11_26) ) == 0 );
225 assert( memcmp( Reserved27_42, calling.c_str(), sizeof(Reserved27_42) ) == 0 );
226 assert( memcmp( Reserved43_74, reserved.c_str(), sizeof(Reserved43_74) ) == 0 );
227 }
228
229
InitSimple(AAssociateRQPDU const & rqpdu)230 void AAssociateACPDU::InitSimple( AAssociateRQPDU const & rqpdu )
231 {
232 TransferSyntaxSub ts1;
233 ts1.SetNameFromUID( UIDs::ImplicitVRLittleEndianDefaultTransferSyntaxforDICOM );
234
235 assert( rqpdu.GetNumberOfPresentationContext() );
236 for( unsigned int index = 0; index < rqpdu.GetNumberOfPresentationContext(); index++ )
237 {
238 // FIXME / HARDCODED We only ever accept Little Endian
239 // FIXME we should check :
240 // rqpdu.GetAbstractSyntax() contains LittleEndian
241 PresentationContextAC pcac1;
242 PresentationContextRQ const &pc = rqpdu.GetPresentationContext(index);
243 uint8_t id = pc.GetPresentationContextID();
244
245 pcac1.SetPresentationContextID( id ); // DCMTK MR
246 pcac1.SetTransferSyntax( ts1 );
247 AddPresentationContextAC( pcac1 );
248 }
249
250 }
251
252 } // end namespace network
253 } // end namespace gdcm
254