| /* |
| |
| types.cpp |
| |
| WSDL parser and converter to gSOAP header file format |
| |
| -------------------------------------------------------------------------------- |
| gSOAP XML Web services tools |
| Copyright (C) 2001-2006, Robert van Engelen, Genivia Inc. All Rights Reserved. |
| This software is released under one of the following two licenses: |
| GPL or Genivia's license for commercial use. |
| -------------------------------------------------------------------------------- |
| GPL license. |
| |
| This program is free software; you can redistribute it and/or modify it under |
| the terms of the GNU General Public License as published by the Free Software |
| Foundation; either version 2 of the License, or (at your option) any later |
| version. |
| |
| This program is distributed in the hope that it will be useful, but WITHOUT ANY |
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A |
| PARTICULAR PURPOSE. See the GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License along with |
| this program; if not, write to the Free Software Foundation, Inc., 59 Temple |
| Place, Suite 330, Boston, MA 02111-1307 USA |
| |
| Author contact information: |
| engelen@genivia.com / engelen@acm.org |
| -------------------------------------------------------------------------------- |
| A commercial use license is available from Genivia, Inc., contact@genivia.com |
| -------------------------------------------------------------------------------- |
| |
| */ |
| |
| #include "types.h" |
| |
| static char *getline(char *s, size_t n, FILE *fd); |
| static const char *nonblank(const char *s); |
| static const char *fill(char *t, int n, const char *s, int e); |
| static const char *utf8(char *t, const char *s); |
| static const char *cstring(const char *s); |
| static const char *xstring(const char *s); |
| static bool is_integer(const char *s); |
| static void documentation(const char *text); |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // Keywords and reserved words |
| // |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| static const char *keywords[] = |
| { "and", |
| "asm", |
| "auto", |
| "bool", |
| "break", |
| "case", |
| "catch", |
| "char", |
| "class", |
| "const", |
| "const_cast", |
| "continue", |
| "default", |
| "delete", |
| "do", |
| "double", |
| "dynamic_cast", |
| "else", |
| "enum", |
| "errno", |
| "explicit", |
| "export", |
| "extern", |
| "false", |
| "FILE", |
| "float", |
| "for", |
| "friend", |
| "goto", |
| "if", |
| "inline", |
| "int", |
| "long", |
| "LONG64", |
| "max", |
| "min", |
| "mustUnderstand", |
| "mutable", |
| "namespace", |
| "new", |
| "not", |
| "NULL", |
| "operator", |
| "or", |
| "private", |
| "protected", |
| "public", |
| "_QName", |
| "register", |
| "reinterpret_cast", |
| "restrict", |
| "return", |
| "short", |
| "signed", |
| "size_t", |
| "sizeof", |
| "static", |
| "static_cast", |
| "struct", |
| "switch", |
| "template", |
| "this", |
| "throw", |
| "time_t", |
| "true", |
| "typedef", |
| "typeid", |
| "typename", |
| "ULONG64", |
| "union", |
| "unsigned", |
| "using", |
| "virtual", |
| "void", |
| "volatile", |
| "wchar_t", |
| "while", |
| "XML", |
| "_XML", |
| "xor", |
| }; |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // Types methods |
| // |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| Types::Types() |
| { init(); |
| } |
| |
| int Types::read(const char *file) |
| { FILE *fd = fopen(file, "r"); |
| char buf[1024], xsd[1024], def[1024], use[1024], ptr[1024], uri[1024]; |
| const char *s; |
| short copy = 0; |
| if (!fd) |
| { fprintf(stderr, "Cannot open file '%s'\n", file); |
| return SOAP_EOF; |
| } |
| fprintf(stderr, "Reading type map file '%s'\n\n", file); |
| while (getline(buf, sizeof(buf), fd)) |
| { s = buf; |
| if (copy) |
| { if (*s == ']') |
| copy = 0; |
| else |
| fprintf(stream, "%s\n", buf); |
| } |
| else if (*s == '[') |
| copy = 1; |
| else if (*s && *s != '#') |
| { s = fill(xsd, sizeof(xsd), s, '='); |
| if (strstr(xsd, "__")) |
| { s = fill(def, sizeof(def), s, '|'); |
| s = fill(use, sizeof(use), s, '|'); |
| s = fill(ptr, sizeof(ptr), s, '|'); |
| if (*xsd) |
| { s = estrdup(xsd); |
| if (*def == '$') |
| { const char *t = modtypemap[s]; |
| if (t) |
| { char *r = (char*)emalloc(strlen(t) + strlen(def) + 1); |
| strcpy(r, t); |
| strcat(r, def); |
| free((void*)modtypemap[s]); |
| modtypemap[s] = r; |
| } |
| else |
| modtypemap[s] = estrdup(def); |
| } |
| else |
| { if (*def) |
| deftypemap[s] = estrdup(def); |
| else |
| deftypemap[s] = ""; |
| if (*use) |
| usetypemap[s] = estrdup(use); |
| else |
| usetypemap[s] = estrdup(xsd); |
| if (*ptr) |
| ptrtypemap[s] = estrdup(ptr); |
| } |
| } |
| } |
| else if (*xsd) |
| { s = fill(uri, sizeof(uri), s, 0); |
| if (uri[0] == '"') |
| { uri[strlen(uri) - 1] = '\0'; |
| nsprefix(xsd, estrdup(uri + 1)); |
| } |
| else if (uri[0] == '<') |
| { uri[strlen(uri) - 1] = '\0'; |
| char *s = estrdup(uri + 1); |
| nsprefix(xsd, s); |
| exturis.insert(s); |
| } |
| else |
| nsprefix(xsd, estrdup(uri)); |
| } |
| } |
| } |
| fclose(fd); |
| return SOAP_OK; |
| } |
| |
| void Types::init() |
| { snum = 1; |
| unum = 1; |
| gnum = 1; |
| with_union = false; |
| fake_union = false; |
| knames.insert(keywords, keywords + sizeof(keywords)/sizeof(char*)); |
| if (cflag) |
| { deftypemap["xsd__ur_type"] = ""; |
| if (dflag) |
| { usetypemap["xsd__ur_type"] = "xsd__anyType"; |
| ptrtypemap["xsd__ur_type"] = "xsd__anyType*"; |
| } |
| else |
| { usetypemap["xsd__ur_type"] = "_XML"; |
| ptrtypemap["xsd__ur_type"] = "_XML"; |
| } |
| } |
| else |
| { deftypemap["xsd__ur_type"] = "class xsd__ur_type { _XML __item; struct soap *soap; };"; |
| usetypemap["xsd__ur_type"] = "xsd__ur_type"; |
| } |
| if (cflag) |
| { deftypemap["xsd__anyType"] = ""; |
| if (dflag) |
| { usetypemap["xsd__anyType"] = "xsd__anyType"; |
| ptrtypemap["xsd__anyType"] = "xsd__anyType*"; |
| } |
| else |
| { usetypemap["xsd__anyType"] = "_XML"; |
| ptrtypemap["xsd__anyType"] = "_XML"; |
| } |
| } |
| else |
| { deftypemap["xsd__anyType"] = "class xsd__anyType { _XML __item; struct soap *soap; };"; |
| usetypemap["xsd__anyType"] = "xsd__anyType*"; |
| } |
| if (cflag) |
| { deftypemap["xsd__base64Binary"] = "struct xsd__base64Binary\n{\tunsigned char *__ptr;\n\tint __size;\n\tchar *id, *type, *options; /* NOTE: for DIME and MTOM XOP attachments only */\n};"; |
| usetypemap["xsd__base64Binary"] = "struct xsd__base64Binary"; |
| } |
| else |
| { deftypemap["xsd__base64Binary"] = "class xsd__base64Binary\n{\tunsigned char *__ptr;\n\tint __size;\n\tchar *id, *type, *options; /* NOTE: for DIME and MTOM XOP attachments only */\n\tstruct soap *soap;\n};"; |
| usetypemap["xsd__base64Binary"] = "xsd__base64Binary"; |
| } |
| if (cflag) |
| { if (eflag) |
| deftypemap["xsd__boolean"] = "enum xsd__boolean { false_, true_ };"; |
| else |
| deftypemap["xsd__boolean"] = "enum xsd__boolean { xsd__boolean__false_, xsd__boolean__true_ };"; |
| usetypemap["xsd__boolean"] = "enum xsd__boolean"; |
| } |
| else |
| { deftypemap["xsd__boolean"] = ""; |
| usetypemap["xsd__boolean"] = "bool"; |
| } |
| deftypemap["xsd__byte"] = ""; |
| usetypemap["xsd__byte"] = "char"; |
| ptrtypemap["xsd__byte"] = "short*"; // avoid char* |
| deftypemap["xsd__dateTime"] = ""; |
| usetypemap["xsd__dateTime"] = "time_t"; |
| deftypemap["xsd__double"] = ""; |
| usetypemap["xsd__double"] = "double"; |
| deftypemap["xsd__float"] = ""; |
| usetypemap["xsd__float"] = "float"; |
| if (cflag) |
| { deftypemap["xsd__hexBinary"] = "struct xsd__hexBinary { unsigned char *__ptr; int __size; };"; |
| usetypemap["xsd__hexBinary"] = "struct xsd__hexBinary"; |
| } |
| else |
| { deftypemap["xsd__hexBinary"] = "class xsd__hexBinary { unsigned char *__ptr; int __size; };"; |
| usetypemap["xsd__hexBinary"] = "xsd__hexBinary"; |
| } |
| deftypemap["xsd__int"] = ""; |
| usetypemap["xsd__int"] = "int"; |
| deftypemap["xsd__long"] = ""; |
| usetypemap["xsd__long"] = "LONG64"; |
| deftypemap["xsd__short"] = ""; |
| usetypemap["xsd__short"] = "short"; |
| if (cflag || sflag) |
| { deftypemap["xsd__string"] = ""; |
| usetypemap["xsd__string"] = "char*"; |
| } |
| else |
| { deftypemap["xsd__string"] = ""; |
| usetypemap["xsd__string"] = "std::string"; |
| } |
| deftypemap["xsd__unsignedByte"] = ""; |
| usetypemap["xsd__unsignedByte"] = "unsigned char"; |
| ptrtypemap["xsd__unsignedByte"] = "unsigned short*"; // avoid unsigned char* |
| deftypemap["xsd__unsignedInt"] = ""; |
| usetypemap["xsd__unsignedInt"] = "unsigned int"; |
| deftypemap["xsd__unsignedLong"] = ""; |
| usetypemap["xsd__unsignedLong"] = "ULONG64"; |
| deftypemap["xsd__unsignedShort"] = ""; |
| usetypemap["xsd__unsignedShort"] = "unsigned short"; |
| if (cflag) |
| { deftypemap["SOAP_ENC__base64Binary"] = "struct SOAP_ENC__base64Binary { unsigned char *__ptr; int __size; };"; |
| usetypemap["SOAP_ENC__base64Binary"] = "struct SOAP_ENC__base64Binary"; |
| } |
| else |
| { deftypemap["SOAP_ENC__base64Binary"] = "class SOAP_ENC__base64Binary { unsigned char *__ptr; int __size; };"; |
| usetypemap["SOAP_ENC__base64Binary"] = "SOAP_ENC__base64Binary"; |
| } |
| if (cflag) |
| { deftypemap["SOAP_ENC__boolean"] = "enum SOAP_ENC__boolean { false_, true_ };"; |
| usetypemap["SOAP_ENC__boolean"] = "enum SOAP_ENC__boolean"; |
| } |
| else |
| { deftypemap["SOAP_ENC__boolean"] = ""; |
| usetypemap["SOAP_ENC__boolean"] = "bool"; |
| } |
| deftypemap["SOAP_ENC__byte"] = ""; |
| usetypemap["SOAP_ENC__byte"] = "char"; |
| deftypemap["SOAP_ENC__dateTime"] = ""; |
| usetypemap["SOAP_ENC__dateTime"] = "time_t"; |
| deftypemap["SOAP_ENC__double"] = ""; |
| usetypemap["SOAP_ENC__double"] = "double"; |
| deftypemap["SOAP_ENC__float"] = ""; |
| usetypemap["SOAP_ENC__float"] = "float"; |
| if (cflag) |
| { deftypemap["SOAP_ENC__hexBinary"] = "struct SOAP_ENC__hexBinary { unsigned char *__ptr; int __size; };"; |
| usetypemap["SOAP_ENC__hexBinary"] = "struct SOAP_ENC__hexBinary"; |
| } |
| else |
| { deftypemap["SOAP_ENC__hexBinary"] = "class SOAP_ENC__hexBinary { unsigned char *__ptr; int __size; };"; |
| usetypemap["SOAP_ENC__hexBinary"] = "SOAP_ENC__hexBinary"; |
| } |
| deftypemap["SOAP_ENC__int"] = ""; |
| usetypemap["SOAP_ENC__int"] = "int"; |
| deftypemap["SOAP_ENC__long"] = ""; |
| usetypemap["SOAP_ENC__long"] = "LONG64"; |
| deftypemap["SOAP_ENC__short"] = ""; |
| usetypemap["SOAP_ENC__short"] = "short"; |
| ptrtypemap["SOAP_ENC__short"] = "int*"; |
| if (cflag || sflag) |
| { deftypemap["SOAP_ENC__string"] = ""; |
| usetypemap["SOAP_ENC__string"] = "char*"; |
| } |
| else |
| { deftypemap["SOAP_ENC__string"] = ""; |
| usetypemap["SOAP_ENC__string"] = "std::string"; |
| } |
| deftypemap["SOAP_ENC__unsignedByte"] = ""; |
| usetypemap["SOAP_ENC__unsignedByte"] = "unsigned char"; |
| ptrtypemap["SOAP_ENC__unsignedByte"] = "unsigned short*"; |
| deftypemap["SOAP_ENC__unsignedInt"] = ""; |
| usetypemap["SOAP_ENC__unsignedInt"] = "unsigned long"; |
| deftypemap["SOAP_ENC__unsignedLong"] = ""; |
| usetypemap["SOAP_ENC__unsignedLong"] = "ULONG64"; |
| deftypemap["SOAP_ENC__unsignedShort"] = ""; |
| usetypemap["SOAP_ENC__unsignedShort"] = "unsigned short"; |
| deftypemap["SOAP_ENC__Array"] = ""; |
| if (read(mapfile)) |
| fprintf(stderr, "Problem reading type map file %s.\nUsing internal type definitions for %s instead.\n\n", mapfile, cflag?"C":"C++"); |
| } |
| |
| const char *Types::nsprefix(const char *prefix, const char *URI) |
| { if (URI) |
| { const char *s = uris[URI]; |
| if (!s) |
| { size_t n; |
| if (!prefix || !*prefix || *prefix == '_') |
| s = schema_prefix; |
| else |
| s = estrdup(prefix); |
| if (!syms[s]) |
| n = syms[s] = 1; |
| else |
| n = ++syms[s]; |
| if (n != 1 || !prefix || !*prefix || *prefix == '_') |
| { char *t = (char*)emalloc(strlen(s) + 16); |
| sprintf(t, "%s%lu", s, (unsigned long)n); |
| s = t; |
| } |
| uris[URI] = s; |
| if (vflag) |
| fprintf(stderr, "namespace prefix %s = \"%s\"\n", s, URI); |
| } |
| return s; |
| } |
| return NULL; |
| } |
| |
| // Find a C name for a QName. If the name has no qualifier, use URI. Suggest prefix for URI |
| const char *Types::fname(const char *prefix, const char *URI, const char *qname, SetOfString *reserved, enum Lookup lookup) |
| { char buf[1024], *t; |
| const char *p, *s, *name; |
| if (!qname) |
| { fprintf(stream, "// Warning: internal error, undefined qname in fname()\n"); |
| qname = "?"; |
| } |
| s = strrchr(qname, ':'); |
| if (s) |
| { name = s + 1; |
| if (*qname == '"') |
| { t = (char*)emalloc(s - qname - 1); |
| strncpy(t, qname + 1, s - qname - 2); |
| t[s - qname - 2] = '\0'; |
| URI = t; |
| } |
| else if (!strncmp(qname, "xs:", 3)) // this hack is necessary since the nsmap table defines "xs" for "xsd" |
| { s = "xsd"; |
| URI = NULL; |
| } |
| else |
| { t = (char*)emalloc(s - qname + 1); |
| strncpy(t, qname, s - qname); |
| t[s - qname] = '\0'; |
| s = t; |
| URI = NULL; |
| } |
| } |
| else |
| name = qname; |
| if (URI) |
| p = nsprefix(prefix, URI); |
| else if (s) |
| p = s; |
| else |
| p = ""; |
| if (lookup == LOOKUP) |
| { s = qnames[Pair(p,name)]; |
| if (s) |
| return s; |
| } |
| t = buf; |
| if (!prefix || *prefix) |
| { s = p; |
| if (prefix && *prefix == '_') // ensures ns prefix starts with _... |
| { strcpy(t, prefix); |
| t += strlen(prefix); |
| } |
| if (s && *s) |
| { for (; *s; s++) |
| { if (isalnum(*s)) |
| *t++ = *s; |
| else if (*s == '-' && s != p) |
| *t++ = '_'; |
| else if (*s == '_') |
| { strcpy(t, "_USCORE"); |
| t += 7; |
| } |
| else |
| { s = utf8(t, s); |
| t += 6; |
| } |
| } |
| if (!prefix || *prefix != '*') |
| { *t++ = '_'; |
| *t++ = '_'; |
| } |
| } |
| else if (isdigit(*name)) |
| *t++ = '_'; |
| } |
| for (s = name; *s; s++) |
| { if (isalnum(*s)) |
| *t++ = *s; |
| else if (*s == '-' && s != name) |
| *t++ = '_'; |
| else if (*s == '_') |
| { strcpy(t, "_USCORE"); |
| t += 7; |
| } |
| else |
| { s = utf8(t, s); |
| t += 6; |
| } |
| } |
| *t = '\0'; |
| while (knames.find(buf) != knames.end() || (reserved && reserved->find(buf) != reserved->end())) |
| { *t++ = '_'; |
| *t = '\0'; |
| } |
| if (isalpha(*buf) || *buf == '_') |
| { t = (char*)emalloc(strlen(buf) + 1); |
| strcpy(t, buf); |
| } |
| else |
| { t = (char*)emalloc(strlen(buf) + 2); |
| *t = '_'; |
| strcpy(t + 1, buf); |
| } |
| if (lookup == LOOKUP) |
| qnames[Pair(p,name)] = t; |
| /* |
| cerr << "[DEFINED " << p << ":" << name << "=" << t << "]" << endl; |
| for (MapOfPairToString::const_iterator i = qnames.begin(); i != qnames.end(); ++i) |
| cerr << "(" << (*i).first.first << "," << (*i).first.second << ") = " << (*i).second << endl; |
| */ |
| return t; |
| } |
| |
| bool Types::is_defined(const char *prefix, const char *URI, const char *qname) |
| { const char *t = fname(prefix, URI, qname, NULL, LOOKUP); |
| return usetypemap[t] != NULL; |
| } |
| |
| const char *Types::aname(const char *prefix, const char *URI, const char *qname) |
| { return fname(prefix, URI, qname, NULL, NOLOOKUP); |
| } |
| |
| const char *Types::cname(const char *prefix, const char *URI, const char *qname) |
| { return fname(prefix, URI, qname, NULL, LOOKUP); |
| } |
| |
| const char *Types::tname(const char *prefix, const char *URI, const char *qname) |
| { const char *s, *t = cname(prefix, URI, qname); |
| s = usetypemap[t]; |
| if (!s) |
| { s = t; |
| fprintf(stream, "// Warning: internal error, undefined qname '%s' for type '%s'\n", qname?qname:"", t); |
| } |
| return s; |
| } |
| |
| const char *Types::tnameptr(bool flag, const char *prefix, const char *URI, const char *qname) |
| { const char *s = pname(flag, prefix, URI, qname); |
| if (flag) |
| { if (!strncmp(s, "char*", 5)) |
| return "char**"; |
| if (!strchr(s, '*')) |
| { char *r = (char*)emalloc(strlen(s) + 2); |
| strcpy(r, s); |
| strcat(r, "*"); |
| return r; |
| } |
| } |
| return s; |
| } |
| |
| const char *Types::pname(bool flag, const char *prefix, const char *URI, const char *qname) |
| { const char *r, *s, *t = cname(prefix, URI, qname); |
| if (flag) |
| { s = ptrtypemap[t]; |
| if (!s) |
| { s = usetypemap[t]; |
| if (!s || !*s) |
| { s = t; |
| fprintf(stream, "// Warning: internal error, undefined: %s %s\n", qname, t); |
| } |
| r = s; |
| do |
| { r = strchr(r + 1, '*'); |
| if (r && *(r-1) != '/' && *(r+1) != '/') |
| break; |
| } while (r); |
| if (!r) // already pointer? |
| { char *p = (char*)emalloc(strlen(s) + 2); |
| strcpy(p, s); |
| strcat(p, "*"); |
| s = p; |
| } |
| ptrtypemap[t] = s; |
| } |
| } |
| else |
| s = usetypemap[t]; |
| if (!s) |
| { s = t; |
| fprintf(stream, "// Warning: internal error, undefined: %s %s\n", qname, t); |
| } |
| return s; |
| } |
| |
| const char *Types::deftname(enum Type type, const char *pointer, bool is_pointer, const char *prefix, const char *URI, const char *qname) |
| { char buf[1024]; |
| const char *q = NULL, *t = fname(prefix, URI, qname, NULL, LOOKUP); |
| char *s; |
| if (deftypemap[t]) |
| return NULL; |
| switch (type) |
| { case ENUM: |
| q = "enum"; |
| if (yflag) |
| knames.insert(t); |
| break; |
| case STRUCT: |
| q = "struct"; |
| if (yflag) |
| knames.insert(t); |
| break; |
| case CLASS: |
| case TYPEDEF: |
| knames.insert(t); |
| default: |
| break; |
| } |
| if (q) |
| { strcpy(buf, q); |
| strcat(buf, " "); |
| } |
| else |
| buf[0] = '\0'; |
| strcat(buf, t); |
| if (pointer) |
| strcat(buf, pointer); |
| s = (char*)emalloc(strlen(buf) + 1); |
| strcpy(s, buf); |
| usetypemap[t] = s; |
| if (pointer || is_pointer) |
| ptrtypemap[t] = s; |
| return t; |
| } |
| |
| // get enumeration value. URI/type refers to the enum simpleType. |
| const char *Types::ename(const char *type, const char *value) |
| { const char *s = enames[Pair(type,value)]; |
| if (!s) |
| { s = fname(NULL, NULL, value, &rnames, NOLOOKUP); |
| if (!eflag && *type) |
| { // Add prefix to enum |
| char *buf = (char*)emalloc(strlen(type) + strlen(s) + 3); |
| if (s[0] == '_' && s[1] != 'x') // _xXXXX is OK here |
| sprintf(buf, "%s_%s", type, s); |
| else |
| sprintf(buf, "%s__%s", type, s); |
| s = buf; |
| } |
| else |
| rnames.insert(s); |
| enames[Pair(type,value)] = s; |
| } |
| return s; |
| } |
| |
| // get operation name |
| const char *Types::oname(const char *prefix, const char *URI, const char *qname) |
| { const char *s = fname(prefix, URI, qname, NULL, LOOKUP); |
| if (s && usetypemap[s]) |
| { // Avoid name clash with structs/classes of the same name |
| onames.insert(s); |
| } |
| s = fname(prefix, URI, qname, &onames, NOLOOKUP); |
| onames.insert(s); |
| return s; |
| } |
| |
| // generate struct name |
| const char *Types::sname(const char *URI, const char *name) |
| { const char *s; |
| char *t; |
| if (!aflag && name) |
| { size_t len = 0; |
| for (VectorOfString::const_iterator i = scope.begin(); i != scope.end(); ++i) |
| len += strlen(*i) + 1; |
| t = (char*)emalloc(len + strlen(name) + 1); |
| *t = '\0'; |
| for (VectorOfString::const_iterator j = scope.begin(); j != scope.end(); ++j) |
| { strcat(t, *j); |
| strcat(t, "-"); |
| } |
| strcat(t, name); |
| s = fname("_", URI, t, &rnames, NOLOOKUP); |
| rnames.insert(s); |
| } |
| else if (URI) |
| { s = nsprefix(NULL, URI); |
| t = (char*)emalloc(strlen(s) + 16); |
| sprintf(t, "_%s__struct_%d", s, snum++); |
| s = t; |
| } |
| else |
| { t = (char*)emalloc(16); |
| sprintf(t, "struct_%d", snum++); |
| s = t; |
| } |
| return s; |
| } |
| |
| // generate union name |
| const char *Types::uname(const char *URI) |
| { const char *s; |
| char *t; |
| if (!aflag) |
| { size_t len = 0; |
| for (VectorOfString::const_iterator i = scope.begin(); i != scope.end(); ++i) |
| len += strlen(*i) + 1; |
| t = (char*)emalloc(len + 6); |
| strcpy(t, "union"); |
| for (VectorOfString::const_iterator j = scope.begin(); j != scope.end(); ++j) |
| { strcat(t, "-"); |
| strcat(t, *j); |
| } |
| s = fname("_", URI, t, &rnames, NOLOOKUP); |
| rnames.insert(s); |
| } |
| else if (URI) |
| { s = nsprefix(NULL, URI); |
| t = (char*)emalloc(strlen(s) + 16); |
| sprintf(t, "_%s__union_%d", s, unum++); |
| s = t; |
| } |
| else |
| { t = (char*)emalloc(16); |
| sprintf(t, "_union_%d", unum++); |
| s = t; |
| } |
| return s; |
| } |
| |
| // generate enum name |
| const char *Types::gname(const char *URI, const char *name) |
| { const char *s; |
| char *t; |
| if (!aflag && name) |
| { size_t len = 0; |
| for (VectorOfString::const_iterator i = scope.begin(); i != scope.end(); ++i) |
| len += strlen(*i) + 1; |
| t = (char*)emalloc(len + strlen(name) + 1); |
| *t = '\0'; |
| for (VectorOfString::const_iterator j = scope.begin(); j != scope.end(); ++j) |
| { strcat(t, *j); |
| strcat(t, "-"); |
| } |
| strcat(t, name); |
| s = fname("_", URI, t, &rnames, NOLOOKUP); |
| rnames.insert(s); |
| } |
| else if (URI) |
| { s = nsprefix(NULL, URI); |
| t = (char*)emalloc(strlen(s) + 16); |
| sprintf(t, "_%s__enum_%d", s, gnum++); |
| s = t; |
| } |
| else |
| { t = (char*)emalloc(16); |
| sprintf(t, "enum_%d", gnum++); |
| s = t; |
| } |
| return s; |
| } |
| |
| // check if nillable or minOccurs=0 (and no default value is present) |
| bool Types::is_nillable(const xs__element& element) |
| { return !element.default_ && (element.nillable || (element.minOccurs && !strcmp(element.minOccurs, "0"))); |
| } |
| |
| bool Types::is_basetype(const char *type) |
| { if (!strcmp(type, "xs:anyType") |
| || !strcmp(tname(NULL, NULL, type), "std::string")) |
| return false; |
| return !strncmp(type, "xs:", 3) || !strncmp(type, "SOAP-ENC:", 9); |
| } |
| |
| void Types::define(const char *URI, const char *name, const xs__complexType& complexType) |
| { // generate prototype for structs/classes and store name |
| const char *prefix = NULL; |
| if (complexType.name) |
| name = complexType.name; |
| else |
| prefix = "_"; |
| if (complexType.complexContent && complexType.complexContent->restriction && !strcmp(complexType.complexContent->restriction->base, "SOAP-ENC:Array")) |
| { if (strcmp(schema_prefix, "ns")) |
| prefix = "*"; |
| else |
| prefix = ""; |
| } |
| if (cflag) |
| { const char *t = deftname(STRUCT, "*", true, prefix, URI, name); |
| if (t) |
| { if (yflag) |
| fprintf(stream, "\n/// Typedef synonym for struct %s.\ntypedef struct %s %s;\n", t, t, t); |
| } |
| else if (name) |
| { t = deftypemap[cname(prefix, URI, name)]; |
| if (t) |
| { fprintf(stream, "\n/// Imported complexType \"%s\":%s from typemap %s.\n", URI, name, mapfile?mapfile:""); |
| document(complexType.annotation); |
| if (*t) |
| format(t); |
| else |
| fprintf(stream, "// complexType definition intentionally left blank.\n"); |
| } |
| } |
| } |
| else |
| { const char *t = deftname(CLASS, "*", true, prefix, URI, name); |
| if (t) |
| fprintf(stream, "\n// Forward declaration of class %s.\nclass %s;\n", t, t); |
| else if (name) |
| { t = deftypemap[cname(prefix, URI, name)]; |
| if (t) |
| { fprintf(stream, "\n/// Imported complexType \"%s\":%s from typemap %s.\n", URI, name, mapfile?mapfile:""); |
| document(complexType.annotation); |
| if (*t) |
| format(t); |
| else |
| fprintf(stream, "// complexType definition intentionally left blank.\n"); |
| } |
| } |
| } |
| } |
| |
| void Types::gen(const char *URI, const char *name, const xs__simpleType& simpleType, bool anonymous) |
| { const char *t = NULL; |
| const char *prefix = NULL; |
| if (simpleType.name) |
| name = simpleType.name; |
| else |
| prefix = "_"; |
| if (!anonymous) |
| { t = deftypemap[cname(NULL, URI, name)]; |
| if (t) |
| { fprintf(stream, "\n/// Imported simpleType \"%s\":%s from typemap %s.\n", URI, name, mapfile?mapfile:""); |
| document(simpleType.annotation); |
| if (*t) |
| format(t); |
| else |
| fprintf(stream, "// simpleType definition intentionally left blank.\n"); |
| return; |
| } |
| } |
| if (simpleType.restriction && simpleType.restriction->base) |
| { if (!anonymous) |
| fprintf(stream, "\n/// \"%s\":%s is a simpleType restriction of %s.\n", URI?URI:"", name, simpleType.restriction->base); |
| document(simpleType.annotation); |
| document(simpleType.restriction->annotation); |
| if (!simpleType.restriction->enumeration.empty()) |
| { bool is_numeric = true; // check if all enumeration values are numeric |
| bool is_qname = !strcmp(simpleType.restriction->base, "xs:QName"); |
| if (!anonymous) |
| { t = deftname(ENUM, NULL, false, prefix, URI, name); |
| if (t && !eflag) |
| fprintf(stream, "/// Note: enum values are prefixed with '%s' to avoid name clashes, please use wsdl2h option -e to omit this prefix\n", t); |
| } |
| else |
| t = gname(URI, name); |
| if (!anonymous) |
| fprintf(stream, "enum %s\n{\n", t); |
| else |
| fprintf(stream, " enum %s\n {\n", t); |
| for (vector<xs__enumeration>::const_iterator enumeration1 = simpleType.restriction->enumeration.begin(); enumeration1 != simpleType.restriction->enumeration.end(); ++enumeration1) |
| { const char *s; |
| if ((s = (*enumeration1).value)) |
| is_numeric &= is_integer(s); |
| } |
| SetOfString enumvals; |
| for (vector<xs__enumeration>::const_iterator enumeration2 = simpleType.restriction->enumeration.begin(); enumeration2 != simpleType.restriction->enumeration.end(); ++enumeration2) |
| { const char *s; |
| document((*enumeration2).annotation); |
| if ((s = (*enumeration2).value)) |
| { if (!enumvals.count(s)) |
| { enumvals.insert(s); |
| if (is_numeric) |
| fprintf(stream, "\t%s = %s,\t///< %s value=\"%s\"\n", ename(t, s), s, simpleType.restriction->base, s); |
| else if (is_qname && (*enumeration2).value_) |
| fprintf(stream, "\t%s,\t///< %s value=\"%s\"\n", ename(t, (*enumeration2).value_), simpleType.restriction->base, (*enumeration2).value_); |
| else |
| fprintf(stream, "\t%s,\t///< %s value=\"%s\"\n", ename(t, s), simpleType.restriction->base, s); |
| } |
| } |
| else |
| fprintf(stream, "//\tunrecognized: enumeration '%s' has no value\n", name?name:""); |
| } |
| if (!anonymous) |
| { fprintf(stream, "};\n"); |
| if (yflag) |
| fprintf(stream, "/// Typedef synonym for enum %s.\ntypedef enum %s %s;\n", t, t, t); |
| if (pflag) |
| { const char *s = aname(prefix, URI, name); |
| knames.insert(s); |
| s = aname(prefix, URI, name); |
| fprintf(stream, "\n/// Class wrapper\n"); |
| fprintf(stream, "class %s : public xsd__anyType\n{ public:\n", s); |
| fprintf(stream, elementformat, tname(prefix, URI, name), "__item;"); |
| modify(s); |
| fprintf(stream, "\n};\n"); |
| } |
| } |
| else |
| fprintf(stream, " }\n"); |
| } |
| else |
| { if (simpleType.restriction->length && simpleType.restriction->length->value) |
| fprintf(stream, "/// Length of this string is exactly %s characters\n", simpleType.restriction->length->value); |
| else |
| { const char *a = NULL, *b = NULL; |
| if (simpleType.restriction->minLength) |
| a = simpleType.restriction->minLength->value; |
| if (simpleType.restriction->maxLength) |
| b = simpleType.restriction->maxLength->value; |
| if (a || b) |
| fprintf(stream, "/// Length of this string is within %s..%s characters\n", a?a:"0", b?b:""); |
| } |
| if (simpleType.restriction->precision && simpleType.restriction->precision->value) |
| fprintf(stream, "/// %sprecision is %s\n", simpleType.restriction->precision->fixed?"fixed ":"", simpleType.restriction->precision->value); |
| if (simpleType.restriction->scale && simpleType.restriction->scale->value) |
| fprintf(stream, "/// %sscale is %s\n", simpleType.restriction->scale->fixed?"fixed ":"", simpleType.restriction->scale->value); |
| if (simpleType.restriction->totalDigits && simpleType.restriction->totalDigits->value) |
| fprintf(stream, "/// %snumber of total digits is %s\n", simpleType.restriction->totalDigits->fixed?"fixed ":"", simpleType.restriction->totalDigits->value); |
| if (simpleType.restriction->fractionDigits && simpleType.restriction->fractionDigits->value) |
| fprintf(stream, "/// %snumber of fraction digits is %s\n", simpleType.restriction->fractionDigits->fixed?"fixed ":"", simpleType.restriction->fractionDigits->value); |
| for (vector<xs__pattern>::const_iterator pattern1 = simpleType.restriction->pattern.begin(); pattern1 != simpleType.restriction->pattern.end(); ++pattern1) |
| fprintf(stream, "/// Content pattern is \"%s\"\n", xstring((*pattern1).value)); |
| const char *ai = NULL, *ae = NULL, *bi = NULL, *be = NULL; |
| if (simpleType.restriction->minInclusive) |
| ai = simpleType.restriction->minInclusive->value; |
| else if (simpleType.restriction->minExclusive) |
| ae = simpleType.restriction->minExclusive->value; |
| if (simpleType.restriction->maxInclusive) |
| bi = simpleType.restriction->maxInclusive->value; |
| else if (simpleType.restriction->maxExclusive) |
| be = simpleType.restriction->maxExclusive->value; |
| if (ai || ae || bi || be) |
| { fprintf(stream, "/// Value range is "); |
| if (ai) |
| fprintf(stream, "[%s..", ai); |
| else if (ae) |
| fprintf(stream, "(%s..", ae); |
| else |
| fprintf(stream, "[-INF.."); |
| if (bi) |
| fprintf(stream, "%s]\n", bi); |
| else if (be) |
| fprintf(stream, "%s)\n", be); |
| else |
| fprintf(stream, "INF]\n"); |
| } |
| if (!simpleType.restriction->attribute.empty()) |
| { fprintf(stderr, "\nWarning: simpleType '%s' should not have attributes\n", name?name:""); |
| } |
| const char *s = tname(NULL, NULL, simpleType.restriction->base); |
| if (!anonymous) |
| { bool is_ptr = false; |
| is_ptr = (strchr(s, '*') != NULL) || (s == pname(true, NULL, NULL, simpleType.restriction->base)); |
| t = deftname(TYPEDEF, NULL, is_ptr, prefix, URI, name); |
| if (t) |
| fprintf(stream, "typedef %s %s", s, t); |
| } |
| else |
| { t = ""; |
| fprintf(stream, elementformat, s, ""); |
| fprintf(stream, "\n"); |
| } |
| if (t) |
| { if (!anonymous && !simpleType.restriction->pattern.empty()) |
| { fprintf(stream, " \""); |
| for (vector<xs__pattern>::const_iterator pattern2 = simpleType.restriction->pattern.begin(); pattern2 != simpleType.restriction->pattern.end(); ++pattern2) |
| { if (pattern2 != simpleType.restriction->pattern.begin()) |
| fprintf(stream, "|"); |
| fprintf(stream, "%s", xstring((*pattern2).value)); |
| } |
| fprintf(stream, "\""); |
| } |
| // add range info only when type is numeric |
| bool is_numeric = false; |
| if (!strncmp(s, "unsigned ", 9)) |
| s += 9; |
| if (strstr("char short int LONG64 float double ", s)) |
| is_numeric = true; |
| if (!anonymous && simpleType.restriction->minLength && simpleType.restriction->minLength->value) |
| fprintf(stream, " %s", simpleType.restriction->minLength->value); |
| else if (is_numeric && !anonymous && simpleType.restriction->minInclusive && simpleType.restriction->minInclusive->value && is_integer(simpleType.restriction->minInclusive->value)) |
| fprintf(stream, " %s", simpleType.restriction->minInclusive->value); |
| if (!anonymous && simpleType.restriction->maxLength && simpleType.restriction->maxLength->value) |
| fprintf(stream, ":%s", simpleType.restriction->maxLength->value); |
| else if (is_numeric && !anonymous && simpleType.restriction->maxInclusive && simpleType.restriction->maxInclusive->value && is_integer(simpleType.restriction->maxInclusive->value)) |
| fprintf(stream, ":%s", simpleType.restriction->maxInclusive->value); |
| if (!anonymous) |
| { fprintf(stream, ";\n"); |
| if (pflag) |
| { const char *s = aname(prefix, URI, name); |
| knames.insert(s); |
| s = aname(prefix, URI, name); |
| fprintf(stream, "\n/// Class wrapper\n"); |
| fprintf(stream, "class %s : public xsd__anyType\n{ public:\n", s); |
| fprintf(stream, elementformat, tname(prefix, URI, name), "__item;"); |
| modify(s); |
| fprintf(stream, "\n};\n"); |
| } |
| } |
| } |
| } |
| } |
| else if (simpleType.list) |
| { if (simpleType.list->restriction && simpleType.list->restriction->base) |
| { if (!anonymous) |
| fprintf(stream, "\n/// \"%s\":%s is a simpleType list restriction of %s.\n", URI?URI:"", name, simpleType.list->restriction->base); |
| document(simpleType.annotation); |
| if (!anonymous) |
| { t = deftname(ENUM, NULL, false, prefix, URI, name); |
| if (t) |
| fprintf(stream, "enum * %s\n{\n", t); |
| } |
| else |
| { t = ""; |
| fprintf(stream, "enum *\n{\n"); |
| } |
| if (t) |
| { for (vector<xs__enumeration>::const_iterator enumeration = simpleType.list->restriction->enumeration.begin(); enumeration != simpleType.list->restriction->enumeration.end(); ++enumeration) |
| { if ((*enumeration).value) |
| { if (!strcmp(simpleType.list->restriction->base, "xs:QName") && (*enumeration).value_) |
| fprintf(stream, "\t%s,\t///< %s value=\"%s\"\n", ename(t, (*enumeration).value_), simpleType.list->restriction->base, (*enumeration).value_); |
| else |
| fprintf(stream, "\t%s,\t///< %s value=\"%s\"\n", ename(t, (*enumeration).value), simpleType.list->restriction->base, (*enumeration).value); |
| } |
| else |
| fprintf(stream, "//\tunrecognized: bitmask enumeration '%s' has no value\n", t); |
| } |
| if (!anonymous) |
| { fprintf(stream, "};\n"); |
| if (yflag) |
| fprintf(stream, "/// Typedef synonym for enum %s.\ntypedef enum %s %s;\n", t, t, t); |
| if (pflag) |
| { const char *s = aname(prefix, URI, name); |
| knames.insert(s); |
| s = aname(prefix, URI, name); |
| fprintf(stream, "\n/// Class wrapper\n"); |
| fprintf(stream, "class %s : public xsd__anyType\n{ public:\n", s); |
| fprintf(stream, elementformat, tname(prefix, URI, name), "__item;"); |
| modify(s); |
| fprintf(stream, "\n};\n"); |
| } |
| } |
| else |
| fprintf(stream, "}\n"); |
| } |
| } |
| else if (simpleType.list->itemType) |
| { const xs__simpleType *p = simpleType.list->itemTypePtr(); |
| if (p && p->restriction && p->restriction->base && !p->restriction->enumeration.empty() && p->restriction->enumeration.size() <= 64) |
| { if (!anonymous) |
| fprintf(stream, "\n/// \"%s\":%s is a simpleType list of %s.\n", URI?URI:"", name, simpleType.list->itemType); |
| document(simpleType.annotation); |
| if (!anonymous) |
| { t = deftname(ENUM, NULL, false, prefix, URI, name); |
| if (t) |
| fprintf(stream, "enum * %s\n{\n", t); |
| } |
| else |
| { t = ""; |
| fprintf(stream, "enum *\n{\n"); |
| } |
| if (t) |
| { for (vector<xs__enumeration>::const_iterator enumeration = p->restriction->enumeration.begin(); enumeration != p->restriction->enumeration.end(); ++enumeration) |
| { if ((*enumeration).value) |
| fprintf(stream, "\t%s,\t///< %s value=\"%s\"\n", ename(t, (*enumeration).value), p->restriction->base, (*enumeration).value); |
| else |
| fprintf(stream, "//\tunrecognized: bitmask enumeration '%s' has no value\n", t); |
| } |
| if (!anonymous) |
| { fprintf(stream, "};\n"); |
| if (yflag) |
| fprintf(stream, "/// Typedef synonym for enum %s.\ntypedef enum %s %s;\n", t, t, t); |
| if (pflag) |
| { const char *s = aname(prefix, URI, name); |
| knames.insert(s); |
| s = aname(prefix, URI, name); |
| fprintf(stream, "\n/// Class wrapper.\n"); |
| fprintf(stream, "class %s : public xsd__anyType\n{ public:\n", s); |
| fprintf(stream, elementformat, tname(prefix, URI, name), "__item;"); |
| modify(s); |
| fprintf(stream, "\n};\n"); |
| } |
| } |
| else |
| fprintf(stream, "}\n"); |
| } |
| } |
| else |
| { const char *s = tname(NULL, NULL, "xsd:string"); |
| if (!anonymous) |
| { fprintf(stream, "\n/// \"%s\":%s is a simpleType containing a whitespace separated list of %s.\n", URI?URI:"", name, simpleType.list->itemType); |
| t = deftname(TYPEDEF, NULL, strchr(s, '*') != NULL, prefix, URI, name); |
| } |
| document(simpleType.annotation); |
| if (t) |
| fprintf(stream, "typedef %s %s;\n", s, t); |
| else |
| { fprintf(stream, elementformat, s, ""); |
| fprintf(stream, "\n"); |
| } |
| } |
| } |
| else |
| { if (!anonymous) |
| fprintf(stream, "\n/// \"%s\":%s is a simpleType list.\n", URI?URI:"", name); |
| document(simpleType.annotation); |
| if (!anonymous) |
| { t = deftname(ENUM, NULL, false, prefix, URI, name); |
| if (t && !eflag) |
| fprintf(stream, "/// Note: enum values are prefixed with '%s' to avoid name clashes, please use wsdl2h option -e to omit this prefix\n", t); |
| } |
| else |
| t = ""; |
| if (t) |
| { fprintf(stream, "enum * %s\n{\n", t); |
| for (vector<xs__simpleType>::const_iterator simple = simpleType.list->simpleType.begin(); simple != simpleType.list->simpleType.end(); ++simple) |
| { if ((*simple).restriction && (*simple).restriction->base) |
| { for (vector<xs__enumeration>::const_iterator enumeration = (*simple).restriction->enumeration.begin(); enumeration != (*simple).restriction->enumeration.end(); ++enumeration) |
| { if ((*enumeration).value) |
| fprintf(stream, "\t%s,\t///< %s value=\"%s\"\n", ename(t, (*enumeration).value), (*simple).restriction->base, (*enumeration).value); |
| else |
| fprintf(stream, "//\tunrecognized: bitmask enumeration '%s' has no value\n", t); |
| } |
| } |
| } |
| if (!anonymous) |
| { fprintf(stream, "};\n"); |
| if (yflag) |
| fprintf(stream, "/// Typedef synonym for enum %s.\ntypedef enum %s %s;\n", t, t, t); |
| if (pflag) |
| { const char *s = aname(prefix, URI, name); |
| knames.insert(s); |
| s = aname(prefix, URI, name); |
| fprintf(stream, "\n/// Class wrapper.\n"); |
| fprintf(stream, "class %s : public xsd__anyType\n{ public:\n", s); |
| fprintf(stream, elementformat, tname(prefix, URI, name), "__item;"); |
| modify(s); |
| fprintf(stream, "\n};\n"); |
| } |
| } |
| else |
| fprintf(stream, "}\n"); |
| } |
| } |
| } |
| else if (simpleType.union_) |
| { if (simpleType.union_->memberTypes) |
| { const char *s = tname(NULL, NULL, "xsd:string"); |
| if (!anonymous) |
| t = deftname(TYPEDEF, NULL, strchr(s, '*') != NULL, prefix, URI, name); |
| fprintf(stream, "\n/// union of values \"%s\"\n", simpleType.union_->memberTypes); |
| if (t) |
| fprintf(stream, "typedef %s %s;\n", s, t); |
| else |
| { fprintf(stream, elementformat, s, ""); |
| fprintf(stream, "\n"); |
| } |
| } |
| else if (!simpleType.union_->simpleType.empty()) |
| { const char *s = tname(NULL, NULL, "xsd:string"); |
| fprintf(stream, "\n"); |
| if (!anonymous) |
| t = deftname(TYPEDEF, NULL, strchr(s, '*') != NULL, prefix, URI, name); |
| for (vector<xs__simpleType>::const_iterator simpleType1 = simpleType.union_->simpleType.begin(); simpleType1 != simpleType.union_->simpleType.end(); ++simpleType1) |
| if ((*simpleType1).restriction) |
| { fprintf(stream, "/// union of values from \"%s\"\n", (*simpleType1).restriction->base); |
| // TODO: are there any other types we should report here? |
| } |
| if (t) |
| fprintf(stream, "typedef %s %s;\n", s, t); |
| else |
| { fprintf(stream, elementformat, s, ""); |
| fprintf(stream, "\n"); |
| } |
| } |
| else |
| fprintf(stream, "//\tunrecognized\n"); |
| } |
| else |
| fprintf(stream, "//\tunrecognized simpleType\n"); |
| } |
| |
| void Types::gen(const char *URI, const char *name, const xs__complexType& complexType, bool anonymous) |
| { const char *t = NULL; |
| bool soapflag = false; |
| if (complexType.name) |
| name = complexType.name; |
| if (anonymous && name) |
| t = sname(URI, name); |
| else if (name) |
| { t = cname(NULL, URI, name); |
| if (deftypemap[t]) |
| return; |
| } |
| if (name) |
| scope.push_back(name); |
| if (complexType.simpleContent) |
| { if (!anonymous) |
| fprintf(stream, "\n/// \"%s\":%s is a%s complexType with simpleContent.\n", URI?URI:"", name, complexType.abstract?"n abstract":""); |
| document(complexType.annotation); |
| if (complexType.simpleContent->restriction) |
| { if (anonymous) |
| fprintf(stream, " struct %s\n {\n", t); |
| else if (cflag) |
| fprintf(stream, "struct %s\n{\n", t); |
| else if (pflag) |
| fprintf(stream, "class %s : public xsd__anyType\n{ public:\n", t); |
| else |
| fprintf(stream, "class %s\n{ public:\n", t); |
| const char *base = "xs:string"; |
| const xs__complexType *complextype = &complexType; |
| do |
| { if (!complextype->simpleContent) |
| break; |
| if (complextype->simpleContent->restriction) |
| { if (complextype->simpleContent->restriction->complexTypePtr()) |
| complextype = complextype->simpleContent->restriction->complexTypePtr(); |
| else |
| { base = complextype->simpleContent->restriction->base; |
| break; |
| } |
| } |
| else if (complextype->simpleContent->extension) |
| { if (complextype->simpleContent->extension->complexTypePtr()) |
| complextype = complextype->simpleContent->extension->complexTypePtr(); |
| else |
| { base = complextype->simpleContent->extension->base; |
| break; |
| } |
| } |
| else |
| break; |
| } |
| while (complextype); |
| fprintf(stream, "/// __item wraps '%s' simpleContent.\n", base); |
| fprintf(stream, elementformat, tname(NULL, NULL, base), "__item"); |
| fprintf(stream, ";\n"); |
| gen(URI, complexType.simpleContent->restriction->attribute); |
| if (complexType.simpleContent->restriction->anyAttribute) |
| gen(URI, *complexType.simpleContent->restriction->anyAttribute); |
| } |
| else if (complexType.simpleContent->extension) |
| { if (cflag || fflag || anonymous) |
| { if (anonymous) |
| fprintf(stream, " struct %s\n {\n", t); |
| else if (cflag) |
| fprintf(stream, "struct %s\n{\n", t); |
| else if (pflag) |
| fprintf(stream, "class %s : public xsd__anyType\n{ public:\n", t); |
| else |
| fprintf(stream, "class %s\n{ public:\n", t); |
| const char *base = "xs:string"; |
| const xs__complexType *p = &complexType; |
| do |
| { if (!p->simpleContent) |
| break; |
| if (p->simpleContent->restriction) |
| { if (p->simpleContent->restriction->complexTypePtr()) |
| p = p->simpleContent->restriction->complexTypePtr(); |
| else |
| { base = p->simpleContent->restriction->base; |
| break; |
| } |
| } |
| else if (p->simpleContent->extension) |
| { if (p->simpleContent->extension->complexTypePtr()) |
| p = p->simpleContent->extension->complexTypePtr(); |
| else |
| { base = p->simpleContent->extension->base; |
| break; |
| } |
| } |
| else |
| break; |
| } |
| while (p); |
| fprintf(stream, "/// __item wraps '%s' simpleContent.\n", base); |
| fprintf(stream, elementformat, tname(NULL, NULL, base), "__item"); |
| fprintf(stream, ";\n"); |
| p = &complexType; |
| bool flag = true; |
| do |
| { if (!p->simpleContent) |
| break; |
| if (p->simpleContent->restriction) |
| { gen(URI, p->simpleContent->restriction->attribute); |
| if (p->simpleContent->restriction->anyAttribute && flag) |
| gen(URI, *p->simpleContent->restriction->anyAttribute); |
| break; |
| } |
| else if (p->simpleContent->extension) |
| { gen(URI, p->simpleContent->extension->attribute); |
| gen(URI, p->simpleContent->extension->attributeGroup); |
| if (p->simpleContent->extension->anyAttribute && flag) |
| { gen(URI, *p->simpleContent->extension->anyAttribute); |
| flag = false; |
| } |
| if (p->simpleContent->extension->complexTypePtr()) |
| p = p->simpleContent->extension->complexTypePtr(); |
| else |
| break; |
| } |
| else |
| break; |
| } |
| while (p); |
| } |
| else |
| { if ( |
| /* TODO: should add check for base type == class |
| complexType.simpleContent->extension->simpleTypePtr() |
| || |
| */ |
| complexType.simpleContent->extension->complexTypePtr()) |
| { fprintf(stream, "class %s : public %s\n{ public:\n", t, cname(NULL, NULL, complexType.simpleContent->extension->base)); |
| soapflag = true; |
| } |
| else |
| { if (pflag) |
| fprintf(stream, "class %s : public xsd__anyType\n{ public:\n", t); |
| else |
| fprintf(stream, "class %s\n{ public:\n", t); |
| fprintf(stream, "/// __item wraps '%s' simpleContent.\n", complexType.simpleContent->extension->base); |
| fprintf(stream, elementformat, tname(NULL, NULL, complexType.simpleContent->extension->base), "__item"); |
| fprintf(stream, ";\n"); |
| } |
| gen(URI, complexType.simpleContent->extension->attribute); |
| gen(URI, complexType.simpleContent->extension->attributeGroup); |
| if (complexType.simpleContent->extension->anyAttribute) |
| gen(URI, *complexType.simpleContent->extension->anyAttribute); |
| } |
| } |
| else |
| fprintf(stream, "//\tunrecognized\n"); |
| } |
| else if (complexType.complexContent) |
| { if (complexType.complexContent->restriction) |
| { if (!anonymous) |
| fprintf(stream, "\n/// \"%s\":%s is a%s complexType with complexContent restriction of %s.\n", URI?URI:"", name, complexType.abstract?"n abstract":"", complexType.complexContent->restriction->base); |
| document(complexType.annotation); |
| if (!strcmp(complexType.complexContent->restriction->base, "SOAP-ENC:Array")) |
| { char *item = NULL, *type = NULL; |
| if (!complexType.complexContent->restriction->attribute.empty()) |
| { xs__attribute& attribute = complexType.complexContent->restriction->attribute.front(); |
| if (attribute.wsdl__arrayType) |
| { type = (char*)malloc(strlen(attribute.wsdl__arrayType)+1); |
| strcpy(type, attribute.wsdl__arrayType); |
| } |
| } |
| if (complexType.complexContent->restriction->sequence && !complexType.complexContent->restriction->sequence->element.empty()) |
| { xs__element& element = complexType.complexContent->restriction->sequence->element.front(); |
| if (!type) |
| { type = (char*)malloc(strlen(element.type)+1); |
| strcpy(type, element.type); |
| } |
| item = element.name; |
| } |
| gen_soap_array(name, t, item, type); |
| if (type) |
| free(type); |
| } |
| else |
| { if (anonymous) |
| fprintf(stream, " struct %s\n {\n", t); |
| else if (cflag) |
| fprintf(stream, "struct %s\n{\n", t); |
| else if (pflag) |
| fprintf(stream, "class %s : public xsd__anyType\n{ public:\n", t); |
| else |
| fprintf(stream, "class %s\n{ public:\n", t); |
| if (!complexType.mixed) |
| { if (complexType.complexContent->restriction->group) |
| gen(URI, *complexType.complexContent->restriction->group); |
| if (complexType.complexContent->restriction->all) |
| gen(URI, *complexType.complexContent->restriction->all); |
| if (complexType.complexContent->restriction->sequence) |
| gen(URI, *complexType.complexContent->restriction->sequence); |
| if (complexType.complexContent->restriction->choice) |
| gen(URI, name, *complexType.complexContent->restriction->choice); |
| } |
| else |
| { fprintf(stream, "/// TODO: mixed complexType/complexContent is user-definable.\n// Consult the protocol documentation to change or insert declarations.\n"); |
| fprintf(stream, elementformat, "_XML", "__any"); |
| fprintf(stream, ";\t///< Catch any element content in XML string\n"); |
| } |
| gen(URI, complexType.complexContent->restriction->attribute); |
| } |
| } |
| else if (complexType.complexContent->extension) |
| { if (!anonymous) |
| fprintf(stream, "\n/// \"%s\":%s is a%s complexType with complexContent extension of %s.\n", URI?URI:"", name, complexType.abstract?"n abstract":"", complexType.complexContent->extension->base); |
| document(complexType.annotation); |
| if (anonymous) |
| fprintf(stream, " struct %s\n {\n", t); |
| else if (cflag) |
| fprintf(stream, "struct %s\n{\n", t); |
| else if (fflag) |
| fprintf(stream, "class %s\n{ public:\n", t); |
| else // TODO: what to do if base class is in another namespace and elements must be qualified in XML payload? |
| { fprintf(stream, "class %s : public %s\n{ public:\n", t, cname(NULL, NULL, complexType.complexContent->extension->base)); |
| soapflag = true; |
| } |
| xs__complexType *p = complexType.complexContent->extension->complexTypePtr(); |
| while (p) |
| { const char *pURI = p->schemaPtr()->targetNamespace; |
| const char *b = cname(NULL, pURI, p->name); |
| static int nesting = 0; |
| if (cflag || fflag || anonymous) |
| fprintf(stream, "/// INHERITED FROM %s:\n", b); |
| else if (nesting == 0) |
| fprintf(stream, "/* INHERITED FROM %s:\n", b); |
| else |
| fprintf(stream, " INHERITED FROM %s:\n", b); |
| nesting++; |
| if (p->complexContent && p->complexContent->extension) |
| { if (p->complexContent->extension->group) |
| gen(pURI, *p->complexContent->extension->group); // schema URI? |
| if (p->complexContent->extension->all) |
| gen(pURI, *p->complexContent->extension->all); |
| if (p->complexContent->extension->sequence) |
| gen(pURI, *p->complexContent->extension->sequence); |
| if (p->complexContent->extension->choice) |
| gen(pURI, p->name, *p->complexContent->extension->choice); |
| gen(pURI, p->complexContent->extension->attribute); |
| gen(pURI, p->complexContent->extension->attributeGroup); |
| if (p->complexContent->extension->anyAttribute) |
| gen(pURI, *p->complexContent->extension->anyAttribute); |
| p = p->complexContent->extension->complexTypePtr(); |
| modify(b); |
| nesting--; |
| if (cflag || fflag || anonymous) |
| fprintf(stream, "// END OF INHERITED\n"); |
| else if (nesting == 0) |
| fprintf(stream, " END OF INHERITED */\n"); |
| else |
| fprintf(stream, " END OF INHERITED\n"); |
| } |
| else |
| { if (p->all) |
| gen(pURI, p->all->element); // what about schema URI? |
| else if (p->choice) |
| gen(pURI, p->name, *p->choice); |
| else if (p->all) |
| gen(pURI, *p->all); |
| else if (p->sequence) |
| gen(pURI, *p->sequence); |
| else if (p->any) |
| gen(pURI, *p->any); |
| gen(pURI, p->attribute); |
| gen(pURI, p->attributeGroup); |
| if (p->anyAttribute) |
| gen(pURI, *p->anyAttribute); |
| modify(b); |
| nesting--; |
| if (cflag || fflag || anonymous) |
| fprintf(stream, "// END OF INHERITED\n"); |
| else if (nesting == 0) |
| fprintf(stream, " END OF INHERITED */\n"); |
| else |
| fprintf(stream, " END OF INHERITED\n"); |
| break; |
| } |
| } |
| if (complexType.complexContent->extension->group) |
| gen(URI, *complexType.complexContent->extension->group); |
| if (complexType.complexContent->extension->all) |
| gen(URI, *complexType.complexContent->extension->all); |
| if (complexType.complexContent->extension->sequence) |
| gen(URI, *complexType.complexContent->extension->sequence); |
| if (complexType.complexContent->extension->choice) |
| gen(URI, name, *complexType.complexContent->extension->choice); |
| gen(URI, complexType.complexContent->extension->attribute); |
| gen(URI, complexType.complexContent->extension->attributeGroup); |
| if (complexType.complexContent->extension->anyAttribute) |
| gen(URI, *complexType.complexContent->extension->anyAttribute); |
| } |
| else |
| fprintf(stream, "//\tunrecognized\n"); |
| } |
| else |
| { if (!anonymous) |
| fprintf(stream, "\n/// \"%s\":%s is a%s complexType.\n", URI?URI:"", name, complexType.abstract?"n abstract":""); |
| document(complexType.annotation); |
| if (anonymous) |
| fprintf(stream, " struct %s\n {\n", t); |
| else if (cflag) |
| fprintf(stream, "struct %s\n{\n", t); |
| else if (pflag) |
| fprintf(stream, "class %s : public xsd__anyType\n{ public:\n", t); |
| else |
| fprintf(stream, "class %s\n{ public:\n", t); |
| if (complexType.all) |
| gen(URI, *complexType.all); |
| else if (complexType.choice) |
| gen(URI, name, *complexType.choice); |
| else if (complexType.sequence) |
| gen(URI, *complexType.sequence); |
| else if (complexType.any) |
| gen(URI, *complexType.any); |
| } |
| gen(URI, complexType.attribute); |
| gen(URI, complexType.attributeGroup); |
| if (complexType.anyAttribute) |
| gen(URI, *complexType.anyAttribute); |
| if (!anonymous) |
| { if (!cflag && !pflag && !soapflag) |
| { if (!complexType.complexContent || !complexType.complexContent->extension || !complexType.complexContent->extension->complexTypePtr()) |
| { fprintf(stream, "/// A handle to the soap struct that manages this instance (automatically set)\n"); |
| fprintf(stream, pointerformat, "struct soap", "soap"); |
| fprintf(stream, ";\n"); |
| } |
| } |
| modify(t); |
| fprintf(stream, "};\n"); |
| } |
| scope.pop_back(); |
| } |
| |
| void Types::gen(const char *URI, const vector<xs__attribute>& attributes) |
| { for (vector<xs__attribute>::const_iterator attribute = attributes.begin(); attribute != attributes.end(); ++attribute) |
| gen(URI, *attribute); |
| } |
| |
| void Types::gen(const char *URI, const xs__attribute& attribute) |
| { const char *name, *type, *nameURI = NULL, *typeURI = NULL; |
| name = attribute.name; |
| type = attribute.type; |
| bool is_optional = attribute.use != required && attribute.use != default_; |
| document(attribute.annotation); |
| if (!URI || strcmp(URI, attribute.schemaPtr()->targetNamespace)) |
| nameURI = attribute.schemaPtr()->targetNamespace; |
| if (attribute.attributePtr()) // attribute ref |
| { name = attribute.attributePtr()->name; |
| if (attribute.schemaPtr() != attribute.attributePtr()->schemaPtr()) |
| nameURI = attribute.attributePtr()->schemaPtr()->targetNamespace; |
| if (attribute.attributePtr()->type) |
| { type = attribute.attributePtr()->type; |
| } |
| else |
| { type = name; |
| typeURI = attribute.attributePtr()->schemaPtr()->targetNamespace; |
| } |
| fprintf(stream, "/// Attribute reference %s.\n", attribute.ref); |
| document(attribute.attributePtr()->annotation); |
| fprintf(stream, attributeformat, pname(is_optional, NULL, typeURI, type), aname(NULL, nameURI, name)); // make sure no name - type clash |
| } |
| else if (name && type) |
| { fprintf(stream, "/// Attribute %s of type %s.\n", name, type); |
| fprintf(stream, attributeformat, pname(is_optional, NULL, NULL, type), aname(NULL, nameURI, name)); // make sure no name - type clash |
| } |
| else if (name && attribute.simpleTypePtr()) |
| { fprintf(stream, "@"); |
| gen(URI, name, *attribute.simpleTypePtr(), true); |
| fprintf(stream, elementformat, "", aname(NULL, nameURI, name)); |
| } |
| else if (attribute.ref) |
| { fprintf(stream, "/// Attribute reference %s.\n", attribute.ref); |
| fprintf(stream, attributeformat, pname(is_optional, NULL, NULL, attribute.ref), aname(NULL, NULL, attribute.ref)); |
| } |
| else |
| { fprintf(stream, "/// Warning: attribute '%s' has no type or ref. Assuming string content.\n", name?name:""); |
| fprintf(stream, attributeformat, tname(NULL, NULL, "xs:string"), aname(NULL, nameURI, name)); |
| } |
| switch (attribute.use) |
| { case optional: |
| case default_: |
| case fixed_: // is this correct??? |
| fprintf(stream, " 0"); |
| break; |
| case prohibited: |
| fprintf(stream, " 0:0"); |
| break; |
| case required: |
| fprintf(stream, " 1"); |
| break; |
| } |
| if (attribute.value) |
| { if (type) |
| { const char *t = tname(NULL, NULL, type); |
| if (!strncmp(t, "unsigned ", 9)) |
| t += 9; |
| if (!strcmp(t, "bool") |
| || !strcmp(t, "char") |
| || !strcmp(t, "double") |
| || !strcmp(t, "float") |
| || !strcmp(t, "int") |
| || !strcmp(t, "long") |
| || !strcmp(t, "LONG64") |
| || !strcmp(t, "short") |
| || !strcmp(t, "ULONG64")) |
| fprintf(stream, " = %s", attribute.value); |
| else if (!strcmp(t, "char*") |
| || !strcmp(t, "char *")) // not elegant |
| fprintf(stream, " = \"%s\"", cstring(attribute.value)); |
| else if (!strncmp(t, "enum ", 5)) |
| fprintf(stream, " = %s", ename(t + 5, attribute.value)); |
| else if (!strcmp(t, "std::string") |
| || !strcmp(t, "std::string*") |
| || !strcmp(t, "std::string *")) // not elegant |
| fprintf(stream, " = \"%s\"", cstring(attribute.value)); |
| else if (!strcmp(t, "xsd__QName") && attribute.value_) // QName is in value_ |
| fprintf(stream, " = \"%s\"", cstring(attribute.value_)); |
| } |
| fprintf(stream, ";\t///< Default value=\"%s\".\n", attribute.value); |
| } |
| else if (attribute.use == required) |
| fprintf(stream, ";\t///< Required attribute.\n"); |
| else if (attribute.use == prohibited) |
| fprintf(stream, ";\t///< Prohibited attribute.\n"); |
| else |
| fprintf(stream, ";\t///< Optional attribute.\n"); |
| } |
| |
| void Types::gen(const char *URI, const vector<xs__attributeGroup>& attributeGroups) |
| { for (vector<xs__attributeGroup>::const_iterator attributeGroup = attributeGroups.begin(); attributeGroup != attributeGroups.end(); ++attributeGroup) |
| { if ((*attributeGroup).attributeGroupPtr()) // attributeGroup ref |
| { if ((*attributeGroup).schemaPtr() == (*attributeGroup).attributeGroupPtr()->schemaPtr()) |
| { gen(URI, (*attributeGroup).attributeGroupPtr()->attribute); |
| gen(URI, (*attributeGroup).attributeGroupPtr()->attributeGroup); |
| } |
| else |
| { gen((*attributeGroup).attributeGroupPtr()->schemaPtr()->targetNamespace, (*attributeGroup).attributeGroupPtr()->attribute); |
| gen((*attributeGroup).attributeGroupPtr()->schemaPtr()->targetNamespace, (*attributeGroup).attributeGroupPtr()->attributeGroup); |
| } |
| if ((*attributeGroup).attributeGroupPtr()->anyAttribute) |
| gen(URI, *(*attributeGroup).attributeGroupPtr()->anyAttribute); |
| } |
| else |
| { gen(URI, (*attributeGroup).attribute); |
| gen(URI, (*attributeGroup).attributeGroup); |
| if ((*attributeGroup).anyAttribute) |
| gen(URI, *(*attributeGroup).anyAttribute); |
| } |
| } |
| } |
| |
| void Types::gen(const char *URI, const vector<xs__all>& alls) |
| { for (vector<xs__all>::const_iterator all = alls.begin(); all != alls.end(); ++all) |
| gen(URI, *all); |
| } |
| |
| void Types::gen(const char *URI, const xs__all& all) |
| { bool tmp_union1 = with_union; |
| bool tmp_union2 = fake_union; |
| with_union = false; |
| fake_union = false; |
| gen(URI, all.element); |
| with_union = tmp_union1; |
| fake_union = tmp_union2; |
| } |
| |
| void Types::gen(const char *URI, const vector<xs__sequence>& sequences) |
| { for (vector<xs__sequence>::const_iterator sequence = sequences.begin(); sequence != sequences.end(); ++sequence) |
| gen(URI, *sequence); |
| } |
| |
| void Types::gen(const char *URI, const vector<xs__sequence*>& sequences) |
| { for (vector<xs__sequence*>::const_iterator sequence = sequences.begin(); sequence != sequences.end(); ++sequence) |
| gen(URI, **sequence); |
| } |
| |
| void Types::gen(const char *URI, const xs__sequence& sequence) |
| { bool tmp_union1 = with_union; |
| bool tmp_union2 = fake_union; |
| with_union = false; |
| fake_union = false; |
| document(sequence.annotation); |
| gen(URI, sequence.element); |
| gen(URI, sequence.group); |
| gen(URI, sequence.choice); |
| gen(URI, sequence.sequence); |
| gen(URI, sequence.any); |
| with_union = tmp_union1; |
| fake_union = tmp_union2; |
| } |
| |
| void Types::gen(const char *URI, const vector<xs__element>& elements) |
| { for (vector<xs__element>::const_iterator element = elements.begin(); element != elements.end(); ++element) |
| gen(URI, *element); |
| } |
| |
| void Types::gen(const char *URI, const xs__element& element) |
| { const char *name, *type, *nameURI = NULL, *typeURI = NULL; |
| name = element.name; |
| type = element.type; |
| document(element.annotation); |
| if (!URI || strcmp(URI, element.schemaPtr()->targetNamespace)) |
| nameURI = element.schemaPtr()->targetNamespace; |
| if (element.elementPtr()) // element ref |
| { name = element.elementPtr()->name; |
| if (element.schemaPtr() != element.elementPtr()->schemaPtr()) |
| nameURI = element.elementPtr()->schemaPtr()->targetNamespace; |
| if (element.elementPtr()->type) |
| { type = element.elementPtr()->type; |
| } |
| else if (element.elementPtr()->schemaPtr()) |
| { type = name; |
| typeURI = element.elementPtr()->schemaPtr()->targetNamespace; |
| } |
| else |
| type = name; |
| document(element.elementPtr()->annotation); |
| if (element.elementPtr()->abstract) |
| { fprintf(stream, "/// Reference %s to abstract element.\n", element.ref); |
| gen_substitutions(URI, element); |
| } |
| else if (element.maxOccurs && strcmp(element.maxOccurs, "1")) // maxOccurs != "1" |
| { const char *s = tnameptr(cflag && !zflag, NULL, typeURI, type); |
| if (cflag || sflag) |
| { fprintf(stream, "/// Size of the dynamic array of %s is %s..%s\n", s, element.minOccurs ? element.minOccurs : "1", element.maxOccurs); |
| fprintf(stream, sizeformat, "int", aname(NULL, NULL, name)); |
| if (is_integer(element.maxOccurs)) |
| fprintf(stream, " %s:%s", element.minOccurs ? element.minOccurs : "1", element.maxOccurs); |
| fprintf(stream, ";\n"); |
| if (cflag && !zflag) |
| { fprintf(stream, "/// Array of length %s..%s\n", element.minOccurs ? element.minOccurs : "1", element.maxOccurs); |
| fprintf(stream, elementformat, s, aname(NULL, nameURI, name)); |
| } |
| else |
| { fprintf(stream, "/// Pointer to array of length %s..%s\n", element.minOccurs ? element.minOccurs : "1", element.maxOccurs); |
| fprintf(stream, pointerformat, s, aname(NULL, nameURI, name)); |
| } |
| } |
| else |
| { fprintf(stream, "/// Vector of %s with length %s..%s\n", s, element.minOccurs ? element.minOccurs : "1", element.maxOccurs); |
| if (with_union) |
| fprintf(stream, pointervectorformat, s, aname(NULL, nameURI, name)); |
| else |
| fprintf(stream, vectorformat, s, aname(NULL, nameURI, name)); |
| } |
| } |
| else |
| { fprintf(stream, "/// Element reference %s.\n", element.ref); |
| document(element.elementPtr()->annotation); |
| fprintf(stream, elementformat, pname(fake_union || is_nillable(element), NULL, typeURI, type), aname(NULL, nameURI, name)); |
| } |
| } |
| else if (name && type) |
| { if (element.abstract) |
| { fprintf(stream, "/// Abstract element %s of type %s.\n", name, type); |
| gen_substitutions(URI, element); |
| } |
| else if (element.maxOccurs && strcmp(element.maxOccurs, "1")) // maxOccurs != "1" |
| { const char *s = tnameptr(cflag && !zflag, NULL, NULL, type); |
| if (cflag || sflag) |
| { fprintf(stream, "/// Size of array of %s is %s..%s\n", s, element.minOccurs ? element.minOccurs : "1", element.maxOccurs); |
| fprintf(stream, sizeformat, "int", aname(NULL, NULL, name)); |
| if (is_integer(element.maxOccurs)) |
| fprintf(stream, " %s:%s", element.minOccurs ? element.minOccurs : "1", element.maxOccurs); |
| fprintf(stream, ";\n"); |
| if (cflag && !zflag) |
| { fprintf(stream, "/// Array of length %s..%s\n", element.minOccurs ? element.minOccurs : "1", element.maxOccurs); |
| fprintf(stream, elementformat, s, aname(NULL, nameURI, name)); |
| } |
| else |
| { fprintf(stream, "/// Pointer to array of length %s..%s\n", element.minOccurs ? element.minOccurs : "1", element.maxOccurs); |
| fprintf(stream, pointerformat, s, aname(NULL, nameURI, name)); |
| } |
| } |
| else |
| { fprintf(stream, "/// Vector of %s with length %s..%s\n", s, element.minOccurs ? element.minOccurs : "1", element.maxOccurs); |
| if (with_union) |
| fprintf(stream, pointervectorformat, s, aname(NULL, nameURI, name)); |
| else |
| fprintf(stream, vectorformat, s, aname(NULL, nameURI, name)); |
| } |
| } |
| else |
| { fprintf(stream, "/// Element %s of type %s.\n", name, type); |
| fprintf(stream, elementformat, pname(fake_union || is_nillable(element), NULL, NULL, type), aname(NULL, nameURI, name)); |
| } |
| } |
| else if (name && element.simpleTypePtr()) |
| { document(element.simpleTypePtr()->annotation); |
| if (element.maxOccurs && strcmp(element.maxOccurs, "1")) // maxOccurs != "1" |
| { fprintf(stream, "/// Size of %s array is %s..%s\n", name, element.minOccurs ? element.minOccurs : "1", element.maxOccurs); |
| fprintf(stream, sizeformat, "int", aname(NULL, NULL, name)); |
| if (is_integer(element.maxOccurs)) |
| fprintf(stream, " %s:%s", element.minOccurs ? element.minOccurs : "1", element.maxOccurs); |
| fprintf(stream, ";\n"); |
| } |
| gen(URI, name, *element.simpleTypePtr(), true); |
| if (is_nillable(element) |
| || element.maxOccurs && strcmp(element.maxOccurs, "1")) // maxOccurs != "1" |
| fprintf(stream, pointerformat, "", aname(NULL, nameURI, name)); |
| else |
| fprintf(stream, elementformat, "", aname(NULL, nameURI, name)); |
| } |
| else if (name && element.complexTypePtr()) |
| { if (element.maxOccurs && strcmp(element.maxOccurs, "1")) // maxOccurs != "1" |
| { fprintf(stream, "/// Size of %s array is %s..%s\n", name, element.minOccurs ? element.minOccurs : "1", element.maxOccurs); |
| fprintf(stream, sizeformat, "int", aname(NULL, NULL, name)); |
| if (is_integer(element.maxOccurs)) |
| fprintf(stream, " %s:%s", element.minOccurs ? element.minOccurs : "1", element.maxOccurs); |
| fprintf(stream, ";\n"); |
| } |
| gen(URI, name, *element.complexTypePtr(), true); |
| if (is_nillable(element) |
| || element.maxOccurs && strcmp(element.maxOccurs, "1")) // maxOccurs != "1" |
| fprintf(stream, pointerformat, "}", aname(NULL, nameURI, name)); |
| else |
| fprintf(stream, elementformat, "}", aname(NULL, nameURI, name)); |
| } |
| else if (element.ref) |
| { fprintf(stream, "/// Element reference %s.\n", element.ref); |
| fprintf(stream, elementformat, tname(NULL, NULL, element.ref), aname(NULL, NULL, element.ref)); |
| } |
| else if (name) |
| { fprintf(stream, "/// Warning: element '%s' has no type or ref. Assuming XML content.\n", name?name:""); |
| if (element.maxOccurs && strcmp(element.maxOccurs, "1")) // maxOccurs != "1" |
| { if (cflag || sflag) |
| { fprintf(stream, sizeformat, "int", aname(NULL, NULL, name)); |
| if (is_integer(element.maxOccurs)) |
| fprintf(stream, " %s:%s", element.minOccurs ? element.minOccurs : "1", element.maxOccurs); |
| fprintf(stream, ";\n"); |
| fprintf(stream, "/// Pointer to array of XML.\n"); |
| fprintf(stream, pointerformat, "_XML", aname(NULL, nameURI, name)); |
| } |
| else |
| { fprintf(stream, "/// Vector of XML with length %s..%s\n", element.minOccurs ? element.minOccurs : "1", element.maxOccurs); |
| if (with_union) |
| fprintf(stream, pointervectorformat, "_XML", aname(NULL, nameURI, name)); |
| else |
| fprintf(stream, vectorformat, "_XML", aname(NULL, nameURI, name)); |
| } |
| } |
| else |
| fprintf(stream, elementformat, "_XML", aname(NULL, nameURI, name)); |
| } |
| else |
| fprintf(stream, "/// Warning: element has no type or ref."); |
| if (!element.abstract && !(element.elementPtr() && element.elementPtr()->abstract)) |
| { if (!element.minOccurs && !element.nillable && !element.default_) |
| fprintf(stream, " 1"); |
| else if (element.minOccurs) |
| fprintf(stream, " %s", element.minOccurs); |
| if (element.maxOccurs && strcmp(element.maxOccurs, "1") && is_integer(element.maxOccurs)) |
| fprintf(stream, ":%s", element.maxOccurs); |
| if (element.default_) |
| { // determine whether the element can be assigned a default value, this is dependent on the choice of mapping for primitive types |
| if (type) |
| { const char *t = tname(NULL, NULL, type); |
| if (!strncmp(t, "unsigned ", 9)) |
| t += 9; |
| if (!strcmp(t, "bool") |
| || !strcmp(t, "char") |
| || !strcmp(t, "double") |
| || !strcmp(t, "float") |
| || !strcmp(t, "int") |
| || !strcmp(t, "long") |
| || !strcmp(t, "LONG64") |
| || !strcmp(t, "short") |
| || !strcmp(t, "ULONG64")) |
| fprintf(stream, " = %s", element.default_); |
| else if (!strcmp(t, "char*") |
| || !strcmp(t, "char *")) // not elegant |
| fprintf(stream, " = \"%s\"", element.default_); |
| else if (!strncmp(t, "enum ", 5)) |
| fprintf(stream, " = %s", ename(t + 5, element.default_)); |
| else if (!strcmp(t, "std::string") || !strcmp(t, "std::string*") || !strcmp(t, "std::string *")) // not elegant |
| fprintf(stream, " = \"%s\"", element.default_); |
| } |
| fprintf(stream, ";\t///< Default value=\"%s\".\n", element.default_); |
| } |
| else if (element.nillable) |
| fprintf(stream, ";\t///< Nullable pointer.\n"); |
| else if ((!element.minOccurs || !strcmp(element.minOccurs, "1")) && (!element.maxOccurs || !strcmp(element.maxOccurs, "1"))) |
| fprintf(stream, ";\t///< Required element.\n"); |
| else if (element.minOccurs && !strcmp(element.minOccurs, "0") && (!element.maxOccurs || !strcmp(element.maxOccurs, "1"))) |
| fprintf(stream, ";\t///< Optional element.\n"); |
| else |
| fprintf(stream, ";\n"); |
| } |
| } |
| |
| void Types::gen(const char *URI, const vector<xs__group>& groups) |
| { for (vector<xs__group>::const_iterator group = groups.begin(); group != groups.end(); ++group) |
| gen(URI, *group); |
| } |
| |
| void Types::gen(const char *URI, const xs__group& group) |
| { if (group.groupPtr()) |
| { if (group.schemaPtr() == group.groupPtr()->schemaPtr()) |
| gen(URI, *group.groupPtr()); |
| else |
| gen(group.groupPtr()->schemaPtr()->targetNamespace, *group.groupPtr()); |
| } |
| else if (group.all) |
| gen(URI, group.all->element); |
| else if (group.sequence) |
| gen(URI, group.sequence->element); |
| else if (group.choice) |
| gen(URI, NULL, *group.choice); |
| } |
| |
| void Types::gen(const char *URI, const vector<xs__choice>& choices) |
| { for (vector<xs__choice>::const_iterator choice = choices.begin(); choice != choices.end(); ++choice) |
| gen(URI, NULL, *choice); |
| } |
| |
| void Types::gen(const char *URI, const char *name, const xs__choice& choice) |
| { const char *r = NULL, *s = NULL, *t = NULL; |
| bool use_union = !uflag; |
| bool wrap_union = false; |
| bool tmp_union; |
| if (!URI && choice.schemaPtr()) |
| URI = choice.schemaPtr()->targetNamespace; |
| fprintf(stream, "/// CHOICE OF ELEMENTS FOR choice"); |
| document(choice.annotation); |
| if (choice.minOccurs) |
| fprintf(stream, " minOccurs=\"%s\"", choice.minOccurs); |
| if (choice.maxOccurs) |
| fprintf(stream, " maxOccurs=\"%s\"", choice.maxOccurs); |
| fprintf(stream, "\n"); |
| if (!choice.group.empty() || !choice.sequence.empty()) |
| use_union = false; |
| else if (cflag || sflag) |
| { for (vector<xs__element>::const_iterator el = choice.element.begin(); el != choice.element.end(); el++) |
| { if ((*el).maxOccurs && strcmp((*el).maxOccurs, "1")) |
| { use_union = false; |
| break; |
| } |
| } |
| } |
| if (use_union) |
| { t = uname(URI); |
| s = strstr(t, "__union"); |
| if (s) |
| r = s + 7; |
| if (!r || !*r) |
| { r = t; |
| s = "__union"; |
| } |
| if (choice.maxOccurs && strcmp(choice.maxOccurs, "1")) |
| { if (with_union) |
| { // Generate a wrapper when we need a union within a union |
| wrap_union = true; |
| fprintf(stream, " struct __%s\n {\n", t); |
| } |
| fprintf(stream, sizeformat, "int", r); |
| if (choice.minOccurs) |
| fprintf(stream, " %s", choice.minOccurs); |
| if (choice.maxOccurs && strcmp(choice.maxOccurs, "1") && is_integer(choice.maxOccurs)) |
| fprintf(stream, ":%s", choice.maxOccurs); |
| fprintf(stream, ";\n struct _%s\n {\n", t); |
| } |
| if (!with_union || wrap_union) |
| { fprintf(stream, choiceformat, "int", r); |
| if (choice.minOccurs) |
| fprintf(stream, " %s", choice.minOccurs); |
| fprintf(stream, ";\t///< Union %s selector: set to SOAP_UNION_%s_<fieldname>%s\n", t, t, choice.minOccurs && !strcmp(choice.minOccurs, "0") ? " or 0" : ""); |
| if (name) |
| fprintf(stream, "/// Union for choice in %s\n", tname(NULL, URI, name)); |
| fprintf(stream, " union %s\n {\n", t); |
| } |
| tmp_union = with_union; |
| with_union = true; |
| } |
| else |
| { tmp_union = fake_union; |
| fake_union = true; |
| } |
| gen(URI, choice.element); |
| gen(URI, choice.group); |
| gen(URI, choice.sequence); // TODO: check potential name conflicts |
| gen(URI, choice.any); |
| if (use_union) |
| { with_union = tmp_union; |
| if (!with_union || wrap_union) |
| fprintf(stream, elementformat, "}", s+2); |
| if (choice.maxOccurs && strcmp(choice.maxOccurs, "1")) |
| { fprintf(stream, ";\n"); |
| fprintf(stream, pointerformat, "}", s); |
| } |
| fprintf(stream, ";\n"); |
| if (wrap_union) |
| { fprintf(stream, elementformat, "}", s); |
| fprintf(stream, ";\n"); |
| } |
| } |
| else |
| fake_union = tmp_union; |
| fprintf(stream, "// END OF CHOICE\n"); |
| } |
| |
| void Types::gen(const char *URI, const vector<xs__any>& anys) |
| { for (vector<xs__any>::const_iterator any = anys.begin(); any != anys.end(); ++any) |
| gen(URI, *any); |
| } |
| |
| void Types::gen(const char *URI, const xs__any& any) |
| { fprintf(stream, "/// TODO: <any"); |
| if (any.namespace_) |
| fprintf(stream, " namespace=\"%s\"", any.namespace_); |
| if (any.minOccurs) |
| fprintf(stream, " minOccurs=\"%s\"", any.minOccurs); |
| if (any.maxOccurs) |
| fprintf(stream, " maxOccurs=\"%s\"", any.maxOccurs); |
| fprintf(stream, ">\n/// Schema extensibility is user-definable.\n/// Consult the protocol documentation to change and/or insert declarations.\n/// Use wsdl2h option -x to remove this element.\n/// Use wsdl2h option -d to use DOM.\n"); |
| if (dflag) |
| { fprintf(stream, pointerformat, "xsd__anyType", "__any"); |
| fprintf(stream, ";\t///< Catch any element content in DOM.\n"); |
| } |
| else if (!xflag) |
| { fprintf(stream, elementformat, "_XML", "__any"); |
| fprintf(stream, ";\t///< Catch any element content in XML string.\n"); |
| } |
| } |
| |
| void Types::gen(const char *URI, const xs__anyAttribute& anyAttribute) |
| { fprintf(stream, "/// TODO: <anyAttribute"); |
| if (anyAttribute.namespace_) |
| fprintf(stream, " namespace=\"%s\"", anyAttribute.namespace_); |
| fprintf(stream, ">\n/// Schema extensibility is user-definable.\n/// Consult the protocol documentation to change and/or insert declarations.\n/// Use wsdl2h option -x to remove this attribute.\n"); |
| if (!xflag) |
| { fprintf(stream, attributeformat, "_XML", "__anyAttribute"); |
| fprintf(stream, ";\t///< Catch any attribute content in XML string.\n"); |
| } |
| } |
| |
| void Types::gen_soap_array(const char *name, const char *t, const char *item, char *type) |
| { char *dims = NULL, size[8]; |
| *size = '\0'; |
| if (type) |
| dims = strrchr(type, '['); |
| if (dims) |
| *dims++ = '\0'; |
| fprintf(stream, "/// SOAP encoded array of %s\n", type ? type : "xs:anyType"); |
| if (cflag) |
| fprintf(stream, "struct %s\n{\n", t); |
| else if (pflag) |
| fprintf(stream, "class %s : public xsd__anyType\n{ public:\n", t); |
| else |
| fprintf(stream, "class %s\n{ public:\n", t); |
| if (dims) |
| { char *s = strchr(dims, ']'); |
| if (s && s != dims) |
| sprintf(size, "[%d]", (int)(s - dims + 1)); |
| } |
| if (type) |
| { if (strchr(type, '[') != NULL) |
| { gen_soap_array(NULL, "", item, type); |
| fprintf(stream, arrayformat, "}", item ? aname(NULL, NULL, item) : ""); |
| fprintf(stream, ";\n"); |
| } |
| else |
| { const char *s = pname(!is_basetype(type), NULL, NULL, type); |
| fprintf(stream, "/// Pointer to array of %s.\n", s); |
| fprintf(stream, arrayformat, s, item ? aname(NULL, NULL, item) : ""); |
| fprintf(stream, ";\n"); |
| } |
| if (*size) |
| fprintf(stream, "/// Size of the multidimensional dynamic array with dimensions=%s\n", size); |
| else |
| fprintf(stream, "/// Size of the dynamic array.\n"); |
| fprintf(stream, sizeformat, "int", size); |
| fprintf(stream, ";\n/// Offset for partially transmitted arrays (uncomment only when required).\n"); |
| fprintf(stream, offsetformat, "int", size); |
| fprintf(stream, ";\n"); |
| } |
| else |
| { // TODO: handle generic SOAP array? E.g. as an array of anyType |
| fprintf(stream, "// TODO: handle generic SOAP-ENC:Array (array of anyType)\n"); |
| } |
| } |
| |
| void Types::gen_substitutions(const char *URI, const xs__element &element) |
| { const std::vector<xs__element*> *substitutions; |
| const char *name; |
| const char *r = NULL, *s = NULL; |
| bool use_union = !uflag; |
| bool wrap_union = false; |
| bool tmp_union; |
| if (!URI && element.schemaPtr()) |
| URI = element.schemaPtr()->targetNamespace; |
| if (element.elementPtr()) |
| { name = element.elementPtr()->name; |
| substitutions = element.elementPtr()->substitutionsPtr(); |
| } |
| else |
| { name = element.name; |
| substitutions = element.substitutionsPtr(); |
| } |
| fprintf(stream, "/// CHOICE OF ELEMENTS FOR substitutionGroup=\"%s\"", name); |
| if (element.minOccurs) |
| fprintf(stream, " minOccurs=\"%s\"", element.minOccurs); |
| if (element.maxOccurs) |
| fprintf(stream, " maxOccurs=\"%s\"", element.maxOccurs); |
| fprintf(stream, " with elements"); |
| for (std::vector<xs__element*>::const_iterator i1 = substitutions->begin(); i1 != substitutions->end(); ++i1) |
| fprintf(stream, " %s", (*i1)->name); |
| fprintf(stream, "\n"); |
| if (use_union) |
| { const char *t = uname(URI); |
| s = strstr(t, "__union"); |
| if (!s) |
| s = "__union"; |
| r = aname(NULL, NULL, name); |
| if (element.maxOccurs && strcmp(element.maxOccurs, "1")) |
| { if (with_union) |
| { // Generate a wrapper when we need a union within a union |
| wrap_union = true; |
| fprintf(stream, " struct __%s\n {\n", t); |
| } |
| fprintf(stream, sizeformat, "int", r); |
| if (element.minOccurs) |
| fprintf(stream, " %s", element.minOccurs); |
| if (element.maxOccurs && strcmp(element.maxOccurs, "1") && is_integer(element.maxOccurs)) |
| fprintf(stream, ":%s", element.maxOccurs); |
| fprintf(stream, ";\n struct _%s\n {\n", t); |
| } |
| if (!with_union || wrap_union) |
| { fprintf(stream, choiceformat, "int", r); |
| if (element.minOccurs) |
| fprintf(stream, " %s", element.minOccurs); |
| fprintf(stream, ";\t///< Union %s selector: set to SOAP_UNION_%s_<fieldname>%s\n", t, t, element.minOccurs && !strcmp(element.minOccurs, "0") ? " or 0" : ""); |
| fprintf(stream, "/// Union for substitutionGroup=\"%s\"\n", name); |
| fprintf(stream, " union %s\n {\n", t); |
| } |
| tmp_union = with_union; |
| with_union = true; |
| } |
| else |
| { tmp_union = fake_union; |
| fake_union = true; |
| } |
| for (vector<xs__element*>::const_iterator i2 = substitutions->begin(); i2 != substitutions->end(); ++i2) |
| gen(URI, *(*i2)); |
| if (use_union) |
| { with_union = tmp_union; |
| if (!with_union || wrap_union) |
| fprintf(stream, elementformat, "}", s); |
| if (element.maxOccurs && strcmp(element.maxOccurs, "1")) |
| { fprintf(stream, ";\n"); |
| fprintf(stream, pointerformat, "}", s); |
| } |
| fprintf(stream, ";\n"); |
| if (wrap_union) |
| { fprintf(stream, elementformat, "}", s); |
| fprintf(stream, ";\n"); |
| } |
| } |
| else |
| fake_union = tmp_union; |
| fprintf(stream, "// END OF CHOICE\n"); |
| } |
| |
| void Types::document(const xs__annotation *annotation) |
| { if (annotation && annotation->documentation) |
| { fprintf(stream, "/// @brief"); |
| documentation(annotation->documentation); |
| } |
| } |
| |
| void Types::modify(const char *name) |
| { // TODO: consider support removal of elements/attributes with ns__X = $- Y |
| const char *s = modtypemap[name]; |
| if (s) |
| { while (*s) |
| { if (*s++ == '$') |
| fprintf(stream, "/// Member declared in %s\n ", mapfile); |
| s = format(s); |
| } |
| } |
| } |
| |
| const char* Types::format(const char *text) |
| { const char *s = text; |
| if (!s) |
| return NULL; |
| while (*s && *s != '$') |
| { if (*s == '\\') |
| { switch (s[1]) |
| { case 'n': |
| fputc('\n', stream); |
| break; |
| case 't': |
| fputc('\t', stream); |
| break; |
| default: |
| fputc(s[1], stream); |
| } |
| s++; |
| } |
| else |
| fputc(*s, stream); |
| s++; |
| } |
| fputc('\n', stream); |
| return s; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // Type map file parsing |
| // |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| static char *getline(char *s, size_t n, FILE *fd) |
| { int c; |
| char *t = s; |
| if (n) |
| n--; |
| for (;;) |
| { c = fgetc(fd); |
| if (c == '\r') |
| continue; |
| if (c == '\\') |
| { c = fgetc(fd); |
| if (c == '\r') |
| c = fgetc(fd); |
| if (c < ' ') |
| continue; |
| if (n) |
| { *t++ = '\\'; |
| n--; |
| } |
| } |
| if (c == '\n' || c == EOF) |
| break; |
| if (n) |
| { *t++ = c; |
| n--; |
| } |
| } |
| *t++ = '\0'; |
| if (!*s && c == EOF) |
| return NULL; |
| return s; |
| } |
| |
| static const char *nonblank(const char *s) |
| { while (*s && isspace(*s)) |
| s++; |
| return s; |
| } |
| |
| static const char *fill(char *t, int n, const char *s, int e) |
| { int i = n; |
| s = nonblank(s); |
| while (*s && *s != e && --i) |
| *t++ = *s++; |
| while (*s && *s != e) |
| s++; |
| if (*s) |
| s++; |
| i = n - i; |
| while (isspace(*--t) && i--) |
| ; |
| t[1] = '\0'; |
| return s; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // Miscellaneous |
| // |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| static const char *utf8(char *t, const char *s) |
| { unsigned int c = 0; |
| int c1, c2, c3, c4; |
| c = (unsigned char)*s; |
| if (c >= 0x80) |
| { c1 = *++s; |
| if (c1 < 0x80) |
| s--; |
| else |
| { c1 &= 0x3F; |
| if (c < 0xE0) |
| c = ((c & 0x1F) << 6) | c1; |
| else |
| { c2 = *++s & 0x3F; |
| if (c < 0xF0) |
| c = ((c & 0x0F) << 12) | (c1 << 6) | c2; |
| else |
| { c3 = *++s & 0x3F; |
| if (c < 0xF8) |
| c = ((c & 0x07) << 18) | (c1 << 12) | (c2 << 6) | c3; |
| else |
| { c4 = *++s & 0x3F; |
| if (c < 0xFC) |
| c = ((c & 0x03) << 24) | (c1 << 18) | (c2 << 12) | (c3 << 6) | c4; |
| else |
| c = ((c & 0x01) << 30) | (c1 << 24) | (c2 << 18) | (c3 << 12) | (c4 << 6) | *++s & 0x3F; |
| } |
| } |
| } |
| } |
| } |
| sprintf(t, "_x%.4x", c); |
| return s; |
| } |
| |
| static const char *cstring(const char *s) |
| { size_t n; |
| char *t; |
| const char *r; |
| for (n = 0, r = s; *r; n++, r++) |
| if (*r == '"' || *r == '\\') |
| n++; |
| else if (*r < 32) |
| n += 3; |
| r = t = (char*)emalloc(n + 1); |
| for (; *s; s++) |
| { if (*s == '"' || *s == '\\') |
| { *t++ = '\\'; |
| *t++ = *s; |
| } |
| else if (*s < 32) |
| { sprintf(t, "\\%03o", (unsigned int)(unsigned char)*s); |
| t += 4; |
| } |
| else |
| *t++ = *s; |
| } |
| *t = '\0'; |
| return r; |
| } |
| |
| static const char *xstring(const char *s) |
| { size_t n; |
| char *t; |
| const char *r; |
| for (n = 0, r = s; *r; n++, r++) |
| { if (*r < 32 || *r >= 127) |
| n += 4; |
| else if (*r == '<' || *r == '>') |
| n += 3; |
| else if (*r == '&') |
| n += 4; |
| else if (*r == '"') |
| n += 5; |
| } |
| r = t = (char*)emalloc(n + 1); |
| for (; *s; s++) |
| { if (*s < 32 || *s >= 127) |
| { sprintf(t, "&#%.2x;", (unsigned char)*s); |
| t += 5; |
| } |
| else if (*s == '<') |
| { strcpy(t, "<"); |
| t += 4; |
| } |
| else if (*s == '>') |
| { strcpy(t, ">"); |
| t += 4; |
| } |
| else if (*s == '&') |
| { strcpy(t, "&"); |
| t += 5; |
| } |
| else if (*s == '"') |
| { strcpy(t, """); |
| t += 6; |
| } |
| else |
| *t++ = *s; |
| } |
| *t = '\0'; |
| return r; |
| } |
| |
| static bool is_integer(const char *s) |
| { if ((*s == '-' || *s == '+') && s[1]) |
| s++; |
| while (*s && isdigit(*s)) |
| s++; |
| return *s == '\0'; |
| } |
| |
| static void documentation(const char *text) |
| { const char *s = text; |
| bool flag = true; |
| if (!s) |
| return; |
| while (*s) |
| { switch (*s) |
| { case '\n': |
| case '\t': |
| case ' ': |
| flag = true; |
| break; |
| default: |
| if (*s > 32) |
| { if (flag) |
| { fputc(' ', stream); |
| flag = false; |
| } |
| fputc(*s, stream); |
| } |
| } |
| s++; |
| } |
| fputc('\n', stream); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // Allocation |
| // |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| void *emalloc(size_t size) |
| { void *p = malloc(size); |
| if (!p) |
| { fprintf(stderr, "Error: Malloc failed\n"); |
| exit(1); |
| } |
| return p; |
| } |
| |
| char *estrdup(const char *s) |
| { char *t = (char*)emalloc(strlen(s) + 1); |
| strcpy(t, s); |
| return t; |
| } |