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