celix_status_t endpointDescriptorReader_parseDocument()

in bundles/remote_services/discovery_common/src/endpoint_descriptor_reader.c [93:268]


celix_status_t endpointDescriptorReader_parseDocument(endpoint_descriptor_reader_t *reader, char *document, celix_array_list_t** endpoints) {
    celix_status_t status = CELIX_SUCCESS;

    reader->reader = xmlReaderForMemory(document, (int) strlen(document), NULL, "UTF-8", 0);
    if (reader->reader == NULL) {
        status = CELIX_BUNDLE_EXCEPTION;
    } else {
        bool inProperty = false;
        bool inXml = false;
        bool inArray = false;
        bool inList = false;
        bool inSet = false;
        bool inValue = false;

        const xmlChar *propertyName = NULL;
        const xmlChar *propertyValue = NULL;
        valueType propertyType = VALUE_TYPE_STRING;
        xmlChar *valueBuffer = xmlMalloc(256);
        valueBuffer[0] = '\0';

        celix_array_list_t* propertyValues = celix_arrayList_create();

        celix_array_list_t* endpointDescriptions = NULL;
        if (*endpoints) {
            // use the given arraylist...
            endpointDescriptions = *endpoints;
        } else {
            endpointDescriptions = celix_arrayList_create();
            // return the read endpoints...
            *endpoints = endpointDescriptions;
        }

        celix_properties_t *endpointProperties = NULL;

        int read = xmlTextReaderRead(reader->reader);
        while (read == XML_TEXTREADER_MODE_INTERACTIVE) {
            int type = xmlTextReaderNodeType(reader->reader);

            if (type == XML_READER_TYPE_ELEMENT) {
                const xmlChar *localname = xmlTextReaderConstLocalName(reader->reader);

                if (inXml) {
                    valueBuffer = xmlStrcat(valueBuffer, BAD_CAST "<");
                    valueBuffer = xmlStrcat(valueBuffer, localname);

                    int i = xmlTextReaderMoveToFirstAttribute(reader->reader);
                    while (i == 1) {
                        const xmlChar *name = xmlTextReaderConstName(reader->reader);
                        const xmlChar *value = xmlTextReaderConstValue(reader->reader);

                        valueBuffer = xmlStrcat(valueBuffer, BAD_CAST " ");
                        valueBuffer = xmlStrcat(valueBuffer, name);
                        valueBuffer = xmlStrcat(valueBuffer, BAD_CAST "=\"");
                        valueBuffer = xmlStrcat(valueBuffer, BAD_CAST value);
                        valueBuffer = xmlStrcat(valueBuffer, BAD_CAST "\"");

                        i = xmlTextReaderMoveToNextAttribute(reader->reader);
                    }

                    valueBuffer = xmlStrcat(valueBuffer, BAD_CAST ">");
                } else if (xmlStrcmp(localname, ENDPOINT_DESCRIPTION) == 0) {

                    if (endpointProperties != NULL)
                        celix_properties_destroy(endpointProperties);

                    endpointProperties = celix_properties_create();
                } else if (xmlStrcmp(localname, PROPERTY) == 0) {
                    inProperty = true;

                    propertyName = xmlTextReaderGetAttribute(reader->reader, NAME);
                    propertyValue = xmlTextReaderGetAttribute(reader->reader, VALUE);
                    xmlChar *vtype = xmlTextReaderGetAttribute(reader->reader, VALUE_TYPE);
                    propertyType = valueTypeFromString((char*) vtype);
                    celix_arrayList_clear(propertyValues);

                    if (xmlTextReaderIsEmptyElement(reader->reader)) {
                        inProperty = false;

                        if (propertyValue != NULL) {
                            endpointDescriptorReader_addSingleValuedProperty(endpointProperties, propertyName, propertyValue);
                        }

                        xmlFree((void *) propertyName);
                        xmlFree((void *) propertyValue);
                        xmlFree((void *) vtype);
                    }
                } else {
                    valueBuffer[0] = 0;
                    inArray |= inProperty && xmlStrcmp(localname, ARRAY) == 0;
                    inList |= inProperty && xmlStrcmp(localname, LIST) == 0;
                    inSet |= inProperty && xmlStrcmp(localname, SET) == 0;
                    inXml |= inProperty && xmlStrcmp(localname, XML) == 0;
                    inValue |= inProperty && xmlStrcmp(localname, VALUE) == 0;
                }
            } else if (type == XML_READER_TYPE_END_ELEMENT) {
                const xmlChar *localname = xmlTextReaderConstLocalName(reader->reader);

                if (inXml) {
                    if (xmlStrcmp(localname, XML) != 0)  {
                        valueBuffer = xmlStrcat(valueBuffer, BAD_CAST "</");
                        valueBuffer = xmlStrcat(valueBuffer, localname);
                        valueBuffer = xmlStrcat(valueBuffer, BAD_CAST ">");
                    }
                    else {
                        inXml = false;
                    }
                } else if (xmlStrcmp(localname, ENDPOINT_DESCRIPTION) == 0) {
                    endpoint_description_t *endpointDescription = NULL;
                    // Completely parsed endpoint description, add it to our list of results...
                    if(endpointDescription_create(endpointProperties, &endpointDescription) == CELIX_SUCCESS){
                        celix_arrayList_add(endpointDescriptions, endpointDescription);
                    }

                    endpointProperties = celix_properties_create();
                } else if (xmlStrcmp(localname, PROPERTY) == 0) {
                    inProperty = false;

                    if (inArray || inList || inSet) {
                        endpointDescriptorReader_addMultiValuedProperty(endpointProperties, propertyName, propertyValues);
                    }
                    else if (propertyValue != NULL) {
                        if (propertyType != VALUE_TYPE_STRING) {
                            celix_logHelper_warning(*reader->loghelper, "ENDPOINT_DESCRIPTOR_READER: Only string support for %s\n", propertyName);
                        }
                        endpointDescriptorReader_addSingleValuedProperty(endpointProperties, propertyName, propertyValue);

                        xmlFree((void *) propertyValue);
                    }
                    else {
                        endpointDescriptorReader_addSingleValuedProperty(endpointProperties, propertyName, valueBuffer);
                    }

                    xmlFree((void *) propertyName);
                    unsigned int k=0;
                    for(;k<celix_arrayList_size(propertyValues);k++){
                        free(celix_arrayList_get(propertyValues,k));
                    }
                    celix_arrayList_clear(propertyValues);

                    propertyType = VALUE_TYPE_STRING;
                    inArray = false;
                    inList = false;
                    inSet = false;
                    inXml = false;
                } else if (xmlStrcmp(localname, VALUE) == 0) {
                    celix_arrayList_add(propertyValues, strdup((char*) valueBuffer));
                    valueBuffer[0] = 0;
                    inValue = false;
                }
            } else if (type == XML_READER_TYPE_TEXT) {
                if (inValue || inXml) {
                    const xmlChar *value = xmlTextReaderValue(reader->reader);
                    valueBuffer = xmlStrcat(valueBuffer, value);
                    xmlFree((void *)value);
                }
            }

            read = xmlTextReaderRead(reader->reader);
        }

        if(endpointProperties!=NULL){
            celix_properties_destroy(endpointProperties);
        }

        unsigned int k=0;
        for(;k<celix_arrayList_size(propertyValues);k++){
            free(celix_arrayList_get(propertyValues,k));
        }
        celix_arrayList_destroy(propertyValues);
        xmlFree(valueBuffer);

        xmlFreeTextReader(reader->reader);
    }

    return status;
}