1/* 2 service.cpp 3 4 Service structures. 5 6-------------------------------------------------------------------------------- 7gSOAP XML Web services tools 8Copyright (C) 2001-2008, Robert van Engelen, Genivia Inc. All Rights Reserved. 9This part of the software is released under one of the following licenses: 10GPL or Genivia's license for commercial use. 11-------------------------------------------------------------------------------- 12GPL license. 13 14This program is free software; you can redistribute it and/or modify it under 15the terms of the GNU General Public License as published by the Free Software 16Foundation; either version 2 of the License, or (at your option) any later 17version. 18 19This program is distributed in the hope that it will be useful, but WITHOUT ANY 20WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 21PARTICULAR PURPOSE. See the GNU General Public License for more details. 22 23You should have received a copy of the GNU General Public License along with 24this program; if not, write to the Free Software Foundation, Inc., 59 Temple 25Place, Suite 330, Boston, MA 02111-1307 USA 26 27Author contact information: 28engelen@genivia.com / engelen@acm.org 29-------------------------------------------------------------------------------- 30A commercial use license is available from Genivia, Inc., contact@genivia.com 31-------------------------------------------------------------------------------- 32 33TODO: consider adding support for non-SOAP HTTP operations 34 add headerfault output definitions 35 36*/ 37 38#include "types.h" 39#include "service.h" 40 41static void comment(const char *start, const char *middle, const char *end, const char *text); 42static void page(const char *page, const char *title, const char *text); 43static void section(const char *section, const char *title, const char *text); 44static void banner(const char*); 45static void ident(); 46static void text(const char*); 47 48//////////////////////////////////////////////////////////////////////////////// 49// 50// Definitions methods 51// 52//////////////////////////////////////////////////////////////////////////////// 53 54Definitions::Definitions() 55{ } 56 57void Definitions::collect(const wsdl__definitions &definitions) 58{ // Collect information: analyze WSDL definitions and imported definitions 59 analyze(definitions); 60 for (vector<wsdl__import>::const_iterator import = definitions.import.begin(); import != definitions.import.end(); ++import) 61 if ((*import).definitionsPtr()) 62 analyze(*(*import).definitionsPtr()); 63} 64 65void Definitions::analyze(const wsdl__definitions &definitions) 66{ // Analyze WSDL and build Service information 67 int binding_count = 0; 68 // Determine number of relevant SOAP service bindings 69 for (vector<wsdl__binding>::const_iterator i = definitions.binding.begin(); i != definitions.binding.end(); ++i) 70 { for (vector<wsdl__binding_operation>::const_iterator j = (*i).operation.begin(); j != (*i).operation.end(); ++j) 71 { if ((*j).operationPtr() && (*j).input && (*j).input->soap__body_) 72 { binding_count++; 73 break; 74 } 75 } 76 } 77 // Analyze and collect service data 78 for (vector<wsdl__binding>::const_iterator binding = definitions.binding.begin(); binding != definitions.binding.end(); ++binding) 79 { // /definitions/binding/documentation 80 const char *binding_documentation = (*binding).documentation; 81 // /definitions/binding/soap:binding 82 soap__binding *soap__binding_ = (*binding).soap__binding_; 83 // /definitions/binding/soap:binding/@transport 84 const char *soap__binding_transport = NULL; 85 if (soap__binding_) 86 soap__binding_transport = soap__binding_->transport; 87 // /definitions/binding/soap:binding/@style 88 soap__styleChoice soap__binding_style = rpc; 89 if (soap__binding_ && soap__binding_->style) 90 soap__binding_style = *soap__binding_->style; 91 // /definitions/binding/http:binding 92 http__binding *http__binding_ = (*binding).http__binding_; 93 const char *http__binding_verb = NULL; 94 if (http__binding_) 95 http__binding_verb = http__binding_->verb; 96 // /definitions/binding/operation* 97 for (vector<wsdl__binding_operation>::const_iterator operation = (*binding).operation.begin(); operation != (*binding).operation.end(); ++operation) 98 { // /definitions/portType/operation/ associated with /definitions/binding/operation 99 wsdl__operation *wsdl__operation_ = (*operation).operationPtr(); 100 // /definitions/binding/operation/soap:operation 101 soap__operation *soap__operation_ = (*operation).soap__operation_; 102 // /definitions/binding/operation/soap:operation/@style 103 soap__styleChoice soap__operation_style = soap__binding_style; 104 if (soap__operation_ && soap__operation_->style) 105 soap__operation_style = *soap__operation_->style; 106 // /definitions/binding/operation/http:operation 107 http__operation *http__operation_ = (*operation).http__operation_; 108 // /definitions/binding/operation/http:operation/@location 109 const char *http__operation_location = NULL; 110 if (http__operation_) 111 http__operation_location = http__operation_->location; 112 // /definitions/binding/operation/input 113 wsdl__ext_input *ext_input = (*operation).input; 114 // /definitions/binding/operation/output 115 wsdl__ext_output *ext_output = (*operation).output; 116 // /definitions/portType/operation 117 if (wsdl__operation_) 118 { wsdl__input *input = wsdl__operation_->input; 119 wsdl__output *output = wsdl__operation_->output; 120 if (http__operation_) 121 { // TODO: HTTP operation 122 } 123 else if (input && ext_input) 124 { soap__body *input_body = ext_input->soap__body_; 125 if (ext_input->mime__multipartRelated_) 126 { for (vector<mime__part>::const_iterator part = ext_input->mime__multipartRelated_->part.begin(); part != ext_input->mime__multipartRelated_->part.end(); ++part) 127 if ((*part).soap__body_) 128 { input_body = (*part).soap__body_; 129 break; 130 } 131 } 132 // MUST have an input, otherwise can't generate a service operation 133 if (input_body) 134 { char *URI; 135 if (soap__operation_style == rpc) 136 URI = input_body->namespace_; 137 else if (binding_count == 1) 138 URI = definitions.targetNamespace; 139 else 140 { // multiple service bidings are used, each needs a unique new URI 141 URI = (char*)soap_malloc(definitions.soap, strlen(definitions.targetNamespace) + strlen((*binding).name) + 2); 142 strcpy(URI, definitions.targetNamespace); 143 if (*URI && URI[strlen(URI)-1] != '/') 144 strcat(URI, "/"); 145 strcat(URI, (*binding).name); 146 } 147 if (URI) 148 { const char *prefix = types.nsprefix(service_prefix, URI); 149 const char *name = types.aname(NULL, NULL, (*binding).name); // name of service is binding name 150 Service *s = services[prefix]; 151 if (!s) 152 { s = services[prefix] = new Service(); 153 s->prefix = prefix; 154 s->URI = URI; 155 s->name = name; 156 s->transport = soap__binding_transport; 157 if ((*binding).portTypePtr()) 158 s->type = types.aname(NULL, NULL, (*binding).portTypePtr()->name); 159 else 160 s->type = NULL; 161 } 162 for (vector<wsdl__service>::const_iterator service = definitions.service.begin(); service != definitions.service.end(); ++service) 163 { for (vector<wsdl__port>::const_iterator port = (*service).port.begin(); port != (*service).port.end(); ++port) 164 { if ((*port).bindingPtr() == &(*binding)) 165 { if ((*port).soap__address_) 166 s->location.insert((*port).soap__address_->location); 167 // TODO: HTTP address for HTTP operations 168 // if ((*port).http__address_) 169 // http__address_location = http__address_->location; 170 if ((*service).documentation) 171 s->service_documentation[(*service).name] = (*service).documentation; 172 if ((*port).documentation && (*port).name) 173 s->port_documentation[(*port).name] = (*port).documentation; 174 if (binding_documentation) 175 s->binding_documentation[(*binding).name] = binding_documentation; 176 } 177 } 178 } 179 Operation *o = new Operation(); 180 o->name = types.aname(NULL, NULL, wsdl__operation_->name); 181 o->prefix = prefix; 182 o->URI = URI; 183 o->style = soap__operation_style; 184 o->documentation = wsdl__operation_->documentation; 185 o->operation_documentation = (*operation).documentation; 186 o->parameterOrder = wsdl__operation_->parameterOrder; 187 if ((*operation).soap__operation_) 188 o->soapAction = (*operation).soap__operation_->soapAction; 189 else 190 { o->soapAction = ""; 191 // determine if we use SOAP 1.2 in which case soapAction is absent, this is a bit of a hack due to the lack of WSDL1.1/SOAP1.2 support and better alternatives 192 for (Namespace *p = definitions.soap->local_namespaces; p && p->id; p++) 193 { if (p->out && !strcmp(p->id, "soap") && !strcmp(p->out, "http://schemas.xmlsoap.org/wsdl/soap12/")) 194 { o->soapAction = NULL; 195 break; 196 } 197 } 198 } 199 o->input = new Message(); 200 o->input->name = (*operation).name; // RPC uses operation/@name 201 if (soap__operation_style == rpc && !input_body->namespace_) 202 { o->input->URI = ""; 203 fprintf(stderr, "Error: no soap:body namespace attribute\n"); 204 } 205 else 206 o->input->URI = input_body->namespace_; 207 o->input->style = soap__operation_style; 208 o->input->use = input_body->use; 209 o->input->encodingStyle = input_body->encodingStyle; 210 o->input->action = input->wsam__Action; 211 o->input->message = input->messagePtr(); 212 o->input->part = NULL; 213 o->input->multipartRelated = ext_input->mime__multipartRelated_; 214 o->input->content = NULL; 215 if (ext_input->mime__multipartRelated_ && !ext_input->mime__multipartRelated_->part.empty()) 216 o->input->header = ext_input->mime__multipartRelated_->part.front().soap__header_; 217 else 218 o->input->header = ext_input->soap__header_; 219 if (ext_input->mime__multipartRelated_ && !ext_input->mime__multipartRelated_->part.empty() && ext_input->mime__multipartRelated_->part.front().soap__body_) 220 o->input->body_parts = ext_input->mime__multipartRelated_->part.front().soap__body_->parts; 221 else 222 o->input->body_parts = input_body->parts; 223 if (ext_input->dime__message_) 224 o->input->layout = ext_input->dime__message_->layout; 225 else 226 o->input->layout = NULL; 227 o->input->documentation = input->documentation; 228 o->input->ext_documentation = ext_input->documentation; 229 if (soap__operation_style == document) 230 o->input_name = types.oname("__", o->URI, o->input->name); 231 else 232 o->input_name = types.oname(NULL, o->input->URI, o->input->name); 233 if (output && ext_output) 234 { soap__body *output_body = ext_output->soap__body_; 235 if (ext_output->mime__multipartRelated_) 236 { for (vector<mime__part>::const_iterator part = ext_output->mime__multipartRelated_->part.begin(); part != ext_output->mime__multipartRelated_->part.end(); ++part) 237 if ((*part).soap__body_) 238 { output_body = (*part).soap__body_; 239 break; 240 } 241 } 242 if (ext_output->mime__content_) 243 { o->output = new Message(); 244 o->output->name = NULL; 245 o->output->URI = NULL; 246 o->output->encodingStyle = NULL; 247 o->output->action = NULL; 248 o->output->body_parts = NULL; 249 o->output->part = NULL; 250 o->output->multipartRelated = NULL; 251 o->output->content = ext_output->mime__content_; 252 o->output->message = output->messagePtr(); 253 o->output->layout = NULL; 254 o->output->documentation = output->documentation; 255 o->output->ext_documentation = ext_output->documentation; 256 } 257 else if (output_body) 258 { o->output = new Message(); 259 o->output->name = (*operation).name; // RPC uses operation/@name with suffix 'Response' as set below 260 o->output->style = soap__operation_style; 261 o->output->use = output_body->use; 262 // the code below is a hack around the RPC encoded response message element tag mismatch with Axis: 263 if (!output_body->namespace_ || output_body->use == encoded) 264 o->output->URI = o->input->URI; // encoded seems (?) to require the request's namespace 265 else 266 o->output->URI = output_body->namespace_; 267 o->output->encodingStyle = output_body->encodingStyle; 268 o->output->action = output->wsam__Action; 269 o->output->message = output->messagePtr(); 270 o->output->part = NULL; 271 o->output->multipartRelated = ext_output->mime__multipartRelated_; 272 o->output->content = NULL; 273 if (ext_output->mime__multipartRelated_ && !ext_output->mime__multipartRelated_->part.empty()) 274 o->output->header = ext_output->mime__multipartRelated_->part.front().soap__header_; 275 else 276 o->output->header = ext_output->soap__header_; 277 if (ext_output->mime__multipartRelated_ && !ext_output->mime__multipartRelated_->part.empty() && ext_output->mime__multipartRelated_->part.front().soap__body_) 278 o->output->body_parts = ext_output->mime__multipartRelated_->part.front().soap__body_->parts; 279 else 280 o->output->body_parts = output_body->parts; 281 if (ext_output->dime__message_) 282 o->output->layout = ext_output->dime__message_->layout; 283 else 284 o->output->layout = NULL; 285 o->output->documentation = output->documentation; 286 o->output->ext_documentation = ext_output->documentation; 287 char *s = (char*)soap_malloc(definitions.soap, strlen(o->output->name) + 9); 288 strcpy(s, o->output->name); 289 strcat(s, "Response"); 290 if (soap__operation_style == document) 291 o->output_name = types.oname("__", o->URI, s); 292 else 293 o->output_name = types.oname(NULL, o->output->URI, s); 294 } 295 } 296 else 297 { o->output_name = NULL; 298 o->output = NULL; 299 } 300 // collect input headers and headerfaults 301 if (ext_input) 302 { const vector<soap__header> *soap__header_ = NULL; 303 // check if soap header is in mime:multipartRelated 304 if (ext_input->mime__multipartRelated_) 305 { for (vector<mime__part>::const_iterator part = ext_input->mime__multipartRelated_->part.begin(); part != ext_input->mime__multipartRelated_->part.end(); ++part) 306 if (!(*part).soap__header_.empty()) 307 { soap__header_ = &(*part).soap__header_; 308 break; 309 } 310 } 311 if (!soap__header_) 312 soap__header_ = &ext_input->soap__header_; 313 for (vector<soap__header>::const_iterator header = soap__header_->begin(); header != soap__header_->end(); ++header) 314 { Message *h = new Message(); 315 h->message = (*header).messagePtr(); 316 h->body_parts = NULL; 317 h->part = (*header).partPtr(); 318 h->URI = (*header).namespace_; 319 if (h->part && h->part->element) 320 h->name = types.aname(NULL, NULL, h->part->element); 321 else if (h->URI && h->part && h->part->name && h->part->type) 322 h->name = types.aname(NULL, h->URI, h->part->name); 323 else 324 { fprintf(stderr, "Error in SOAP Header part definition: input part '%s' missing?\n", h->part && h->part->name ? h->part->name : "?"); 325 h->name = ""; 326 } 327 h->encodingStyle = (*header).encodingStyle; 328 h->style = document; // irrelevant 329 h->use = (*header).use; 330 h->multipartRelated = NULL; 331 h->content = NULL; 332 h->layout = NULL; 333 h->ext_documentation = NULL; // TODO: add document content 334 h->documentation = NULL; // TODO: add document content 335 s->header[h->name] = h; 336 for (vector<soap__headerfault>::const_iterator headerfault = (*header).headerfault.begin(); headerfault != (*header).headerfault.end(); ++headerfault) 337 { // TODO: headerfault processing. This is rarely used. 338 } 339 } 340 } 341 // collect output headers and headerfaults 342 if (ext_output) 343 { const vector<soap__header> *soap__header_ = NULL; 344 // check if soap header is in mime:multipartRelated 345 if (ext_output->mime__multipartRelated_) 346 { for (vector<mime__part>::const_iterator part = ext_output->mime__multipartRelated_->part.begin(); part != ext_output->mime__multipartRelated_->part.end(); ++part) 347 if (!(*part).soap__header_.empty()) 348 { soap__header_ = &(*part).soap__header_; 349 break; 350 } 351 } 352 if (!soap__header_) 353 soap__header_ = &ext_output->soap__header_; 354 for (vector<soap__header>::const_iterator header = soap__header_->begin(); header != soap__header_->end(); ++header) 355 { Message *h = new Message(); 356 h->message = (*header).messagePtr(); 357 h->body_parts = NULL; 358 h->part = (*header).partPtr(); 359 h->URI = (*header).namespace_; 360 if (h->part && h->part->element) 361 h->name = types.aname(NULL, NULL, h->part->element); 362 else if (h->URI && h->part && h->part->name && h->part->type) 363 h->name = types.aname(NULL, h->URI, h->part->name); 364 else 365 { fprintf(stderr, "Error in SOAP Header part definition: output part '%s' missing?\n", h->part && h->part->name ? h->part->name : "?"); 366 h->name = ""; 367 } 368 h->encodingStyle = (*header).encodingStyle; 369 h->style = document; // irrelevant 370 h->use = (*header).use; 371 h->multipartRelated = NULL; 372 h->content = NULL; 373 h->layout = NULL; 374 h->ext_documentation = NULL; // TODO: add document content 375 h->documentation = NULL; // TODO: add document content 376 s->header[h->name] = h; 377 for (vector<soap__headerfault>::const_iterator headerfault = (*header).headerfault.begin(); headerfault != (*header).headerfault.end(); ++headerfault) 378 { // TODO: headerfault processing. This is rarely used. 379 } 380 } 381 } 382 // collect faults 383 for (vector<wsdl__ext_fault>::const_iterator ext_fault = (*operation).fault.begin(); ext_fault != (*operation).fault.end(); ++ext_fault) 384 { if ((*ext_fault).soap__fault_ && (*ext_fault).messagePtr()) 385 { Message *f = new Message(); 386 f->message = (*ext_fault).messagePtr(); 387 f->body_parts = NULL; 388 f->part = NULL; 389 f->encodingStyle = (*ext_fault).soap__fault_->encodingStyle; 390 f->action = NULL; 391 f->URI = (*ext_fault).soap__fault_->namespace_; 392 f->style = document; // irrelevant 393 f->use = (*ext_fault).soap__fault_->use; 394 if (f->use == literal && !f->URI) 395 f->URI = s->URI; // must have a unique URI 396 f->multipartRelated = NULL; 397 f->content = NULL; 398 f->layout = NULL; 399 f->ext_documentation = (*ext_fault).documentation; 400 f->name = types.aname("_", f->URI, f->message->name); 401 f->documentation = f->message->documentation; 402 o->fault.push_back(f); 403 s->fault[f->name] = f; 404 } 405 else 406 fprintf(stderr, "Error: no wsdl:definitions/binding/operation/fault/soap:fault\n"); 407 } 408 s->operation.push_back(o); 409 } 410 else 411 fprintf(stderr, "Warning: no SOAP RPC operation namespace, operations will be ignored\n"); 412 } 413 else 414 fprintf(stderr, "Error: no wsdl:definitions/binding/operation/input/soap:body\n"); 415 } 416 else 417 fprintf(stderr, "Error: no wsdl:definitions/portType/operation/input\n"); 418 } 419 else 420 fprintf(stderr, "Error: no wsdl:definitions/portType/operation\n"); 421 } 422 } 423} 424 425void Definitions::compile(const wsdl__definitions& definitions) 426{ // compile the definitions and generate gSOAP header file 427 const char *defs; 428 if (definitions.name) 429 defs = types.aname(NULL, NULL, definitions.name); 430 else 431 defs = "Service"; 432 ident(); 433 fprintf(stream, "/* NOTE:\n\n - Compile this file with soapcpp2 to complete the code generation process.\n - Use soapcpp2 option -I to specify paths for #import\n To build with STL, 'stlvector.h' is imported from 'import' dir in package.\n - Use wsdl2h options -c and -s to generate pure C code or C++ code without STL.\n - Use 'typemap.dat' to control namespace bindings and type mappings.\n It is strongly recommended to customize the names of the namespace prefixes\n generated by wsdl2h. To do so, modify the prefix bindings in the Namespaces\n section below and add the modified lines to 'typemap.dat' to rerun wsdl2h.\n - Use Doxygen (www.doxygen.org) to browse this file.\n - Use wsdl2h option -l to view the software license terms.\n\n DO NOT include this file directly into your project.\n Include only the soapcpp2-generated headers and source code files.\n*/\n"); 434 // gsoap compiler options: 'w' disables WSDL/schema output to avoid file collisions 435 if (cflag) 436 fprintf(stream, "\n//gsoapopt cw\n"); 437 else 438 fprintf(stream, "\n//gsoapopt w\n"); 439 banner(definitions.targetNamespace?definitions.targetNamespace:"targetNamespace"); 440 // copy documentation from WSDL definitions 441 if (definitions.documentation) 442 { fprintf(stream, "/* WSDL Documentation:\n\n"); 443 text(definitions.documentation); 444 fprintf(stream, "*/\n\n"); 445 } 446 if (lflag) 447 { banner("License"); 448 fprintf(stream, "/*\n%s*/\n\n", licensenotice); 449 } 450 if (definitions.version) 451 { banner("Version"); 452 fprintf(stream, "#define SOAP_WSDL_VERSION \"%s\"\n", definitions.version); 453 } 454 banner("Import"); 455 if (dflag) 456 { fprintf(stream, "\n// dom.h declares the DOM xsd__anyType object (compiler and link with dom.cpp)\n"); 457 fprintf(stream, "#import \"dom.h\"\n"); 458 } 459 if (!cflag && !sflag) 460 { fprintf(stream, "\n// STL vector containers (use option -s to disable)\n"); 461 fprintf(stream, "#import \"stlvector.h\"\n"); 462 } 463 if (mflag) 464 { fprintf(stream, "#import \""); 465 fprintf(stream, "xsd.h\"\t// import primitive XSD types.\n"); 466 } 467 for (SetOfString::const_iterator u = exturis.begin(); u != exturis.end(); ++u) 468 { bool found = false; 469 size_t n = strlen(*u); 470 for (SetOfString::const_iterator i = definitions.builtinTypes().begin(); i != definitions.builtinTypes().end(); ++i) 471 { if (**i == '"' && !strncmp(*u, *i + 1, n)) 472 { found = true; 473 break; 474 } 475 } 476 if (!found) 477 { for (SetOfString::const_iterator j = definitions.builtinElements().begin(); j != definitions.builtinElements().end(); ++j) 478 { if (**j == '"' && !strncmp(*u, *j + 1, n)) 479 { found = true; 480 break; 481 } 482 } 483 } 484 if (!found) 485 { for (SetOfString::const_iterator k = definitions.builtinAttributes().begin(); k != definitions.builtinAttributes().end(); ++k) 486 { if (**k == '"' && !strncmp(*u, *k + 1, n)) 487 { found = true; 488 break; 489 } 490 } 491 } 492 if (found) 493 { if (vflag) 494 fprintf(stderr, "import %s\n", *u); 495 fprintf(stream, "#import \"%s.h\"\t// %s = <%s>\n", types.nsprefix(NULL, *u), types.nsprefix(NULL, *u), *u); 496 } 497 } 498 banner("Schema Namespaces"); 499 // determine if we must use SOAP 1.2, this is a bit of a hack due to the lack of WSDL1.1/SOAP1.2 support and better alternatives 500 for (Namespace *p = definitions.soap->local_namespaces; p && p->id; p++) 501 { // p->out is set to the actual namespace name that matches the p->in pattern 502 if (p->out && !strcmp(p->id, "soap") && !strcmp(p->out, "http://schemas.xmlsoap.org/wsdl/soap12/")) 503 { fprintf(stream, "// This service uses SOAP 1.2 namespaces:\n"); 504 fprintf(stream, schemaformat, "SOAP-ENV", "namespace", "http://www.w3.org/2003/05/soap-envelope"); 505 fprintf(stream, schemaformat, "SOAP-ENC", "namespace", "http://www.w3.org/2003/05/soap-encoding"); 506 break; 507 } 508 } 509 if (definitions.types) 510 { fprintf(stream, "\n/* NOTE:\n\nIt is strongly recommended to customize the names of the namespace prefixes\ngenerated by wsdl2h. To do so, modify the prefix bindings below and add the\nmodified lines to typemap.dat to rerun wsdl2h:\n\n"); 511 if (definitions.targetNamespace && *definitions.targetNamespace) 512 fprintf(stream, "%s = \"%s\"\n", types.nsprefix(service_prefix, definitions.targetNamespace), definitions.targetNamespace); 513 for (vector<xs__schema*>::const_iterator schema1 = definitions.types->xs__schema_.begin(); schema1 != definitions.types->xs__schema_.end(); ++schema1) 514 if (!definitions.targetNamespace || strcmp((*schema1)->targetNamespace, definitions.targetNamespace)) 515 fprintf(stream, "%s = \"%s\"\n", types.nsprefix(NULL, (*schema1)->targetNamespace), (*schema1)->targetNamespace); 516 fprintf(stream, "\n*/\n\n"); 517 for (vector<xs__schema*>::const_iterator schema2 = definitions.types->xs__schema_.begin(); schema2 != definitions.types->xs__schema_.end(); ++schema2) 518 fprintf(stream, schemaformat, types.nsprefix(NULL, (*schema2)->targetNamespace), "namespace", (*schema2)->targetNamespace); 519 for (vector<xs__schema*>::const_iterator schema3 = definitions.types->xs__schema_.begin(); schema3 != definitions.types->xs__schema_.end(); ++schema3) 520 { if ((*schema3)->elementFormDefault == (*schema3)->attributeFormDefault) 521 fprintf(stream, schemaformat, types.nsprefix(NULL, (*schema3)->targetNamespace), "form", (*schema3)->elementFormDefault == qualified ? "qualified" : "unqualified"); 522 else 523 { fprintf(stream, schemaformat, types.nsprefix(NULL, (*schema3)->targetNamespace), "elementForm", (*schema3)->elementFormDefault == qualified ? "qualified" : "unqualified"); 524 fprintf(stream, schemaformat, types.nsprefix(NULL, (*schema3)->targetNamespace), "attributeForm", (*schema3)->attributeFormDefault == qualified ? "qualified" : "unqualified"); 525 } 526 } 527 } 528 banner("Schema Types"); 529 // generate the prototypes first: these should allow use before def, e.g. class names then generate the defs 530 // check if xsd:anyType is used 531 if (!cflag && !pflag) 532 { for (SetOfString::const_iterator i = definitions.builtinTypes().begin(); i != definitions.builtinTypes().end(); ++i) 533 { if (!cflag && !strcmp(*i, "xs:anyType")) 534 { pflag = 1; 535 break; 536 } 537 } 538 } 539 if (dflag && pflag) 540 { fprintf(stderr, "\nWarning -d option: -p option disabled and xsd__anyType base class removed.\nUse run-time SOAP_DOM_NODE flag to deserialize class instances into DOM nodes.\n"); 541 fprintf(stream, "\n/*\nWarning -d option used: -p option disabled and xsd:anyType base class removed.\nUse run-time SOAP_DOM_NODE flag to deserialize class instances into DOM nodes.\nA DOM node is represented by the xsd__anyType object implemented in dom.cpp.\n*/\n\n"); 542 pflag = 0; 543 } 544 // define xsd:anyType first, if used 545 if (!cflag && pflag) 546 { const char *s, *t; 547 t = types.cname(NULL, NULL, "xs:anyType"); 548 s = types.deftypemap[t]; 549 if (s) 550 { if (*s) 551 { if (!mflag) 552 fprintf(stream, "%s\n", s); 553 } 554 s = types.usetypemap[t]; 555 if (s) 556 { if (mflag) 557 fprintf(stream, "// xsd.h: should define type %s\n", s); 558 types.knames.insert(s); 559 } 560 } 561 else 562 { fprintf(stderr, "Error: no xsd__anyType defined in type map\n"); 563 pflag = 0; 564 } 565 } 566 // produce built-in primitive types, limited to the ones that are used only 567 if (vflag) 568 fprintf(stderr, "\nGenerating built-in types\n"); 569 for (SetOfString::const_iterator i = definitions.builtinTypes().begin(); i != definitions.builtinTypes().end(); ++i) 570 { const char *s, *t; 571 if (!cflag && !strcmp(*i, "xs:anyType")) 572 continue; 573 t = types.cname(NULL, NULL, *i); 574 s = types.deftypemap[t]; 575 if (s) 576 { if (*s) 577 { if (**i == '"') 578 fprintf(stream, "\n/// Imported type %s from typemap %s.\n", *i, mapfile?mapfile:""); 579 else 580 fprintf(stream, "\n/// Built-in type \"%s\".\n", *i); 581 if (mflag) 582 fprintf(stream, "// (declaration of %s removed by option -m)\n", t); 583 else 584 types.format(s); 585 } 586 s = types.usetypemap[t]; 587 if (s && *s) 588 { if (mflag && **i != '"') 589 fprintf(stream, "\n// xsd.h: typemap override of type %s with %s\n", t, s); 590 if (types.knames.find(s) == types.knames.end()) 591 types.knames.insert(s); 592 } 593 } 594 else 595 { if (!mflag) 596 { if (**i == '"') 597 fprintf(stream, "\n// Imported type %s defined by %s\n", *i, t); 598 else 599 { s = types.tname(NULL, NULL, "xsd:string"); 600 fprintf(stream, "\n/// Primitive built-in type \"%s\"\n", *i); 601 fprintf(stream, "typedef %s %s;\n", s, t); 602 types.deftname(TYPEDEF, NULL, strchr(s, '*') != NULL, NULL, NULL, *i); 603 } 604 } 605 else if (**i == '"') 606 fprintf(stream, "\n// Imported type %s defined by %s\n", *i, t); 607 else 608 fprintf(stream, "\n// xsd.h: should define type %s\n", t); 609 types.deftname(TYPEDEF, NULL, false, NULL, NULL, *i); 610 } 611 if (pflag && !strncmp(*i, "xs:", 3)) // only xsi types are polymorph 612 { s = types.aname(NULL, NULL, *i); 613 if (!mflag) 614 { fprintf(stream, "\n/// Class wrapper for built-in type \"%s\" derived from xsd__anyType\n", *i); 615 fprintf(stream, "class %s : public xsd__anyType\n{ public:\n", s); 616 fprintf(stream, elementformat, types.tname(NULL, NULL, *i), "__item;"); 617 fprintf(stream, "\n};\n"); 618 } 619 types.knames.insert(s); 620 } 621 } 622 // produce built-in primitive elements, limited to the ones that are used only 623 if (vflag) 624 fprintf(stderr, "\nGenerating built-in elements\n"); 625 for (SetOfString::const_iterator j = definitions.builtinElements().begin(); j != definitions.builtinElements().end(); ++j) 626 { const char *s, *t; 627 t = types.cname("_", NULL, *j); 628 s = types.deftypemap[t]; 629 if (s) 630 { if (*s) 631 { if (**j == '"') 632 fprintf(stream, "\n/// Imported element %s from typemap %s.\n", *j, mapfile?mapfile:""); 633 else 634 fprintf(stream, "\n/// Built-in element \"%s\".\n", *j); 635 if (mflag) 636 fprintf(stream, "// (declaration of %s removed by option -m)\n", t); 637 else 638 types.format(s); 639 } 640 s = types.usetypemap[t]; 641 if (s && *s) 642 { if (mflag && **j != '"') 643 fprintf(stream, "\n// xsd.h: typemap override of element %s with %s\n", t, s); 644 if (types.knames.find(s) == types.knames.end()) 645 types.knames.insert(s); 646 } 647 } 648 else 649 { if (!mflag) 650 { if (**j == '"') 651 fprintf(stream, "\n// Imported element %s declared as %s\n", *j, t); 652 else 653 { fprintf(stream, "\n/// Built-in element \"%s\".\n", *j); 654 fprintf(stream, "typedef _XML %s;\n", t); 655 types.deftname(TYPEDEF, NULL, true, "_", NULL, *j); // already pointer 656 } 657 } 658 else if (**j == '"') 659 fprintf(stream, "\n// Imported element %s declared as %s\n", *j, t); 660 else 661 fprintf(stream, "\n// xsd.h: should define element %s\n", t); 662 types.deftname(TYPEDEF, NULL, false, "_", NULL, *j); 663 } 664 } 665 // produce built-in primitive attributes, limited to the ones that are used only 666 if (vflag) 667 fprintf(stderr, "\nGenerating built-in attributes\n"); 668 for (SetOfString::const_iterator k = definitions.builtinAttributes().begin(); k != definitions.builtinAttributes().end(); ++k) 669 { const char *s, *t; 670 t = types.cname("_", NULL, *k); 671 s = types.deftypemap[t]; 672 if (s) 673 { if (*s) 674 { if (**k == '"') 675 fprintf(stream, "\n/// Imported attribute %s from typemap %s.\n", *k, mapfile?mapfile:""); 676 else 677 fprintf(stream, "\n/// Built-in attribute \"%s\".\n", *k); 678 if (mflag) 679 fprintf(stream, "// (declaration of %s removed by option -m)\n", t); 680 else 681 types.format(s); 682 } 683 s = types.usetypemap[t]; 684 if (s && *s) 685 { if (mflag && **k != '"') 686 fprintf(stream, "\n// xsd.h: typemap override of attribute %s with %s\n", t, s); 687 if (types.knames.find(s) == types.knames.end()) 688 types.knames.insert(s); 689 } 690 } 691 else 692 { s = types.tname(NULL, NULL, "xsd:string"); 693 if (!mflag) 694 { if (**k == '"') 695 fprintf(stream, "\n// Imported attribute %s declared as %s\n", *k, t); 696 else 697 { fprintf(stream, "\n/// Built-in attribute \"%s\".\n", *k); 698 fprintf(stream, "typedef %s %s;\n", s, t); 699 } 700 } 701 else if (**k == '"') 702 fprintf(stream, "// Imported attribute %s declared as %s\n", *k, t); 703 else 704 fprintf(stream, "// xsd.h: should define attribute %s\n", t); 705 types.deftname(TYPEDEF, NULL, strchr(s, '*') != NULL, "_", NULL, *k); 706 } 707 } 708 // produce types 709 // define class/struct types first 710 if (definitions.types) 711 { comment("Definitions", defs, "types", definitions.types->documentation); 712 fprintf(stream, "\n"); 713 for (vector<xs__schema*>::const_iterator schema4 = definitions.types->xs__schema_.begin(); schema4 != definitions.types->xs__schema_.end(); ++schema4) 714 { if (vflag) 715 fprintf(stderr, "\nDefining types in %s\n", (*schema4)->targetNamespace); 716 for (vector<xs__complexType>::const_iterator complexType = (*schema4)->complexType.begin(); complexType != (*schema4)->complexType.end(); ++complexType) 717 types.define((*schema4)->targetNamespace, NULL, *complexType); 718 if (vflag) 719 fprintf(stderr, "\nDefining elements in %s\n", (*schema4)->targetNamespace); 720 for (vector<xs__element>::const_iterator element = (*schema4)->element.begin(); element != (*schema4)->element.end(); ++element) 721 { if (!(*element).type && !(*element).abstract) 722 { if ((*element).complexTypePtr()) 723 types.define((*schema4)->targetNamespace, (*element).name, *(*element).complexTypePtr()); 724 else if (!(*element).simpleTypePtr()) 725 { fprintf(stream, "\n/// Element \"%s\":%s.\n", (*schema4)->targetNamespace, (*element).name); 726 if (gflag) 727 { const char *t = types.deftname(TYPEDEF, NULL, false, "_", (*schema4)->targetNamespace, (*element).name); 728 if (t) 729 fprintf(stream, "typedef _XML %s;\n", t); 730 else 731 fprintf(stream, "// Element definition intentionally left blank.\n"); 732 } 733 else 734 { const char *s = types.cname("_", (*schema4)->targetNamespace, (*element).name); 735 types.ptrtypemap[s] = types.usetypemap[s] = "_XML"; 736 fprintf(stream, "/// Note: use wsdl2h option -g to generate this global element declaration.\n"); 737 } 738 } 739 } 740 } 741 } 742 // visit types with lowest base level first 743 int baseLevel = 1; 744 bool found; 745 do 746 { found = (baseLevel == 1); 747 for (vector<xs__schema*>::iterator schema = definitions.types->xs__schema_.begin(); schema != definitions.types->xs__schema_.end(); ++schema) 748 { for (vector<xs__simpleType>::iterator simpleType = (*schema)->simpleType.begin(); simpleType != (*schema)->simpleType.end(); ++simpleType) 749 { if ((*simpleType).baseLevel() == baseLevel) 750 { found = true; 751 types.gen((*schema)->targetNamespace, NULL, *simpleType, false); 752 } 753 } 754 for (vector<xs__element>::iterator element = (*schema)->element.begin(); element != (*schema)->element.end(); ++element) 755 { if (!(*element).type && (*element).simpleTypePtr() && (*element).simpleTypePtr()->baseLevel() == baseLevel) 756 { found = true; 757 if ((*element).type) 758 fprintf(stream, "/// Element \"%s\":%s of simpleType %s.\n", (*schema)->targetNamespace, (*element).name, (*element).type); 759 types.document((*element).annotation); 760 types.gen((*schema)->targetNamespace, (*element).name, *(*element).simpleTypePtr(), false); 761 } 762 if (!(*element).type && (*element).complexTypePtr() && (*element).complexTypePtr()->baseLevel() == baseLevel) 763 found = true; 764 } 765 for (vector<xs__attribute>::const_iterator attribute = (*schema)->attribute.begin(); attribute != (*schema)->attribute.end(); ++attribute) 766 { if (!(*attribute).type && (*attribute).simpleTypePtr() && (*attribute).simpleTypePtr()->baseLevel() == baseLevel) 767 { found = true; 768 if ((*attribute).type) 769 fprintf(stream, "/// Attribute \"%s\":%s of simpleType %s.\n", (*schema)->targetNamespace, (*attribute).name, (*attribute).type); 770 types.document((*attribute).annotation); 771 types.gen((*schema)->targetNamespace, (*attribute).name, *(*attribute).simpleTypePtr(), false); // URI = NULL won't generate type in schema (type without namespace qualifier) 772 } 773 } 774 for (vector<xs__complexType>::iterator complexType = (*schema)->complexType.begin(); complexType != (*schema)->complexType.end(); ++complexType) 775 { if ((*complexType).baseLevel() == baseLevel) 776 found = true; 777 } 778 } 779 ++baseLevel; 780 } while (found); 781 // generate complex type defs. Problem: what if a simpleType restriction/extension depends on a complexType simpleContent restriction/extension? 782 int maxLevel = baseLevel; 783 for (baseLevel = 1; baseLevel < maxLevel; ++baseLevel) 784 { for (vector<xs__schema*>::iterator schema = definitions.types->xs__schema_.begin(); schema != definitions.types->xs__schema_.end(); ++schema) 785 { for (vector<xs__complexType>::iterator complexType = (*schema)->complexType.begin(); complexType != (*schema)->complexType.end(); ++complexType) 786 { if ((*complexType).baseLevel() == baseLevel) 787 types.gen((*schema)->targetNamespace, NULL, *complexType, false); 788 } 789 for (vector<xs__element>::iterator element = (*schema)->element.begin(); element != (*schema)->element.end(); ++element) 790 { if (!(*element).type && (*element).complexTypePtr() && (*element).complexTypePtr()->baseLevel() == baseLevel) 791 { fprintf(stream, "\n\n/// Element \"%s\":%s of complexType.\n", (*schema)->targetNamespace, (*element).name); 792 types.document((*element).annotation); 793 types.gen((*schema)->targetNamespace, (*element).name, *(*element).complexTypePtr(), false); 794 } 795 } 796 } 797 } 798 // option to consider: generate local complexTypes iteratively 799 /* 800 for (MapOfStringToType::const_iterator local = types.locals.begin(); local != types.locals.end(); ++local) 801 { types.gen(NULL, (*local).first, *(*local).second); 802 } 803 */ 804 for (vector<xs__schema*>::iterator schema = definitions.types->xs__schema_.begin(); schema != definitions.types->xs__schema_.end(); ++schema) 805 { if (vflag) 806 fprintf(stderr, "\nGenerating elements in %s\n", (*schema)->targetNamespace); 807 for (vector<xs__element>::iterator element = (*schema)->element.begin(); element != (*schema)->element.end(); ++element) 808 { if ((*element).name && (*element).type && !(*element).abstract) 809 { fprintf(stream, "\n/// Element \"%s\":%s of type %s.\n", (*schema)->targetNamespace, (*element).name, (*element).type); 810 types.document((*element).annotation); 811 if (!types.is_defined("_", (*schema)->targetNamespace, (*element).name)) 812 { const char *s = types.tname(NULL, (*schema)->targetNamespace, (*element).type); 813 const char *t = types.deftname(TYPEDEF, NULL, false, "_", (*schema)->targetNamespace, (*element).name); 814 if (gflag) 815 { if (strncmp(s, "char", 4) && strchr(s, '*')) // don't want pointer typedef, unless char* 816 { size_t n = strlen(s); 817 char *r = (char*)malloc(n); 818 strncpy(r, s, n - 1); 819 r[n - 1] = '\0'; 820 fprintf(stream, "typedef %s %s;\n", r, t); 821 free(r); 822 } 823 else 824 fprintf(stream, "typedef %s %s;\n", s, t); 825 } 826 else 827 fprintf(stream, "/// Note: use wsdl2h option -g to generate this global element declaration.\n"); 828 } 829 else 830 { const char *s = types.cname("_", (*schema)->targetNamespace, (*element).name); 831 const char *t = types.deftypemap[s]; 832 if (t && *t) 833 { fprintf(stream, "/// Imported element %s from typemap %s.\n", s, mapfile?mapfile:""); 834 types.format(t); 835 } 836 else 837 fprintf(stream, "// '%s' element definition intentionally left blank.\n", types.cname("_", (*schema)->targetNamespace, (*element).name)); 838 } 839 } 840 } 841 if (vflag) 842 fprintf(stderr, "\nGenerating attributes in %s\n", (*schema)->targetNamespace); 843 for (vector<xs__attribute>::iterator attribute = (*schema)->attribute.begin(); attribute != (*schema)->attribute.end(); ++attribute) 844 { if ((*attribute).name && (*attribute).type) 845 { fprintf(stream, "\n/// Attribute \"%s\":%s of simpleType %s.\n", (*schema)->targetNamespace, (*attribute).name, (*attribute).type); 846 types.document((*attribute).annotation); 847 if (!types.is_defined("_", (*schema)->targetNamespace, (*attribute).name)) 848 { const char *s = types.tname(NULL, (*schema)->targetNamespace, (*attribute).type); 849 const char *t = types.deftname(TYPEDEF, NULL, false, "_", (*schema)->targetNamespace, (*attribute).name); 850 if (gflag) 851 { if (strncmp(s, "char", 4) && strchr(s, '*')) // don't want pointer typedef, unless char* 852 { size_t n = strlen(s); 853 char *r = (char*)malloc(n); 854 strncpy(r, s, n - 1); 855 r[n - 1] = '\0'; 856 fprintf(stream, "typedef %s %s;\n", r, t); 857 free(r); 858 } 859 else 860 fprintf(stream, "typedef %s %s;\n", s, t); 861 } 862 else 863 fprintf(stream, "/// Note: use wsdl2h option -g to generate this global attribute declaration.\n"); 864 } 865 else 866 { const char *s = types.cname("_", (*schema)->targetNamespace, (*attribute).name); 867 const char *t = types.deftypemap[s]; 868 if (t && *t) 869 { fprintf(stream, "/// Imported attribute %s from typemap %s.\n", s, mapfile?mapfile:""); 870 types.format(t); 871 } 872 else 873 fprintf(stream, "// '%s' attribute definition intentionally left blank.\n", types.cname("_", (*schema)->targetNamespace, (*attribute).name)); 874 } 875 } 876 } 877 } 878 } 879 if (vflag) 880 fprintf(stderr, "\nCollecting service bindings"); 881 collect(definitions); 882 if (!services.empty()) 883 { banner("Services"); 884 for (MapOfStringToService::const_iterator service1 = services.begin(); service1 != services.end(); ++service1) 885 { Service *sv = (*service1).second; 886 if (sv && sv->prefix) 887 { fprintf(stream, "\n"); 888 if (sv->name) 889 fprintf(stream, serviceformat, sv->prefix, "name", sv->name, ""); 890 if (sv->type) 891 fprintf(stream, serviceformat, sv->prefix, "type", sv->type, ""); 892 for (SetOfString::const_iterator port = sv->location.begin(); port != sv->location.end(); ++port) 893 fprintf(stream, serviceformat, sv->prefix, "port", (*port), ""); 894 if (sv->URI) 895 fprintf(stream, serviceformat, sv->prefix, "namespace", sv->URI, ""); 896 if (sv->transport) 897 fprintf(stream, serviceformat, sv->prefix, "transport", sv->transport, ""); 898 } 899 } 900 fprintf(stream, "\n/** @mainpage %s Definitions\n", definitions.name?definitions.name:"Service"); 901 if (definitions.version) 902 { section(defs, "_version Version", NULL); 903 text(definitions.version); 904 } 905 if (definitions.documentation) 906 { section(defs, "_documentation Documentation", NULL); 907 text(definitions.documentation); 908 } 909 if (definitions.types && definitions.types->documentation) 910 { section(defs, "_types Types", NULL); 911 text(definitions.types->documentation); 912 } 913 section(defs, "_bindings Bindings", NULL); 914 for (MapOfStringToService::const_iterator service2 = services.begin(); service2 != services.end(); ++service2) 915 { Service *sv = (*service2).second; 916 if (sv && sv->name) 917 fprintf(stream, " - @ref %s\n", sv->name); 918 } 919 fprintf(stream, "\n*/\n"); 920 for (MapOfStringToService::const_iterator service3 = services.begin(); service3 != services.end(); ++service3) 921 { Service *sv = (*service3).second; 922 if (sv && sv->name) 923 { fprintf(stream, "\n/**\n"); 924 page(sv->name, " Binding", sv->name); 925 for (MapOfStringToString::const_iterator service_doc = sv->service_documentation.begin(); service_doc != sv->service_documentation.end(); ++service_doc) 926 { const char *name = types.aname(NULL, NULL, (*service_doc).first); 927 section(name, "_service Service Documentation", (*service_doc).first); 928 text((*service_doc).second); 929 } 930 for (MapOfStringToString::const_iterator port_doc = sv->port_documentation.begin(); port_doc != sv->port_documentation.end(); ++port_doc) 931 { const char *name = types.aname(NULL, NULL, (*port_doc).first); 932 section(name, "_port Port Documentation", (*port_doc).first); 933 text((*port_doc).second); 934 } 935 for (MapOfStringToString::const_iterator binding_doc = sv->binding_documentation.begin(); binding_doc != sv->binding_documentation.end(); ++binding_doc) 936 { const char *name = types.aname(NULL, NULL, (*binding_doc).first); 937 section(name, "_binding Binding Documentation", (*binding_doc).first); 938 text((*binding_doc).second); 939 } 940 section(sv->name, "_operations Operations of Binding ", sv->name); 941 for (vector<Operation*>::const_iterator op = sv->operation.begin(); op != sv->operation.end(); ++op) 942 { if (*op && (*op)->input_name) 943 fprintf(stream, " - @ref %s\n", (*op)->input_name); 944 } 945 section((*sv).name, "_ports Endpoints of Binding ", sv->name); 946 for (SetOfString::const_iterator port = sv->location.begin(); port != sv->location.end(); ++port) 947 fprintf(stream, " - %s\n", *port); 948 fprintf(stream, "\nNote: use wsdl2h option -N to change the service binding prefix name\n\n*/\n"); 949 } 950 } 951 } 952 generate(); 953 if (cppnamespace) 954 fprintf(stream, "\n} // namespace %s\n", cppnamespace); 955 fprintf(stream, "\n/* End of %s */\n", outfile?outfile:"file"); 956} 957 958void Definitions::generate() 959{ MapOfStringToMessage headers; 960 MapOfStringToMessage faults; 961 const char *t; 962 for (MapOfStringToService::const_iterator service1 = services.begin(); service1 != services.end(); ++service1) 963 { if ((*service1).second) 964 { for (MapOfStringToMessage::const_iterator header = (*service1).second->header.begin(); header != (*service1).second->header.end(); ++header) 965 headers[(*header).first] = (*header).second; 966 for (MapOfStringToMessage::const_iterator fault = (*service1).second->fault.begin(); fault != (*service1).second->fault.end(); ++fault) 967 faults[(*fault).first] = (*fault).second; 968 } 969 } 970 // Generate SOAP Header definition 971 t = types.deftypemap["SOAP_ENV__Header"]; 972 if (t && *t) 973 { banner("Custom SOAP Header"); 974 types.format(t); 975 } 976 else if (!jflag && !headers.empty()) 977 { banner("SOAP Header"); 978 fprintf(stream, "/**\n\nThe SOAP Header is part of the gSOAP context and its content is accessed\nthrough the soap.header variable. You may have to set the soap.actor variable\nto serialize SOAP Headers with SOAP-ENV:actor or SOAP-ENV:role attributes.\nUse option -j to remove entire SOAP Header definition.\nUse option -k to remove the mustUnderstand qualifiers.\n\n*/\n"); 979 fprintf(stream, "struct SOAP_ENV__Header\n{\n"); 980 for (MapOfStringToMessage::const_iterator header = headers.begin(); header != headers.end(); ++header) 981 { if ((*header).second->URI && !types.uris[(*header).second->URI]) 982 fprintf(stream, schemaformat, types.nsprefix(NULL, (*header).second->URI), "namespace", (*header).second->URI); 983 comment("Header", (*header).first, "WSDL", (*header).second->ext_documentation); 984 comment("Header", (*header).first, "SOAP", (*header).second->documentation); 985 if (!kflag) 986 { fprintf(stream, elementformat, "mustUnderstand", "// must be understood by receiver"); 987 fprintf(stream, "\n"); 988 } 989 if ((*header).second->part && (*header).second->part->elementPtr()) 990 { fprintf(stream, "/// \"%s\" SOAP Header part element\n", (*header).second->part->name); 991 if ((*header).second->part->elementPtr()->type && (*header).second->part->element) 992 fprintf(stream, elementformat, types.pname(true, NULL, NULL, (*header).second->part->elementPtr()->type), types.aname(NULL, NULL, (*header).second->part->element)); 993 else if ((*header).second->part->element) 994 fprintf(stream, elementformat, types.pname(true, "_", NULL, (*header).second->part->element), types.aname(NULL, NULL, (*header).second->part->element)); 995 else 996 fprintf(stream, elementformat, types.pname(true, "_", NULL, (*header).second->part->elementPtr()->name), (*header).first); 997 fprintf(stream, ";\n"); 998 } 999 else if ((*header).second->part && (*header).second->part->type) 1000 { fprintf(stream, "/// \"%s\" SOAP Header part type\n", (*header).second->part->type); 1001 fprintf(stream, elementformat, types.pname(true, NULL, NULL, (*header).second->part->type), types.aname(NULL, (*header).second->URI, (*header).second->part->name)); 1002 fprintf(stream, ";\n"); 1003 } 1004 else 1005 { if ((*header).second->part && (*header).second->part->element) 1006 fprintf(stream, elementformat, types.pname(true, "_", NULL, (*header).second->part->element), (*header).first); 1007 else 1008 fprintf(stream, pointerformat, (*header).first, (*header).first); 1009 fprintf(stream, ";\t///< TODO: Please check element name and type (imported type)\n"); 1010 } 1011 } 1012 types.modify("SOAP_ENV__Header"); 1013 fprintf(stream, "\n};\n"); 1014 } 1015 // Generate Fault detail element definitions 1016 for (MapOfStringToMessage::const_iterator fault = faults.begin(); fault != faults.end(); ++fault) 1017 { if ((*fault).second->use == encoded) 1018 { banner("SOAP Fault Detail Message"); 1019 fprintf(stream, "/// SOAP Fault detail message \"%s:%s\"\n", (*fault).second->URI, (*fault).second->message->name); 1020 comment("Fault", (*fault).first, "WSDL", (*fault).second->ext_documentation); 1021 comment("Fault", (*fault).first, "SOAP", (*fault).second->documentation); 1022 if (cflag) 1023 fprintf(stream, "struct %s\n{", (*fault).first); 1024 else 1025 fprintf(stream, "class %s\n{ public:", (*fault).first); 1026 (*fault).second->generate(types, ";", false, true, false); 1027 if (!cflag) 1028 { fprintf(stream, "\n"); 1029 fprintf(stream, pointerformat, "struct soap", "soap"); 1030 fprintf(stream, ";"); 1031 } 1032 fprintf(stream, "\n};\n"); 1033 if (cflag) 1034 fprintf(stream, "typedef struct %s %s;\n", (*fault).first, (*fault).first); 1035 if ((*fault).second->URI && !types.uris[(*fault).second->URI]) 1036 fprintf(stream, schemaformat, types.nsprefix(NULL, (*fault).second->URI), "namespace", (*fault).second->URI); 1037 } 1038 } 1039 t = types.deftypemap["SOAP_ENV__Detail"]; 1040 if (t && *t) 1041 { banner("Custom SOAP Detail"); 1042 types.format(t); 1043 } 1044 else if (!jflag && !faults.empty()) 1045 { SetOfString fault_elements; 1046 banner("SOAP Fault Detail"); 1047 fprintf(stream, "/**\n\nThe SOAP Fault is part of the gSOAP context and its content is accessed\nthrough the soap.fault->detail variable (SOAP 1.1) or the\nsoap.fault->SOAP_ENV__Detail variable (SOAP 1.2).\nUse option -j to omit.\n\n*/\n"); 1048 fprintf(stream, "struct SOAP_ENV__Detail\n{\n"); 1049 types.modify("SOAP_ENV__Detail"); 1050 for (MapOfStringToMessage::const_iterator fault = faults.begin(); fault != faults.end(); ++fault) 1051 { if ((*fault).second->URI && !types.uris[(*fault).second->URI]) 1052 fprintf(stream, schemaformat, types.nsprefix(NULL, (*fault).second->URI), "namespace", (*fault).second->URI); 1053 comment("Fault", (*fault).first, "WSDL", (*fault).second->ext_documentation); 1054 comment("Fault", (*fault).first, "SOAP", (*fault).second->documentation); 1055 if ((*fault).second->use == literal) 1056 { for (vector<wsdl__part>::const_iterator part = (*fault).second->message->part.begin(); part != (*fault).second->message->part.end(); ++part) 1057 { if ((*part).elementPtr()) 1058 { if (fault_elements.find((*part).element) == fault_elements.end()) 1059 { if ((*part).elementPtr()->type) 1060 fprintf(stream, elementformat, types.pname(true, NULL, NULL, (*part).elementPtr()->type), types.aname(NULL, (*fault).second->URI, (*part).element)); 1061 else 1062 fprintf(stream, elementformat, types.pname(true, "_", NULL, (*part).element), types.aname(NULL, (*fault).second->URI, (*part).element)); 1063 fprintf(stream, ";\n"); 1064 fault_elements.insert((*part).element); 1065 } 1066 fprintf(stream, "///< SOAP Fault element \"%s\" part \"%s\"\n", (*part).element?(*part).element:"", (*part).name?(*part).name:""); 1067 } 1068 else if ((*part).name && (*part).type) 1069 { if (fault_elements.find((*part).name) == fault_elements.end()) 1070 { fprintf(stream, elementformat, types.pname(true, NULL, NULL, (*part).type), types.aname("_", (*fault).second->URI, (*part).name)); 1071 fprintf(stream, ";\n"); 1072 fault_elements.insert((*part).name); 1073 } 1074 fprintf(stream, "///< SOAP Fault type \"%s\" part \"%s\"\n", (*part).type, (*part).name); 1075 } 1076 else 1077 fprintf(stream, "// Unknown SOAP Fault element \"%s\" part \"%s\"\n", (*fault).second->message->name, (*part).name?(*part).name:""); 1078 } 1079 } 1080 else 1081 { fprintf(stream, pointerformat, (*fault).first, types.aname(NULL, (*fault).second->URI, (*fault).second->message->name)); 1082 fprintf(stream, ";\t///< SOAP Fault detail message \"%s\":%s\n", (*fault).second->URI, (*fault).second->message->name); 1083 } 1084 } 1085 fprintf(stream, elementformat, "int", "__type"); 1086 fprintf(stream, ";\t///< set to SOAP_TYPE_X for a serializable type X\n"); 1087 fprintf(stream, pointerformat, "void", "fault"); 1088 fprintf(stream, ";\t///< points to serializable object X or NULL\n"); 1089 const char *t = types.tname(NULL, NULL, "xsd:any"); 1090 fprintf(stream, elementformat, t, "__any"); 1091 if (dflag) 1092 fprintf(stream, ";\t///< Catch any element content in DOM.\n"); 1093 else 1094 fprintf(stream, ";\t///< Catch any element content in XML string.\n"); 1095 fprintf(stream, "};\n"); 1096 } 1097 /* The SOAP Fault struct below is autogenerated by soapcpp2 (kept here for future mods) 1098 if (!mflag && !faults.empty()) 1099 { fprintf(stream, "struct SOAP_ENV__Code\n{\n"); 1100 fprintf(stream, elementformat, "_QName", "SOAP_ENV__Value"); 1101 fprintf(stream, ";\n"); 1102 fprintf(stream, pointerformat, "char", "SOAP_ENV__Node"); 1103 fprintf(stream, ";\n"); 1104 fprintf(stream, pointerformat, "char", "SOAP_ENV__Role"); 1105 fprintf(stream, ";\n};\n"); 1106 fprintf(stream, "struct SOAP_ENV__Detail\n{\n"); 1107 fprintf(stream, elementformat, "int", "__type"); 1108 fprintf(stream, ";\n"); 1109 fprintf(stream, pointerformat, "void", "fault"); 1110 fprintf(stream, ";\n"); 1111 fprintf(stream, elementformat, "_XML", "__any"); 1112 fprintf(stream, ";\n};\n"); 1113 fprintf(stream, "struct SOAP_ENV__Fault\n{\n"); 1114 fprintf(stream, elementformat, "_QName", "faultcode"); 1115 fprintf(stream, ";\n"); 1116 fprintf(stream, pointerformat, "char", "faultstring"); 1117 fprintf(stream, ";\n"); 1118 fprintf(stream, pointerformat, "char", "faultactor"); 1119 fprintf(stream, ";\n"); 1120 fprintf(stream, pointerformat, "struct SOAP_ENV__Detail", "detail"); 1121 fprintf(stream, ";\n"); 1122 fprintf(stream, pointerformat, "struct SOAP_ENV__Code", "SOAP_ENV__Code"); 1123 fprintf(stream, ";\n"); 1124 fprintf(stream, pointerformat, "char", "SOAP_ENV__Reason"); 1125 fprintf(stream, ";\n"); 1126 fprintf(stream, pointerformat, "struct SOAP_ENV__Detail", "SOAP_ENV__Detail"); 1127 fprintf(stream, ";\n};\n"); 1128 } 1129 */ 1130 for (MapOfStringToService::const_iterator service2 = services.begin(); service2 != services.end(); ++service2) 1131 if ((*service2).second) 1132 (*service2).second->generate(types); 1133} 1134 1135//////////////////////////////////////////////////////////////////////////////// 1136// 1137// Service methods 1138// 1139//////////////////////////////////////////////////////////////////////////////// 1140 1141Service::Service() 1142{ prefix = NULL; 1143 URI = NULL; 1144 name = NULL; 1145 type = NULL; 1146 transport = NULL; 1147} 1148 1149void Service::generate(Types& types) 1150{ if (name) 1151 banner(name); 1152 for (vector<Operation*>::const_iterator op2 = operation.begin(); op2 != operation.end(); ++op2) 1153 { if (*op2 && (*op2)->input) 1154 { bool flag = false, anonymous = ((*op2)->style != document && (*op2)->parameterOrder != NULL); 1155 banner((*op2)->input_name); 1156 if ((*op2)->output && (*op2)->output_name) 1157 { if ((*op2)->style == document) 1158 flag = (*op2)->output->message && (*op2)->output->message->part.size() == 1; 1159 else if (!wflag) 1160 flag = (*op2)->output->message && (*op2)->output->use == encoded && (*op2)->output->message->part.size() == 1 && !(*(*op2)->output->message->part.begin()).simpleTypePtr() && !(*(*op2)->output->message->part.begin()).complexTypePtr(); 1161 if (flag && (*op2)->input->message && (*(*op2)->output->message->part.begin()).element) 1162 for (vector<wsdl__part>::const_iterator part = (*op2)->input->message->part.begin(); part != (*op2)->input->message->part.end(); ++part) 1163 if ((*part).element && !strcmp((*part).element, (*(*op2)->output->message->part.begin()).element)) 1164 flag = false; 1165 if (!flag) 1166 { fprintf(stream, "/// Operation response struct \"%s\" of service binding \"%s\" operation \"%s\"\n", (*op2)->output_name, name, (*op2)->input_name); 1167 fprintf(stream, "struct %s\n{", (*op2)->output_name); 1168 (*op2)->output->generate(types, ";", anonymous, true, false); 1169 fprintf(stream, "\n};\n"); 1170 } 1171 } 1172 fprintf(stream, "\n/// Operation \"%s\" of service binding \"%s\"\n\n/**\n\nOperation details:\n\n", (*op2)->input_name, name); 1173 if ((*op2)->documentation) 1174 text((*op2)->documentation); 1175 if ((*op2)->operation_documentation) 1176 text((*op2)->operation_documentation); 1177 if ((*op2)->input->documentation) 1178 { fprintf(stream, "Input request:\n"); 1179 text((*op2)->input->documentation); 1180 } 1181 if ((*op2)->input->ext_documentation) 1182 { fprintf(stream, "Input request:\n"); 1183 text((*op2)->input->ext_documentation); 1184 } 1185 if ((*op2)->output) 1186 { if ((*op2)->output->documentation) 1187 { fprintf(stream, "Output response:\n"); 1188 text((*op2)->output->documentation); 1189 } 1190 if ((*op2)->output->ext_documentation) 1191 { fprintf(stream, "Output response:\n"); 1192 text((*op2)->output->ext_documentation); 1193 } 1194 } 1195 if ((*op2)->output) 1196 { if ((*op2)->output->content) 1197 { fprintf(stream, " - Response has MIME content"); 1198 if ((*op2)->output->content->type) 1199 { fprintf(stream, " type=\""); 1200 text((*op2)->output->content->type); 1201 fprintf(stream, "\""); 1202 } 1203 fprintf(stream, "\n TODO: this form of MIME content response is not automatically handled.\n Use one-way request and implement code to parse response.\n"); 1204 } 1205 } 1206 else 1207 fprintf(stream, " - One-way message\n"); 1208 if ((*op2)->style == document) 1209 fprintf(stream, " - SOAP document/literal style\n"); 1210 else 1211 { if ((*op2)->input->use == literal) 1212 fprintf(stream, " - SOAP RPC literal style\n"); 1213 else if ((*op2)->input->encodingStyle) 1214 fprintf(stream, " - SOAP RPC encodingStyle=\"%s\"\n", (*op2)->input->encodingStyle); 1215 else 1216 fprintf(stream, " - SOAP RPC encoded\n"); 1217 } 1218 if ((*op2)->output) 1219 { if ((*op2)->input->use != (*op2)->output->use) 1220 { if ((*op2)->output->use == literal) 1221 fprintf(stream, " - SOAP RPC literal response\n"); 1222 else if ((*op2)->output->encodingStyle) 1223 fprintf(stream, " - SOAP RPC response encodingStyle=\"%s\"\n", (*op2)->output->encodingStyle); 1224 else 1225 fprintf(stream, " - SOAP RPC encoded response\n"); 1226 } 1227 } 1228 if ((*op2)->soapAction) 1229 { if (*(*op2)->soapAction) 1230 fprintf(stream, " - SOAP action=\"%s\"\n", (*op2)->soapAction); 1231 } 1232 if ((*op2)->input) 1233 { if ((*op2)->input->action) 1234 fprintf(stream, " - Addressing action=\"%s\"\n", (*op2)->input->action); 1235 } 1236 if ((*op2)->output) 1237 { if ((*op2)->output->action) 1238 fprintf(stream, " - Addressing response action=\"%s\"\n", (*op2)->output->action); 1239 } 1240 for (vector<Message*>::const_iterator message = (*op2)->fault.begin(); message != (*op2)->fault.end(); ++message) 1241 { if ((*message)->use == literal) 1242 { for (vector<wsdl__part>::const_iterator part = (*message)->message->part.begin(); part != (*message)->message->part.end(); ++part) 1243 { if ((*part).element) 1244 fprintf(stream, " - SOAP Fault: %s (literal)\n", (*part).element); 1245 else if ((*part).name && (*part).type) 1246 fprintf(stream, " - SOAP Fault: %s (literal)\n", (*part).name); 1247 } 1248 } 1249 else if ((*message)->message && (*message)->message->name) 1250 fprintf(stream, " - SOAP Fault: %s\n", (*message)->name); 1251 } 1252 if (!(*op2)->input->header.empty()) 1253 fprintf(stream, " - Request message has mandatory header part(s):\n"); 1254 for (vector<soap__header>::const_iterator inputheader = (*op2)->input->header.begin(); inputheader != (*op2)->input->header.end(); ++inputheader) 1255 { if ((*inputheader).part) 1256 { if ((*inputheader).use == encoded && (*inputheader).namespace_) 1257 fprintf(stream, " - %s\n", types.aname(NULL, (*inputheader).namespace_, (*inputheader).part)); 1258 else if ((*inputheader).partPtr() && (*inputheader).partPtr()->element) 1259 fprintf(stream, " - %s\n", types.aname(NULL, NULL, (*inputheader).partPtr()->element)); 1260 } 1261 } 1262 if ((*op2)->input->multipartRelated) 1263 { int k = 2; 1264 fprintf(stream, " - Request message has MIME multipart/related attachments:\n"); 1265 for (vector<mime__part>::const_iterator part = (*op2)->input->multipartRelated->part.begin(); part != (*op2)->input->multipartRelated->part.end(); ++part) 1266 { if ((*part).soap__body_) 1267 { fprintf(stream, " -# MIME attachment with SOAP Body and mandatory header part(s):\n"); 1268 for (vector<soap__header>::const_iterator header = (*part).soap__header_.begin(); header != (*part).soap__header_.end(); ++header) 1269 { if ((*header).part) 1270 { if ((*header).use == encoded && (*header).namespace_) 1271 fprintf(stream, " - %s\n", types.aname(NULL, (*header).namespace_, (*header).part)); 1272 else if ((*header).partPtr() && (*header).partPtr()->element) 1273 fprintf(stream, " - %s\n", types.aname(NULL, NULL, (*header).partPtr()->element)); 1274 } 1275 } 1276 } 1277 else 1278 { fprintf(stream, " -# MIME attachment %d:\n", k++); 1279 for (vector<mime__content>::const_iterator content = (*part).content.begin(); content != (*part).content.end(); ++content) 1280 { fprintf(stream, " -"); 1281 if ((*content).part) 1282 { fprintf(stream, " part=\""); 1283 text((*content).part); 1284 fprintf(stream, "\""); 1285 } 1286 if ((*content).type) 1287 { fprintf(stream, " type=\""); 1288 text((*content).type); 1289 fprintf(stream, "\""); 1290 } 1291 fprintf(stream, "\n"); 1292 } 1293 } 1294 } 1295 } 1296 if ((*op2)->input->layout) 1297 fprintf(stream, " - Request message has DIME attachments in compliance with %s\n", (*op2)->input->layout); 1298 if ((*op2)->output) 1299 { if (!(*op2)->output->header.empty()) 1300 fprintf(stream, " - Response message has mandatory header part(s):\n"); 1301 for (vector<soap__header>::const_iterator outputheader = (*op2)->output->header.begin(); outputheader != (*op2)->output->header.end(); ++outputheader) 1302 { if ((*outputheader).part) 1303 { if ((*outputheader).use == encoded && (*outputheader).namespace_) 1304 fprintf(stream, " - %s\n", types.aname(NULL, (*outputheader).namespace_, (*outputheader).part)); 1305 else if ((*outputheader).partPtr() && (*outputheader).partPtr()->element) 1306 fprintf(stream, " - %s\n", types.aname(NULL, NULL, (*outputheader).partPtr()->element)); 1307 } 1308 } 1309 } 1310 if ((*op2)->output && (*op2)->output_name && (*op2)->output->multipartRelated) 1311 { int k = 2; 1312 fprintf(stream, " - Response message has MIME multipart/related attachments\n"); 1313 for (vector<mime__part>::const_iterator part = (*op2)->output->multipartRelated->part.begin(); part != (*op2)->output->multipartRelated->part.end(); ++part) 1314 { if ((*part).soap__body_) 1315 { fprintf(stream, " -# MIME attachment with SOAP Body and mandatory header part(s):\n"); 1316 for (vector<soap__header>::const_iterator header = (*part).soap__header_.begin(); header != (*part).soap__header_.end(); ++header) 1317 { if ((*header).part) 1318 { if ((*header).use == encoded && (*header).namespace_) 1319 fprintf(stream, " - %s\n", types.aname(NULL, (*header).namespace_, (*header).part)); 1320 else if ((*header).partPtr() && (*header).partPtr()->element) 1321 fprintf(stream, " - %s\n", types.aname(NULL, NULL, (*header).partPtr()->element)); 1322 } 1323 } 1324 } 1325 else 1326 { fprintf(stream, " -# MIME attachment %d:\n", k++); 1327 for (vector<mime__content>::const_iterator content = (*part).content.begin(); content != (*part).content.end(); ++content) 1328 { fprintf(stream, " -"); 1329 if ((*content).part) 1330 { fprintf(stream, " part=\""); 1331 text((*content).part); 1332 fprintf(stream, "\""); 1333 } 1334 if ((*content).type) 1335 { fprintf(stream, " type=\""); 1336 text((*content).type); 1337 fprintf(stream, "\""); 1338 } 1339 fprintf(stream, "\n"); 1340 } 1341 } 1342 } 1343 } 1344 if ((*op2)->output && (*op2)->output_name && (*op2)->output->layout) 1345 fprintf(stream, " - Response message has DIME attachments in compliance with %s\n", (*op2)->output->layout); 1346 fprintf(stream, "\nC stub function (defined in soapClient.c[pp] generated by soapcpp2):\n@code\n int soap_call_%s(\n struct soap *soap,\n NULL, // char *endpoint = NULL selects default endpoint for this operation\n NULL, // char *action = NULL selects default action for this operation\n // request parameters:", (*op2)->input_name); 1347 (*op2)->input->generate(types, ",", false, false, false); 1348 fprintf(stream, "\n // response parameters:"); 1349 if ((*op2)->output && (*op2)->output_name) 1350 { if (flag) 1351 { if ((*op2)->style == document) 1352 { // Shortcut: do not generate wrapper struct 1353 (*op2)->output->generate(types, "", false, false, true); 1354 } 1355 else if ((*(*op2)->output->message->part.begin()).name) 1356 { fprintf(stream, "\n"); 1357 fprintf(stream, anonymous ? anonformat : paraformat, types.tname(NULL, NULL, (*(*op2)->output->message->part.begin()).type), cflag ? "*" : "&", types.aname(NULL, NULL, (*(*op2)->output->message->part.begin()).name), ""); 1358 } 1359 } 1360 else 1361 fprintf(stream, "\n struct %s%s", (*op2)->output_name, cflag ? "*" : "&"); 1362 } 1363 fprintf(stream, "\n );\n@endcode\n\nC server function (called from the service dispatcher defined in soapServer.c[pp]):\n@code\n int %s(\n struct soap *soap,\n // request parameters:", (*op2)->input_name); 1364 (*op2)->input->generate(types, ",", false, false, false); 1365 fprintf(stream, "\n // response parameters:"); 1366 if ((*op2)->output && (*op2)->output_name) 1367 { if (flag) 1368 { if ((*op2)->style == document) 1369 { // Shortcut: do not generate wrapper struct 1370 (*op2)->output->generate(types, "", false, false, true); 1371 } 1372 else if ((*(*op2)->output->message->part.begin()).name) 1373 { fprintf(stream, "\n"); 1374 fprintf(stream, anonymous ? anonformat : paraformat, types.tname(NULL, NULL, (*(*op2)->output->message->part.begin()).type), cflag ? "*" : "&", types.aname(NULL, NULL, (*(*op2)->output->message->part.begin()).name), ""); 1375 } 1376 } 1377 else 1378 fprintf(stream, "\n struct %s%s", (*op2)->output_name, cflag ? "*" : "&"); 1379 } 1380 fprintf(stream, "\n );\n@endcode\n\n"); 1381 if (!cflag) 1382 { fprintf(stream, "C++ proxy class (defined in soap%sProxy.h):\n", name); 1383 fprintf(stream, " class %s;\n\n", name); 1384 fprintf(stream, "Note: use soapcpp2 option '-i' to generate improved proxy and service classes;\n\n"); 1385 } 1386 fprintf(stream, "*/\n\n"); 1387 (*op2)->generate(types); 1388 } 1389 } 1390} 1391 1392//////////////////////////////////////////////////////////////////////////////// 1393// 1394// Operation methods 1395// 1396//////////////////////////////////////////////////////////////////////////////// 1397 1398void Operation::generate(Types &types) 1399{ bool flag = false, anonymous = ((style != document) && parameterOrder != NULL); 1400 const char *method_name = strstr(input_name + 1, "__") + 2; 1401 if (!method_name) 1402 method_name = input_name; 1403 if (style == document) 1404 fprintf(stream, serviceformat, prefix, "method-style", method_name, "document"); 1405 else 1406 fprintf(stream, serviceformat, prefix, "method-style", method_name, "rpc"); 1407 if (input->use == literal) 1408 fprintf(stream, serviceformat, prefix, "method-encoding", method_name, "literal"); 1409 else if (input->encodingStyle) 1410 fprintf(stream, serviceformat, prefix, "method-encoding", method_name, input->encodingStyle); 1411 else 1412 fprintf(stream, serviceformat, prefix, "method-encoding", method_name, "encoded"); 1413 if (output) 1414 { if (input->use != output->use) 1415 { if (output->use == literal) 1416 fprintf(stream, serviceformat, prefix, "method-response-encoding", method_name, "literal"); 1417 else if (output->encodingStyle) 1418 fprintf(stream, serviceformat, prefix, "method-response-encoding", method_name, output->encodingStyle); 1419 else 1420 fprintf(stream, serviceformat, prefix, "method-response-encoding", method_name, "encoded"); 1421 } 1422 if (style == rpc && input->URI && output->URI && strcmp(input->URI, output->URI)) 1423 fprintf(stream, schemaformat, types.nsprefix(NULL, output->URI), "namespace", output->URI); 1424 } 1425 if (soapAction) 1426 { if (*soapAction) 1427 fprintf(stream, serviceformat, prefix, "method-action", method_name, soapAction); 1428 else 1429 fprintf(stream, serviceformat, prefix, "method-action", method_name, "\"\""); 1430 } 1431 else if (input && input->action) 1432 fprintf(stream, serviceformat, prefix, "method-action", method_name, input->action); 1433 else if (output && output->action) 1434 fprintf(stream, serviceformat, prefix, "method-response-action", method_name, output->action); 1435 for (vector<Message*>::const_iterator message = fault.begin(); message != fault.end(); ++message) 1436 { if ((*message)->use == literal) 1437 { for (vector<wsdl__part>::const_iterator part = (*message)->message->part.begin(); part != (*message)->message->part.end(); ++part) 1438 { if ((*part).element) 1439 fprintf(stream, serviceformat, prefix, "method-fault", method_name, types.aname(NULL, NULL, (*part).element)); 1440 else if ((*part).type) 1441 fprintf(stream, serviceformat, prefix, "method-fault", method_name, types.aname(NULL, (*message)->URI, (*part).name)); 1442 } 1443 } 1444 else 1445 { if ((*message)->message && (*message)->message->name) 1446 fprintf(stream, serviceformat, prefix, "method-fault", method_name, (*message)->name); 1447 } 1448 } 1449 if (input->multipartRelated) 1450 { for (vector<mime__part>::const_iterator inputmime = input->multipartRelated->part.begin(); inputmime != input->multipartRelated->part.end(); ++inputmime) 1451 { for (vector<soap__header>::const_iterator inputheader = (*inputmime).soap__header_.begin(); inputheader != (*inputmime).soap__header_.end(); ++inputheader) 1452 { if ((*inputheader).part) 1453 { if ((*inputheader).use == encoded && (*inputheader).namespace_) 1454 fprintf(stream, serviceformat, prefix, "method-input-header-part", method_name, types.aname(NULL, (*inputheader).namespace_, (*inputheader).part)); 1455 else if ((*inputheader).partPtr() && (*inputheader).partPtr()->element) 1456 fprintf(stream, serviceformat, prefix, "method-input-header-part", method_name, types.aname(NULL, NULL, (*inputheader).partPtr()->element)); 1457 } 1458 } 1459 for (vector<mime__content>::const_iterator content = (*inputmime).content.begin(); content != (*inputmime).content.end(); ++content) 1460 if ((*content).type) 1461 fprintf(stream, serviceformat, prefix, "method-input-mime-type", method_name, (*content).type); 1462 } 1463 } 1464 // TODO: add headerfault directives 1465 for (vector<soap__header>::const_iterator inputheader = input->header.begin(); inputheader != input->header.end(); ++inputheader) 1466 { if ((*inputheader).part) 1467 { if ((*inputheader).use == encoded && (*inputheader).namespace_) 1468 fprintf(stream, serviceformat, prefix, "method-input-header-part", method_name, types.aname(NULL, (*inputheader).namespace_, (*inputheader).part)); 1469 else if ((*inputheader).partPtr() && (*inputheader).partPtr()->element) 1470 fprintf(stream, serviceformat, prefix, "method-input-header-part", method_name, types.aname(NULL, NULL, (*inputheader).partPtr()->element)); 1471 } 1472 } 1473 if (output) 1474 { if (output->multipartRelated) 1475 { for (vector<mime__part>::const_iterator outputmime = output->multipartRelated->part.begin(); outputmime != output->multipartRelated->part.end(); ++outputmime) 1476 { for (vector<soap__header>::const_iterator outputheader = (*outputmime).soap__header_.begin(); outputheader != (*outputmime).soap__header_.end(); ++outputheader) 1477 { if ((*outputheader).part) 1478 { if ((*outputheader).use == encoded && (*outputheader).namespace_) 1479 fprintf(stream, serviceformat, prefix, "method-output-header-part", method_name, types.aname(NULL, (*outputheader).namespace_, (*outputheader).part)); 1480 else if ((*outputheader).partPtr() && (*outputheader).partPtr()->element) 1481 fprintf(stream, serviceformat, prefix, "method-output-header-part", method_name, types.aname(NULL, NULL, (*outputheader).partPtr()->element)); 1482 } 1483 } 1484 for (vector<mime__content>::const_iterator content = (*outputmime).content.begin(); content != (*outputmime).content.end(); ++content) 1485 if ((*content).type) 1486 fprintf(stream, serviceformat, prefix, "method-output-mime-type", method_name, (*content).type); 1487 } 1488 } 1489 for (vector<soap__header>::const_iterator outputheader = output->header.begin(); outputheader != output->header.end(); ++outputheader) 1490 { if ((*outputheader).part) 1491 { if ((*outputheader).use == encoded && (*outputheader).namespace_) 1492 fprintf(stream, serviceformat, prefix, "method-output-header-part", method_name, types.aname(NULL, (*outputheader).namespace_, (*outputheader).part)); 1493 else if ((*outputheader).partPtr() && (*outputheader).partPtr()->element) 1494 fprintf(stream, serviceformat, prefix, "method-output-header-part", method_name, types.aname(NULL, NULL, (*outputheader).partPtr()->element)); 1495 } 1496 } 1497 } 1498 if (output_name) 1499 { if (style == document) 1500 flag = output->message && output->message->part.size() == 1; 1501 else if (!wflag) 1502 flag = output->message && output->use == encoded && output->message->part.size() == 1 && !(*output->message->part.begin()).simpleTypePtr() && !(*output->message->part.begin()).complexTypePtr(); 1503 if (flag && input->message && (*output->message->part.begin()).element) 1504 for (vector<wsdl__part>::const_iterator part = input->message->part.begin(); part != input->message->part.end(); ++part) 1505 if ((*part).element && !strcmp((*part).element, (*output->message->part.begin()).element)) 1506 flag = false; 1507 } 1508 fprintf(stream, "int %s(", input_name); 1509 input->generate(types, ",", anonymous, true, false); 1510 if (output_name) 1511 { if (flag) 1512 { if (style == document) 1513 { // Shortcut: do not generate wrapper struct 1514 output->generate(types, "", false, true, true); 1515 } 1516 else if ((*output->message->part.begin()).name) 1517 { fprintf(stream, "\n"); 1518 fprintf(stream, anonymous ? anonformat : paraformat, types.tname(NULL, NULL, (*output->message->part.begin()).type), cflag ? "*" : "&", types.aname(NULL, NULL, (*output->message->part.begin()).name), ""); 1519 fprintf(stream, "\t///< Response parameter"); 1520 } 1521 } 1522 else 1523 { fprintf(stream, "\n struct %-28s%s", output_name, cflag ? "*" : "&"); 1524 fprintf(stream, "\t///< Response struct parameter"); 1525 } 1526 fprintf(stream, "\n);\n"); 1527 } 1528 else 1529 fprintf(stream, "\n void\t///< One-way message: no response parameter\n);\n"); 1530} 1531 1532//////////////////////////////////////////////////////////////////////////////// 1533// 1534// Message methods 1535// 1536//////////////////////////////////////////////////////////////////////////////// 1537 1538void Message::generate(Types &types, const char *sep, bool anonymous, bool remark, bool response) 1539{ if (message) 1540 { for (vector<wsdl__part>::const_iterator part = message->part.begin(); part != message->part.end(); ++part) 1541 { if (!(*part).name) 1542 fprintf(stderr, "Error: no part name in message '%s'\n", message->name?message->name:""); 1543 else if (!body_parts || soap_strsearch(body_parts, (*part).name)) 1544 { if (remark && (*part).documentation) 1545 comment("", (*part).name, "parameter", (*part).documentation); 1546 else 1547 fprintf(stream, "\n"); 1548 if ((*part).element) 1549 { if ((*part).elementPtr()) 1550 { const char *name, *type, *URI, *prefix = NULL; 1551 if (style == rpc) 1552 name = (*part).name; 1553 else 1554 name = (*part).elementPtr()->name; 1555 /* comment out to use a type that refers to an element defined with typedef */ 1556 if ((*part).elementPtr()->type) 1557 type = (*part).elementPtr()->type; 1558 else 1559 { type = (*part).elementPtr()->name; 1560 prefix = "_"; 1561 } 1562 if (style == document && (*part).elementPtr()->schemaPtr()) 1563 URI = (*part).elementPtr()->schemaPtr()->targetNamespace; 1564 else 1565 URI = NULL; 1566 if (response) 1567 { const char *t = types.tname(prefix, URI, type); 1568 bool flag = (strchr(t, '*') && strcmp(t, "char*") && strcmp(t, "char *")); 1569 fprintf(stream, anonymous ? anonformat : paraformat, t, flag ? " " : cflag ? "*" : "&", types.aname(NULL, URI, name), sep); 1570 if (remark) 1571 fprintf(stream, "\t///< Response parameter"); 1572 } 1573 else 1574 { fprintf(stream, anonymous ? anonformat : paraformat, types.pname(false, prefix, URI, type), " ", types.aname(NULL, URI, name), sep); 1575 if (remark && *sep == ',') 1576 fprintf(stream, "\t///< Request parameter"); 1577 } 1578 } 1579 else 1580 { fprintf(stream, anonymous ? anonformat : paraformat, types.pname(false, NULL, NULL, (*part).element), " ", types.aname(NULL, NULL, (*part).element), sep); 1581 if (remark) 1582 fprintf(stream, "\t///< TODO: Check element type (imported type)"); 1583 } 1584 } 1585 else if ((*part).type) 1586 { if (response) 1587 { const char *t = types.tname(NULL, NULL, (*part).type); 1588 bool flag = (strchr(t, '*') && strcmp(t, "char*") && strcmp(t, "char *")); 1589 fprintf(stream, anonymous ? anonformat : paraformat, t, flag ? " " : cflag ? "*" : "&", types.aname(NULL, NULL, (*part).name), sep); 1590 if (remark) 1591 fprintf(stream, "\t///< Response parameter"); 1592 } 1593 else 1594 { fprintf(stream, anonymous ? anonformat : paraformat, types.pname(false, NULL, NULL, (*part).type), " ", types.aname(NULL, NULL, (*part).name), sep); 1595 if (remark && *sep == ',') 1596 fprintf(stream, "\t///< Request parameter"); 1597 } 1598 } 1599 else 1600 fprintf(stderr, "Error: no wsdl:definitions/message/part/@type in part '%s'\n", (*part).name); 1601 } 1602 } 1603 } 1604 else 1605 fprintf(stderr, "Error: no wsdl:definitions/message\n"); 1606} 1607 1608//////////////////////////////////////////////////////////////////////////////// 1609// 1610// Miscellaneous 1611// 1612//////////////////////////////////////////////////////////////////////////////// 1613 1614static void comment(const char *start, const char *middle, const char *end, const char *text) 1615{ if (text) 1616 { if (strchr(text, '\r') || strchr(text, '\n')) 1617 fprintf(stream, "\n/** %s %s %s documentation:\n%s\n*/\n\n", start, middle, end, text); 1618 else 1619 fprintf(stream, "\n/// %s %s %s: %s\n", start, middle, end, text); 1620 } 1621} 1622 1623static void page(const char *page, const char *title, const char *text) 1624{ if (text) 1625 fprintf(stream, "\n@page %s%s \"%s\"\n", page, title, text); 1626 else 1627 fprintf(stream, "\n@page %s%s\n", page, title); 1628} 1629 1630static void section(const char *section, const char *title, const char *text) 1631{ if (text) 1632 fprintf(stream, "\n@section %s%s \"%s\"\n", section, title, text); 1633 else 1634 fprintf(stream, "\n@section %s%s\n", section, title); 1635} 1636 1637static void banner(const char *text) 1638{ int i; 1639 fprintf(stream, "\n/"); 1640 for (i = 0; i < 78; i++) 1641 fputc('*', stream); 1642 fprintf(stream, "\\\n *%76s*\n * %-75s*\n *%76s*\n\\", "", text, ""); 1643 for (i = 0; i < 78; i++) 1644 fputc('*', stream); 1645 fprintf(stream, "/\n\n"); 1646 if (vflag) 1647 fprintf(stderr, "\n---- %s ----\n\n", text); 1648} 1649 1650static void ident() 1651{ time_t t = time(NULL), *p = &t; 1652 char tmp[256]; 1653 int i; 1654 strftime(tmp, 256, "%Y-%m-%d %H:%M:%S GMT", gmtime(p)); 1655 fprintf(stream, "/* %s\n Generated by wsdl2h "VERSION" from ", outfile?outfile:""); 1656 if (infiles) 1657 { for (i = 0; i < infiles; i++) 1658 fprintf(stream, "%s ", infile[i]); 1659 } 1660 else 1661 fprintf(stream, "(stdin) "); 1662 fprintf(stream, "and %s\n %s\n Copyright (C) 2001-2008 Robert van Engelen, Genivia Inc. All Rights Reserved.\n This part of the software is released under one of the following licenses:\n GPL or Genivia's license for commercial use.\n*/\n\n", mapfile, tmp); 1663} 1664 1665static void text(const char *text) 1666{ const char *s = text; 1667 if (!s) 1668 return; 1669 while (*s) 1670 { switch (*s) 1671 { case '\n': 1672 case '\t': 1673 case ' ': 1674 fputc(*s, stream); 1675 break; 1676 case '/': 1677 fputc(*s, stream); 1678 if (s[1] == '*') 1679 fputc(' ', stream); 1680 break; 1681 case '*': 1682 fputc(*s, stream); 1683 if (s[1] == '/') 1684 fputc(' ', stream); 1685 break; 1686 default: 1687 if (*s > 32) 1688 fputc(*s, stream); 1689 } 1690 s++; 1691 } 1692 fputc('\n', stream); 1693} 1694