/Users/maurits/Documents/studie/afstuderen/biosphere/common/xml.c

Go to the documentation of this file.
00001 /*
00002  * Author: MA Hartman
00003  * Date: feb 20, 2007
00004  * 
00005  * Function:
00006  * XML translation for different Bio-SPHERE structures.
00007  * 
00008  * License information:
00009  * 
00010  * Copyright (c) 2006 Maurits Hartman
00011  *
00012  * Permission is hereby granted, free of charge, to any person
00013  * obtaining a copy of this software and associated documentation
00014  * files (the "Software"), to deal in the Software without
00015  * restriction, including without limitation the rights to use,
00016  * copy, modify, merge, publish, distribute, sublicense, and/or sell
00017  * copies of the Software, and to permit persons to whom the
00018  * Software is furnished to do so, subject to the following
00019  * conditions:
00020  * 
00021  * The above copyright notice and this permission notice shall be
00022  * included in all copies or substantial portions of the Software.
00023  * 
00024  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00025  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
00026  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00027  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
00028  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
00029  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
00030  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
00031  * OTHER DEALINGS IN THE SOFTWARE.
00032  * 
00033  */
00034  
00035 #include "xml.h"
00036 #include "str.h"
00037 #include "type.h"
00038 #include <alloc.h>
00039 #include <stack.h>
00040 
00041 #include <apr_base64.h>
00042 #include <apr_strings.h>
00043 #include <apr_xml.h>
00044 #include <apr_uuid.h>
00045 #include <assert.h>
00046 #include <string.h>
00047 #include <stdio.h>
00048 
00049 
00050 /*******************************************************
00051  *                                                     *
00052  *  SERVICE DEFINITION TO XML HELPER FUNCTIONS         *
00053  *                                                     *
00054  *******************************************************/
00055 
00056 static bs_status add_datatypes_to_xml(char **buf, const bs_definition *def,
00057                 apr_pool_t *mp)
00058 {
00059         bs_uint16 i;
00060         char *collect = "";
00061         
00062         for (i = 0; i < def->num_data_types; i++) {
00063                 char *tmp;
00064                 bs_data_type *type = def->data_types[i];
00065                 tmp = apr_psprintf(mp, "<type name=\"%s\" />", type->name);
00066                 collect = apr_pstrcat(mp, collect, tmp, NULL);
00067         }
00068         
00069         *buf = apr_pstrcat(mp, *buf, collect, NULL);
00070         return BS_OK;
00071 }
00072 
00073 
00074 static bs_status add_message_part_to_xml(char **buf,
00075                 const bs_message_part *part, apr_pool_t *mp)
00076 {
00077         char *collect = apr_psprintf(mp, "<part name=\"%s\" type=\"%s\"/>",
00078                         part->name, part->type->name);
00079         *buf = apr_pstrcat(mp, *buf, collect, NULL);
00080         return BS_OK;
00081 }
00082 
00083 
00084 static bs_status add_message_to_xml(char **buf, const bs_message *msg,
00085                 apr_pool_t *mp)
00086 {
00087         bs_status rv;
00088         int i;
00089         char *collect = apr_psprintf(mp, "<message name=\"%s\">", msg->name);
00090         
00091         for (i = 0; i < msg->num_parts; i++) {
00092                 rv = add_message_part_to_xml(&collect, msg->parts[i], mp);
00093                 if (rv != BS_OK) return rv;
00094         }
00095         
00096         *buf = apr_pstrcat(mp, *buf, collect, "</message>", NULL);
00097         return BS_OK;
00098 }
00099 
00100 
00101 static bs_status add_messages_to_xml(char **buf, const bs_definition *def,
00102                 apr_pool_t *mp)
00103 {
00104         int i;
00105         bs_status rv;
00106         
00107         for (i = 0; i < def->num_messages; i++) {
00108                 rv = add_message_to_xml(buf, def->messages[i], mp);
00109                 if (rv != BS_OK) return rv;
00110         }
00111                 
00112         return BS_OK;
00113 }
00114 
00115 
00116 static bs_status add_operation_to_xml(char **buf, const bs_operation *op,
00117                 apr_pool_t *mp)
00118 {
00119         char *i = "", *o = "", *f = "";
00120         char *collect = apr_psprintf(mp, "<operation name=\"%s\">", op->name);
00121         
00122         if (op->input)
00123                 i = apr_psprintf(mp, "<input message=\"%s\"/>", op->input->name);
00124         if (op->output)
00125                 o = apr_psprintf(mp, "<output message=\"%s\"/>", op->output->name);
00126         if (op->fault)
00127                 f = apr_psprintf(mp, "<fault message=\"%s\"/>", op->fault->name);
00128         
00129         *buf = apr_pstrcat(mp, *buf, collect, i, o, f, "</operation>", NULL);
00130         return BS_OK;   
00131 }
00132 
00133 
00134 static bs_status add_port_type_to_xml(char **buf, const bs_port_type *pt,
00135                 apr_pool_t *mp)
00136 {
00137         bs_status rv;
00138         unsigned i;
00139         char *collect = "";
00140         
00141         collect = apr_psprintf(mp, "<portType name=\"%s\">", pt->name);
00142         
00143         for (i = 0; i < pt->num_operations; i++) {
00144                 rv = add_operation_to_xml(&collect, pt->operations[i], mp);
00145                 if (rv != BS_OK) return rv;
00146         }
00147         
00148         *buf = apr_pstrcat(mp, *buf, collect, "</portType>", NULL);
00149         return BS_OK;   
00150 }
00151 
00152 
00153 static bs_status add_porttypes_to_xml(char **buf, const bs_definition *def,
00154                 apr_pool_t *mp)
00155 {
00156         int i;
00157         bs_status rv;
00158         
00159         for (i = 0; i < def->num_port_types; i++) {
00160                 rv = add_port_type_to_xml(buf, def->port_types[i], mp);
00161                 if (rv != BS_OK) return rv;
00162         }
00163 
00164         return BS_OK;
00165 }
00166 
00167 
00168 static bs_status add_port_to_xml(char **buf, const bs_port *port,
00169                 apr_pool_t *mp)
00170 {
00171         char *collect = apr_psprintf(mp, "<port name=\"%s\" type=\"%s\" />",
00172                         port->name, port->port_type->name);
00173         *buf = apr_pstrcat(mp, *buf, collect, NULL);
00174         return BS_OK;   
00175 }
00176 
00177 
00178 static bs_status add_service_to_xml(char **buf, const bs_service *sv,
00179                 apr_pool_t *mp)
00180 {
00181         bs_status rv;
00182         unsigned i;
00183         char *collect = apr_psprintf(mp, "<service name=\"%s\">", sv->name);
00184                         
00185         /* Add the ports of the service: */
00186         for (i = 0; i < sv->num_ports; i++) {
00187                 rv = add_port_to_xml(&collect, sv->ports[i], mp);
00188                 if (rv != BS_OK) return rv;     
00189         }
00190         
00191         *buf = apr_pstrcat(mp, *buf, collect, "</service>", NULL);
00192         return BS_OK;   
00193 }
00194 
00195 
00196 static bs_status add_services_to_xml(char **buf, const bs_definition *def,
00197                 apr_pool_t *mp)
00198 {
00199         unsigned i;
00200         bs_status rv;
00201         
00202         for (i = 0; i < def->num_services; i++) {
00203                 rv = add_service_to_xml(buf, def->services[i], mp);
00204                 if (rv != BS_OK) return rv;
00205         }
00206 
00207         return BS_OK;
00208 }
00209 
00210 
00211 /*******************************************************
00212  *                                                     *
00213  *  SERVICE REQUEST TO XML HELPER FUNCTIONS            *
00214  *                                                     *
00215  *******************************************************/
00216 
00217 static bs_status add_use_service_to_xml(char **buf, const bs_service_request *def,
00218                 apr_pool_t *mp)
00219 {
00220         char *collect = apr_psprintf(mp,
00221                         "<use service=\"%s\" port=\"%s\" operation=\"%s\" />",
00222                         def->service, def->port, def->operation);
00223         *buf = apr_pstrcat(mp, *buf, collect, NULL);
00224         return BS_OK;
00225 }
00226 
00227 
00228 static bs_status add_part_instance_to_xml(char **buf, const bs_part_instance *def,
00229                 apr_pool_t *mp)
00230 {
00231         char *tmp, *data64;
00232         tmp = apr_psprintf(mp, "<part name=\"%s\" type=\"%s\" size=\"%" BS_UINT64_FMT "\">", def->name,
00233                         def->type->name, def->size);
00234         
00235         /* Convert the data to base64 encoding if necessary: */
00236         if (def->type->builtin) data64 = def->data;
00237         else {
00238                 data64 = apr_pcalloc(mp, apr_base64_encode_len(def->size) + 1);
00239             apr_base64_encode(data64, def->data, def->size);
00240         }
00241         
00242         *buf = apr_pstrcat(mp, *buf, tmp, data64, "</part>", NULL);
00243         return BS_OK;           
00244 }
00245 
00246 
00247 static bs_status add_message_instance_to_xml(char **buf, const bs_message_instance *def,
00248                 char *type, apr_pool_t *mp)
00249 {
00250         bs_status rv;
00251         unsigned i;
00252         char *tmp, *tmp2, *collect = "";
00253         tmp = apr_psprintf(mp, "<%s message=\"%s\">", type, def->name);
00254                         
00255         /* Add the ports of the service: */
00256         for (i = 0; i < def->num_parts; i++) {
00257                 rv = add_part_instance_to_xml(&collect, def->parts[i], mp);
00258                 if (rv != BS_OK) return rv;     
00259         }
00260         
00261         tmp2 = apr_psprintf(mp, "</%s>", type);
00262         *buf = apr_pstrcat(mp, *buf, tmp, collect, tmp2, NULL);
00263         return BS_OK;   
00264 }
00265 
00266 
00267 /*******************************************************
00268  *                                                     *
00269  *  SERVICE RESPONSE TO XML HELPER FUNCTIONS           *
00270  *                                                     *
00271  *******************************************************/
00272 
00273 static bs_status add_used_service_to_xml(char **buf, const bs_service_response *def,
00274                 apr_pool_t *mp)
00275 {
00276         char *collect = apr_psprintf(mp,
00277                         "<used service=\"%s\" port=\"%s\" operation=\"%s\" />",
00278                         def->service, def->port, def->operation);
00279         *buf = apr_pstrcat(mp, *buf, collect, NULL);
00280         return BS_OK;
00281 }
00282 
00283 
00284 /*******************************************************
00285  *                                                     *
00286  *  MAIN TO XML FUNCTIONS                              *
00287  *                                                     *
00288  *******************************************************/
00289 
00290 bs_status xlate_definition_to_xml(char **buf, bs_uint64 *size,
00291                 const bs_definition *def, apr_pool_t *mp)
00292 {
00293         char *collect = apr_psprintf(mp, "<definitions name=\"%s\">", def->name);
00294         add_datatypes_to_xml(&collect, def, mp);
00295         add_messages_to_xml(&collect, def, mp);
00296         add_porttypes_to_xml(&collect, def, mp);
00297         add_services_to_xml(&collect, def, mp);
00298         *buf = apr_pstrcat(mp, collect, "</definitions>", NULL);
00299         *size = strlen(*buf);
00300         return BS_OK;
00301 }
00302 
00303 
00304 bs_status xlate_request_to_xml(char **buf, bs_uint64 *size,
00305                 const bs_service_request *def, apr_pool_t *mp)
00306 {
00307         char *collect, uuid_format[APR_UUID_FORMATTED_LENGTH + 1];
00308         
00309         /* Create (null-terminated) UUID for the request: */
00310         uuid_format[APR_UUID_FORMATTED_LENGTH] = '\0';
00311         apr_uuid_format(uuid_format, (apr_uuid_t *) &def->uuid);
00312         collect = apr_psprintf(mp, "<request uuid=\"%s\">", uuid_format);
00313         
00314         add_use_service_to_xml(&collect, def, mp);
00315         add_message_instance_to_xml(&collect, def->input, "input", mp);
00316         
00317         *buf = apr_pstrcat(mp, collect, "</request>", NULL);
00318         *size = strlen(*buf);
00319         return BS_OK;   
00320 }
00321 
00322 
00323 bs_status xlate_response_to_xml(char **buf, bs_uint64 *size,
00324                 const bs_service_response *def, apr_pool_t *mp)
00325 {
00326         char *collect, uuid_format[APR_UUID_FORMATTED_LENGTH + 1];
00327         
00328         /* Create (null-terminated) UUID for the request: */
00329         uuid_format[APR_UUID_FORMATTED_LENGTH] = '\0';
00330         apr_uuid_format(uuid_format, (apr_uuid_t *) &def->uuid);
00331         collect = apr_psprintf(mp, "<response uuid=\"%s\">", uuid_format);
00332         
00333         add_used_service_to_xml(&collect, def, mp);
00334         if (def->output)
00335                 add_message_instance_to_xml(&collect, def->output, "output", mp);
00336         if (def->fault)
00337                 add_message_instance_to_xml(&collect, def->fault, "fault", mp);
00338         
00339         *buf = apr_pstrcat(mp, collect, "</response>", NULL);
00340         *size = strlen(*buf);
00341         return BS_OK;   
00342 }
00343 
00344 
00345 /*******************************************************
00346  *                                                     *
00347  *  SERVICE DEFINITION FROM XML HELPER FUNCTIONS       *
00348  *                                                     *
00349  *******************************************************/
00350 
00354 static bs_data_type *process_data_type(const apr_xml_elem *type, apr_pool_t *mp)
00355 {
00356         const apr_xml_attr *attr;
00357         bs_data_type *ret = NULL;
00358         
00359         /* Process data type name attribute and allocate bs_data_type structure: */
00360         for (attr = type->attr; attr; attr = attr->next) {
00361                 if (streq(attr->name, "name")) {
00362                         ret = new_bs_data_type(mp, attr->value);
00363                         break;
00364                 }
00365         }
00366         
00367         return ret;
00368 }
00369 
00370 
00375 static bs_data_type *lookup_data_type_by_name(const bs_definition *def, const char *name)
00376 {
00377         /* Look for the datatype by its name in the given definition def: */
00378         bs_uint16 i;
00379         for (i = 0; i < def->num_data_types; i++) {
00380                 bs_data_type *type = def->data_types[i];
00381                 if (streq(type->name, name)) return type;       
00382         }
00383         return NULL;    
00384 }
00385 
00386 
00395 static bs_message *process_message(const apr_xml_elem *msg, bs_definition *def,
00396                 apr_pool_t *mp)
00397 {
00398         const apr_xml_elem *part;
00399         const apr_xml_attr *attr;
00400         bs_message *m = NULL;
00401         
00402         /* Process message name attribute and allocate bs_message structure: */
00403         for (attr = msg->attr; attr; attr = attr->next)
00404                 if (streq(attr->name, "name"))
00405                         m = new_bs_message(mp, attr->value, 0);
00406         if (!m) return NULL;
00407         
00408         /* Go through all the parts of the message: */
00409         for (part = msg->first_child; part; part = part->next) {
00410                 /* Retrieve the name and type attributes of the part and allocate: */
00411                 char *part_name = NULL;
00412                 bs_data_type *part_type = NULL;
00413                 bs_message_part *msg_part = NULL;
00414                 for (attr = part->attr; attr; attr = attr->next) {
00415                         if (streq(attr->name, "name"))
00416                                 part_name = apr_pstrdup(mp, attr->value);
00417                         if (streq(attr->name, "type")) {
00418                                 part_type = lookup_data_type_by_name(def, attr->value);
00419                                 if (!part_type) return NULL;
00420                         }
00421                 }
00422                 msg_part = new_bs_message_part(mp, part_name, part_type);
00423                 add_part_to_message(m, msg_part, mp);
00424         }       
00425         return m;
00426 }
00427 
00428 
00437 static bs_message *lookup_message_by_element(const apr_xml_elem *elem,
00438         const bs_definition *def, apr_pool_t *mp)
00439 {
00440         const apr_xml_attr *attr;
00441         char *message_name = NULL;
00442         bs_uint32 i;
00443         
00444         /* Retrieve the message name from elem */
00445         for (attr = elem->attr; attr; attr = attr->next)
00446                 if (streq(attr->name, "message"))
00447                         message_name = apr_pstrdup(mp, attr->value);
00448         if (!message_name) return NULL;
00449         
00450         /* Look for the message by its name in the given definition def: */
00451         for (i = 0; i < def->num_messages; i++) {
00452                 bs_message *msg = def->messages[i];
00453                 if (streq(msg->name, message_name)) return msg; 
00454         }
00455         return NULL;
00456 }
00457 
00458 
00469 static bs_operation *process_operation(const apr_xml_elem *op, bs_definition *def,
00470         apr_pool_t *mp)
00471 {
00472         const apr_xml_elem *elem;
00473         const apr_xml_attr *attr;
00474         char *op_name = NULL;
00475         bs_message *input = NULL, *output = NULL, *fault = NULL;
00476         
00477         /* Process operation name attribute: */
00478         for (attr = op->attr; attr; attr = attr->next)
00479                 if (streq(attr->name, "name"))
00480                         op_name = apr_pstrdup(mp, attr->value);
00481         if (!op_name) return NULL;
00482         
00483         /* Lookup the named input, output and/or fault messages: */
00484         for (elem = op->first_child; elem; elem = elem->next) {
00485                 if (streq(elem->name, "input")) {
00486                         input = lookup_message_by_element(elem, def, mp);
00487                         if (!input) return NULL;
00488                 }
00489                 else if (streq(elem->name, "output")) {
00490                         output = lookup_message_by_element(elem, def, mp);
00491                         if (!output) return NULL;
00492                 }
00493                 else if (streq(elem->name, "fault")) {
00494                         fault = lookup_message_by_element(elem, def, mp);
00495                         if (!fault) return NULL;
00496                 }
00497         }
00498         
00499         return new_bs_operation(mp, op_name, input, output, fault);     
00500 }
00501 
00502 
00512 static bs_port_type *process_porttype(const apr_xml_elem *pt, bs_definition *def,
00513                 apr_pool_t *mp)
00514 {
00515         const apr_xml_elem *operation;
00516         const apr_xml_attr *attr;
00517         bs_port_type *p = NULL;
00518         
00519         /* Process portType name attribute and allocate bs_port_type structure: */
00520         for (attr = pt->attr; attr; attr = attr->next)
00521                 if (streq(attr->name, "name"))
00522                         p = new_bs_port_type(mp, attr->value, 0);
00523         if (!p) return NULL;
00524         
00525         /* Go through all the operations of the portType: */
00526         for (operation = pt->first_child; operation; operation = operation->next) {
00527                 bs_operation *op = process_operation(operation, def, mp);
00528                 if (!op) return NULL;
00529                 add_operation_to_port_type(p, op, mp);
00530         }
00531 
00532         return p;       
00533 }
00534 
00535 
00542 static bs_port_type *lookup_porttype_by_name(const char *name, bs_definition *def)
00543 {
00544         /* Look for the porttype by its name in the given definition def: */
00545         bs_uint16 i;
00546         for (i = 0; i < def->num_port_types; i++) {
00547                 bs_port_type *pt = def->port_types[i];
00548                 if (streq(pt->name, name)) return pt;   
00549         }
00550         return NULL;    
00551 }
00552 
00553 
00562 static bs_port *process_port(const apr_xml_elem *port, bs_definition *def,
00563                 apr_pool_t *mp)
00564 {
00565         const apr_xml_attr *attr;
00566         char *port_name = NULL;
00567         bs_port_type *port_type = NULL;
00568         
00569         /* Find the name and type of the port and create a bs_port structure: */
00570         for (attr = port->attr; attr; attr = attr->next) {
00571                 if (streq(attr->name, "name"))
00572                         port_name = apr_pstrdup(mp, attr->value);
00573                 else if (streq(attr->name, "type")) {
00574                         port_type = lookup_porttype_by_name(attr->value, def);
00575                         if (!port_type) return NULL;
00576                 }
00577         }
00578         return new_bs_port(mp, port_name, port_type);
00579 }
00580 
00581 
00591 static bs_service *process_service(const apr_xml_elem *svc, bs_definition *def,
00592                 apr_pool_t *mp)
00593 {
00594         const apr_xml_elem *port;
00595         const apr_xml_attr *attr;
00596         bs_service *s = NULL;
00597         
00598         /* Find the name of the service and create a bs_service structure: */
00599         for (attr = svc->attr; attr; attr = attr->next)
00600                 if (streq(attr->name, "name"))
00601                         s = new_bs_service(mp, attr->value, 0);
00602         if (!s) return NULL;
00603         
00604         /* Process all port elements in this service: */
00605         for (port = svc->first_child; port; port = port->next) {
00606                 bs_port *pt = process_port(port, def, mp);
00607                 if (!pt) return NULL;
00608                 add_port_to_service(s, pt, mp);
00609         }
00610 
00611         return s;       
00612 }
00613 
00614 
00622 static bs_status process_definition(const apr_xml_elem *root, bs_definition **def,
00623                 apr_pool_t *mp)
00624 {
00625         const apr_xml_elem *elem;
00626         const apr_xml_attr *attr;
00627         bs_definition *d = NULL;
00628         
00629         /* Process definition name attribute and allocate bs_definition structure: */
00630         for (attr = root->attr; attr; attr = attr->next)
00631                 if (streq(attr->name, "name"))
00632                         d = new_bs_definition(mp, attr->value, 0, 0, 0, 0);
00633         if (!d) return BS_XML_PARSE_ERROR;
00634         
00635         /* Process the different child elements: */
00636         for (elem = root->first_child; elem; elem = elem->next) {
00637                 if (streq(elem->name, "type")) {
00638                         bs_data_type *type = process_data_type(elem, mp);
00639                         if (!type) return BS_ERROR;
00640                         add_data_type_to_definition(d, type, mp);
00641                 }
00642                 else if (streq(elem->name, "message")) {
00643                         bs_message *msg = process_message(elem, d, mp);
00644                         if (!msg) return BS_ERROR;
00645                         add_message_to_definition(d, msg, mp);
00646                 }
00647                 else if (streq(elem->name, "portType")) {
00648                         bs_port_type *type = process_porttype(elem, d, mp);
00649                         if (!type) return BS_ERROR;
00650                         add_port_type_to_definition(d, type, mp);
00651                 }
00652                 else if (streq(elem->name, "service")) {
00653                         bs_service *svc = process_service(elem, d, mp);
00654                         if (!svc) return BS_ERROR;
00655                         add_service_to_definition(d, svc, mp);
00656                 }
00657         }
00658         
00659         *def = d;
00660         return BS_OK;
00661 }
00662 
00663 
00664 /*******************************************************
00665  *                                                     *
00666  *  SERVICE REQUEST FROM XML HELPER FUNCTIONS          *
00667  *                                                     *
00668  *******************************************************/
00669 
00674 static bs_status process_request_input_part(bs_part_instance **part,
00675                 const apr_xml_elem *elem, apr_pool_t *mp)
00676 {
00677         const apr_xml_attr *attr;
00678         bs_part_instance *ret = NULL;
00679         char *name = NULL, *data = NULL;
00680         bs_data_type *type = NULL;
00681         
00682         /* Get the attributes of the part: */
00683         for (attr = elem->attr; attr; attr = attr->next) {
00684                 if (streq(attr->name, "name"))
00685                         name = apr_pstrdup(mp, attr->value);
00686                 else if (streq(attr->name, "type"))
00687                         type = new_bs_data_type(mp, attr->value);
00688         }
00689         if (!name || !type) return BS_XML_PARSE_ERROR;
00690         
00691         /* Copy (and decode if necessary) the data: */
00692         if (type->builtin) {
00693                 if (elem->first_cdata.first == NULL) /* Be safe:  */
00694                         data = apr_pstrdup(mp, "");
00695                 else
00696                         data = apr_pstrdup(mp, elem->first_cdata.first->text);
00697         }
00698         else {
00699                 if (elem->first_cdata.first == NULL) /* Be safe:  */
00700                         data = apr_pstrdup(mp, "");
00701                 else {
00702                         const char *encbuf = elem->first_cdata.first->text;
00703                         data = apr_pcalloc(mp, apr_base64_decode_len(encbuf));
00704                         apr_base64_decode(data, encbuf);
00705                 }
00706         }
00707         ret = new_bs_part_instance(mp, name, type, data, strlen(data));
00708         if (!ret) return BS_ERROR;
00709         
00710         *part = ret;
00711         return BS_OK;
00712 }
00713 
00714 
00719 static bs_status process_request_input(const apr_xml_elem *msg,
00720                 bs_service_request *request, apr_pool_t *mp)
00721 {
00722         const apr_xml_attr *attr;
00723         const apr_xml_elem *part;
00724         bs_message_instance *inst = NULL;
00725         
00726         /* Find the message name and allocate it: */
00727         for (attr = msg->attr; attr; attr = attr->next)
00728                 if (streq(attr->name, "message"))
00729                         inst = new_bs_message_instance(mp, attr->value, 0);
00730         if (!inst) return BS_XML_PARSE_ERROR;
00731         
00732         /* Add the parts, one by one: */
00733         for (part = msg->first_child; part; part = part->next) {
00734                 bs_part_instance *pinst;
00735                 bs_status rv;
00736                 
00737                 /* Check if it's really a part and add to message instance: */
00738                 if (!streq(part->name, "part"))
00739                         return BS_XML_PARSE_ERROR;
00740                 rv = process_request_input_part(&pinst, part, mp);
00741                 if (rv != BS_OK) return BS_XML_PARSE_ERROR;
00742                 add_part_to_request_instance(pinst, inst, mp);
00743         }
00744         
00745         request->input = inst;
00746         return BS_OK;   
00747 }
00748 
00749 
00753 static bs_status process_request_use(const apr_xml_elem *elem,
00754                 bs_service_request *request, apr_pool_t *mp)
00755 {
00756         const apr_xml_attr *attr;
00757         
00758         for (attr = elem->attr; attr; attr = attr->next) {
00759                 if (streq(attr->name, "service"))
00760                         request->service = apr_pstrdup(mp, attr->value);
00761                 else if (streq(attr->name, "port"))
00762                         request->port = apr_pstrdup(mp, attr->value);
00763                 else if (streq(attr->name, "operation"))
00764                         request->operation = apr_pstrdup(mp, attr->value);
00765         }
00766         return BS_OK;   
00767 }
00768  
00769  
00770 static bs_status process_request(const apr_xml_elem *root,
00771                 bs_service_request **request,
00772                 apr_pool_t *mp)
00773 {
00774         const apr_xml_elem *elem;
00775         const apr_xml_attr *attr;
00776         bs_service_request *r = NULL;
00777         
00778         /* Create a new service_request structure: */
00779         for (attr = root->attr; attr; attr = attr->next)
00780                 if (streq(attr->name, "uuid")) {
00781                         bs_byte uuid[16];
00782                         apr_uuid_parse((apr_uuid_t *) &uuid, attr->value);
00783                         r = new_bs_service_request(mp, uuid, NULL, NULL, NULL, NULL);
00784                 }
00785         if (!r) return BS_XML_PARSE_ERROR;
00786         
00787         /* Search for the <use> element which contains the requested service: */
00788         for (elem = root->first_child; elem; elem = elem->next) {
00789                 if (streq(elem->name, "use")) {
00790                         bs_status rv = process_request_use(elem, r, mp);
00791                         if (rv != BS_OK) return BS_XML_PARSE_ERROR;
00792                 }
00793                 else if (streq(elem->name, "input")) {
00794                         bs_status rv = process_request_input(elem, r, mp);
00795                         if (rv != BS_OK) return BS_XML_PARSE_ERROR;
00796                 }
00797         }
00798         
00799         *request = r;
00800         return BS_OK;
00801 }
00802 
00803  
00804  /*******************************************************
00805  *                                                     *
00806  *  SERVICE RESPONSE FROM XML HELPER FUNCTIONS         *
00807  *                                                     *
00808  *******************************************************/
00809 static bs_status process_response_output(const apr_xml_elem *msg,
00810                 bs_service_response *response, apr_pool_t *mp)
00811 {
00812         const apr_xml_attr *attr;
00813         const apr_xml_elem *part;
00814         bs_message_instance *inst = NULL;
00815         
00816         /* Find the message name and allocate it: */
00817         for (attr = msg->attr; attr; attr = attr->next)
00818                 if (streq(attr->name, "message"))
00819                         inst = new_bs_message_instance(mp, attr->value, 0);
00820         if (!inst) return BS_XML_PARSE_ERROR;
00821         
00822         /* Add the parts, one by one: */
00823         for (part = msg->first_child; part; part = part->next) {
00824                 bs_part_instance *pinst;
00825                 bs_status rv;
00826                 
00827                 /* Check if it's really a part and add to message instance: */
00828                 if (!streq(part->name, "part"))
00829                         return BS_XML_PARSE_ERROR;
00830                 rv = process_request_input_part(&pinst, part, mp);
00831                 if (rv != BS_OK) return BS_XML_PARSE_ERROR;
00832                 add_part_to_request_instance(pinst, inst, mp);
00833         }
00834         
00835         response->output = inst;
00836         return BS_OK;   
00837 }
00838 
00839 
00840 static bs_status process_response_fault(const apr_xml_elem *msg,
00841                 bs_service_response *response, apr_pool_t *mp)
00842 {
00843         const apr_xml_attr *attr;
00844         const apr_xml_elem *part;
00845         bs_message_instance *inst = NULL;
00846         
00847         /* Find the message name and allocate it: */
00848         for (attr = msg->attr; attr; attr = attr->next)
00849                 if (streq(attr->name, "message"))
00850                         inst = new_bs_message_instance(mp, attr->value, 0);
00851         if (!inst) return BS_XML_PARSE_ERROR;
00852         
00853         /* Add the parts, one by one: */
00854         for (part = msg->first_child; part; part = part->next) {
00855                 bs_part_instance *pinst;
00856                 bs_status rv;
00857                 
00858                 /* Check if it's really a part and add to message instance: */
00859                 if (!streq(part->name, "part"))
00860                         return BS_XML_PARSE_ERROR;
00861                 rv = process_request_input_part(&pinst, part, mp);
00862                 if (rv != BS_OK) return BS_XML_PARSE_ERROR;
00863                 add_part_to_request_instance(pinst, inst, mp);
00864         }
00865         
00866         response->output = inst;
00867         return BS_OK;   
00868 }
00869 
00870 
00871 static bs_status process_response_used(const apr_xml_elem *elem,
00872                 bs_service_response *response, apr_pool_t *mp)
00873 {
00874         const apr_xml_attr *attr;
00875         
00876         for (attr = elem->attr; attr; attr = attr->next) {
00877                 if (streq(attr->name, "service"))
00878                         response->service = apr_pstrdup(mp, attr->value);
00879                 else if (streq(attr->name, "port"))
00880                         response->port = apr_pstrdup(mp, attr->value);
00881                 else if (streq(attr->name, "operation"))
00882                         response->operation = apr_pstrdup(mp, attr->value);
00883         }
00884         return BS_OK;   
00885 }
00886 
00887 
00888 static bs_status process_response(const apr_xml_elem *root,
00889                 bs_service_response **response,
00890                 apr_pool_t *mp)
00891 {
00892         const apr_xml_elem *elem;
00893         const apr_xml_attr *attr;
00894         bs_service_response *r = NULL;
00895         
00896         /* Create a new service_request structure: */
00897         for (attr = root->attr; attr; attr = attr->next)
00898                 if (streq(attr->name, "uuid")) {
00899                         bs_byte uuid[16];
00900                         apr_uuid_parse((apr_uuid_t *) &uuid, attr->value);
00901                         r = new_bs_service_response(mp, uuid, NULL, NULL, NULL, NULL, NULL);
00902                 }
00903         if (!r) return BS_XML_PARSE_ERROR;
00904         
00905         /* Search for the <used> element which contains the requested service: */
00906         for (elem = root->first_child; elem; elem = elem->next) {
00907                 if (streq(elem->name, "used")) {
00908                         bs_status rv = process_response_used(elem, r, mp);
00909                         if (rv != BS_OK) return BS_XML_PARSE_ERROR;
00910                 }
00911                 else if (streq(elem->name, "output")) {
00912                         bs_status rv = process_response_output(elem, r, mp);
00913                         if (rv != BS_OK) return BS_XML_PARSE_ERROR;
00914                 }
00915                 else if (streq(elem->name, "fault")) {
00916                         bs_status rv = process_response_fault(elem, r, mp);
00917                         if (rv != BS_OK) return BS_XML_PARSE_ERROR;
00918                 }
00919         }
00920         
00921         *response = r;
00922         return BS_OK;   
00923 }
00924 
00925 
00933 static bs_status process_tree(const apr_xml_elem *root, void **object, unsigned *type, apr_pool_t *mp)
00934 {
00935         /* This sometimes happens when expat is not correctly parsing: */
00936         if (!root) return BS_XML_PARSE_ERROR;
00937         
00938         if (streq(root->name, "definitions")) {
00939                 *type = SERVICE_DEF_FROM_XML;
00940                 return process_definition(root, (bs_definition **) object, mp);
00941         }
00942         else if (streq(root->name, "request")) {
00943                 *type = SERVICE_REQUEST_FROM_XML;
00944                 return process_request(root, (bs_service_request **) object, mp);
00945         }
00946         else if (streq(root->name, "response")) {
00947                 *type = SERVICE_RESPONSE_FROM_XML;
00948                 return process_response(root, (bs_service_response **) object, mp);
00949         }
00950         else return BS_XML_UNKNOWN_ROOT;        
00951 }
00952 
00953 
00954 bs_status xlate_from_xml(const char *buf, bs_uint64 limit, void **object,
00955                 unsigned *type, apr_pool_t *mp)
00956 {
00957         apr_xml_parser *parser = apr_xml_parser_create(mp);
00958         apr_xml_doc *doc;
00959     apr_status_t rv;
00960         
00961         /* Advance the pointer in the buffer until a '<' is encountered: */
00962         while (buf[0] != '<' && buf[0] != '\0' && limit > 0) {
00963                 buf++;
00964                 limit--;
00965         }
00966 
00967         /* Parse the given buffer with XML in one go: */
00968         rv = apr_xml_parser_feed(parser, buf, limit);
00969     if (rv != APR_SUCCESS) {
00970         char err[256];
00971         apr_xml_parser_geterror(parser, err, sizeof(err));
00972         fprintf(stderr, "XML parse error: %s\n", err);
00973         return BS_XML_NWF;
00974     }
00975     else apr_xml_parser_done(parser, &doc);
00976     
00977     /* Process the generated tree into a bs_definition/request/response struct: */
00978     return process_tree(doc->root, object, type, mp);    
00979 }

Generated on Tue Jul 17 09:50:52 2007 for Bio-SPHERE by  doxygen 1.5.1