| /** |
| *Licensed to the Apache Software Foundation (ASF) under one |
| *or more contributor license agreements. See the NOTICE file |
| *distributed with this work for additional information |
| *regarding copyright ownership. The ASF licenses this file |
| *to you under the Apache License, Version 2.0 (the |
| *"License"); you may not use this file except in compliance |
| *with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| *Unless required by applicable law or agreed to in writing, |
| *software distributed under the License is distributed on an |
| *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| *specific language governing permissions and limitations |
| *under the License. |
| */ |
| /* |
| * manifest_parser.c |
| * |
| * \date Jul 12, 2010 |
| * \author <a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a> |
| * \copyright Apache License, Version 2.0 |
| */ |
| #include <stdlib.h> |
| #include <string.h> |
| |
| #include "utils.h" |
| #include "constants.h" |
| #include "manifest_parser.h" |
| #include "capability.h" |
| #include "requirement.h" |
| #include "attribute.h" |
| #include "hash_map.h" |
| #include "celix_errno.h" |
| #include "linked_list_iterator.h" |
| #include "celix_log.h" |
| |
| //FIXME the manifest parser has no destroy function and as result contains memory leaks. |
| |
| struct manifestParser { |
| module_pt owner; |
| manifest_pt manifest; |
| |
| version_pt bundleVersion; |
| char * bundleSymbolicName; |
| linked_list_pt capabilities; |
| linked_list_pt requirements; |
| }; |
| |
| static linked_list_pt manifestParser_parseImportHeader(char * header); |
| static linked_list_pt manifestParser_parseExportHeader(module_pt module, char * header); |
| static linked_list_pt manifestParser_parseDelimitedString(char * value, char * delim); |
| static linked_list_pt manifestParser_parseStandardHeaderClause(char * clauseString); |
| static linked_list_pt manifestParser_parseStandardHeader(char * header); |
| |
| celix_status_t manifestParser_create(module_pt owner, manifest_pt manifest, manifest_parser_pt *manifest_parser) { |
| celix_status_t status; |
| manifest_parser_pt parser; |
| |
| status = CELIX_SUCCESS; |
| parser = (manifest_parser_pt) malloc(sizeof(*parser)); |
| if (parser) { |
| char * bundleVersion = NULL; |
| char * bundleSymbolicName = NULL; |
| parser->manifest = manifest; |
| parser->owner = owner; |
| |
| bundleVersion = manifest_getValue(manifest, OSGI_FRAMEWORK_BUNDLE_VERSION); |
| if (bundleVersion != NULL) { |
| parser->bundleVersion = NULL; |
| version_createVersionFromString(bundleVersion, &parser->bundleVersion); |
| } else { |
| parser->bundleVersion = NULL; |
| version_createEmptyVersion(&parser->bundleVersion); |
| } |
| bundleSymbolicName = manifest_getValue(manifest, OSGI_FRAMEWORK_BUNDLE_SYMBOLICNAME); |
| if (bundleSymbolicName != NULL) { |
| parser->bundleSymbolicName = bundleSymbolicName; |
| } |
| |
| parser->capabilities = manifestParser_parseExportHeader(owner, manifest_getValue(manifest, OSGI_FRAMEWORK_EXPORT_LIBRARY)); |
| parser->requirements = manifestParser_parseImportHeader(manifest_getValue(manifest, OSGI_FRAMEWORK_IMPORT_LIBRARY)); |
| |
| *manifest_parser = parser; |
| |
| status = CELIX_SUCCESS; |
| } else { |
| status = CELIX_ENOMEM; |
| } |
| |
| framework_logIfError(logger, status, NULL, "Cannot create manifest parser"); |
| |
| return status; |
| } |
| |
| celix_status_t manifestParser_destroy(manifest_parser_pt mp) { |
| linkedList_destroy(mp->capabilities); |
| mp->capabilities = NULL; |
| linkedList_destroy(mp->requirements); |
| mp->requirements = NULL; |
| mp->bundleSymbolicName = NULL; |
| version_destroy(mp->bundleVersion); |
| mp->bundleVersion = NULL; |
| mp->manifest = NULL; |
| mp->owner = NULL; |
| |
| free(mp); |
| |
| return CELIX_SUCCESS; |
| } |
| |
| static linked_list_pt manifestParser_parseDelimitedString(char * value, char * delim) { |
| linked_list_pt list; |
| |
| if (linkedList_create(&list) == CELIX_SUCCESS) { |
| if (value != NULL) { |
| int CHAR = 1; |
| int DELIMITER = 2; |
| int STARTQUOTE = 4; |
| int ENDQUOTE = 8; |
| |
| char buffer[512]; |
| int expecting = (CHAR | DELIMITER | STARTQUOTE); |
| unsigned int i; |
| |
| buffer[0] = '\0'; |
| |
| for (i = 0; i < strlen(value); i++) { |
| char c = value[i]; |
| |
| bool isDelimiter = (strchr(delim, c) != NULL); |
| bool isQuote = (c == '"'); |
| |
| if (isDelimiter && ((expecting & DELIMITER) > 0)) { |
| linkedList_addElement(list, strdup(buffer)); |
| buffer[0] = '\0'; |
| expecting = (CHAR | DELIMITER | STARTQUOTE); |
| } else if (isQuote && ((expecting & STARTQUOTE) > 0)) { |
| char tmp[2]; |
| tmp[0] = c; |
| tmp[1] = '\0'; |
| strcat(buffer, tmp); |
| expecting = CHAR | ENDQUOTE; |
| } else if (isQuote && ((expecting & ENDQUOTE) > 0)) { |
| char tmp[2]; |
| tmp[0] = c; |
| tmp[1] = '\0'; |
| strcat(buffer, tmp); |
| expecting = (CHAR | STARTQUOTE | DELIMITER); |
| } else if ((expecting & CHAR) > 0) { |
| char tmp[2]; |
| tmp[0] = c; |
| tmp[1] = '\0'; |
| strcat(buffer, tmp); |
| } else { |
| return NULL; |
| } |
| } |
| |
| if (strlen(buffer) > 0) { |
| linkedList_addElement(list, strdup(utils_stringTrim(buffer))); |
| } |
| } |
| } |
| |
| return list; |
| } |
| |
| static linked_list_pt manifestParser_parseStandardHeaderClause(char * clauseString) { |
| linked_list_pt paths; |
| linked_list_pt clause; |
| linked_list_pt pieces; |
| |
| clause = NULL; |
| pieces = manifestParser_parseDelimitedString(clauseString, ";"); |
| |
| if (linkedList_create(&paths) == CELIX_SUCCESS) { |
| int pathCount = 0; |
| int pieceIdx; |
| hash_map_pt dirsMap = NULL; |
| hash_map_pt attrsMap = NULL; |
| char * sep; |
| |
| for (pieceIdx = 0; pieceIdx < linkedList_size(pieces); pieceIdx++) { |
| char * piece = linkedList_get(pieces, pieceIdx); |
| if (strchr(piece, '=') != NULL) { |
| break; |
| } else { |
| linkedList_addElement(paths, strdup(piece)); |
| pathCount++; |
| } |
| } |
| |
| if (pathCount == 0) { |
| return NULL; |
| } |
| |
| dirsMap = hashMap_create(utils_stringHash, NULL, utils_stringEquals, NULL); |
| attrsMap = hashMap_create(utils_stringHash, NULL, utils_stringEquals, NULL); |
| |
| |
| for (pieceIdx = pathCount; pieceIdx < linkedList_size(pieces); pieceIdx++) { |
| char * sepPtr; |
| char * key; |
| char * value; |
| char * DIRECTIVE_SEP = ":="; |
| char * ATTRIBUTE_SEP = "="; |
| char * piece = linkedList_get(pieces, pieceIdx); |
| if ((sepPtr = strstr(piece, DIRECTIVE_SEP)) != NULL) { |
| sep = DIRECTIVE_SEP; |
| } else if ((sepPtr = strstr(piece, ATTRIBUTE_SEP)) != NULL) { |
| sep = ATTRIBUTE_SEP; |
| } else { |
| return NULL; |
| } |
| |
| key = string_ndup(piece, sepPtr - piece); |
| value = strdup(sepPtr+strlen(sep)); |
| |
| if (value[0] == '"' && value[strlen(value) -1] == '"') { |
| char * oldV = strdup(value); |
| int len = strlen(oldV) - 2; |
| value = (char *) realloc(value, (sizeof(char) * len+1)); |
| value[0] = '\0'; |
| value = strncpy(value, oldV+1, strlen(oldV) - 2); |
| value[len] = '\0'; |
| //check if correct |
| free(oldV); |
| } |
| |
| if (strcmp(sep, DIRECTIVE_SEP) == 0) { |
| // Not implemented |
| } else { |
| attribute_pt attr = NULL; |
| if (hashMap_containsKey(attrsMap, key)) { |
| return NULL; |
| } |
| |
| if (attribute_create(key, value, &attr) == CELIX_SUCCESS) { |
| hashMap_put(attrsMap, key, attr); |
| } |
| } |
| } |
| |
| if (linkedList_create(&clause) == CELIX_SUCCESS) { |
| linkedList_addElement(clause, paths); |
| linkedList_addElement(clause, dirsMap); |
| linkedList_addElement(clause, attrsMap); |
| } |
| } |
| |
| for(int listIdx = 0; listIdx < linkedList_size(pieces); listIdx++){ |
| void * element = linkedList_get(pieces, listIdx); |
| free(element); |
| } |
| |
| linkedList_destroy(pieces); |
| |
| |
| return clause; |
| } |
| |
| static linked_list_pt manifestParser_parseStandardHeader(char * header) { |
| linked_list_pt clauseStrings = NULL; |
| linked_list_pt completeList = NULL; |
| |
| if (linkedList_create(&completeList) == CELIX_SUCCESS) { |
| if (header != NULL) { |
| if (strlen(header) == 0) { |
| return NULL; |
| } |
| |
| char *hdr = strdup(header); |
| clauseStrings = manifestParser_parseDelimitedString(hdr, ","); |
| free(hdr); |
| if (clauseStrings != NULL) { |
| int i; |
| for (i = 0; i < linkedList_size(clauseStrings); i++) { |
| char *clauseString = (char *) linkedList_get(clauseStrings, i); |
| linkedList_addElement(completeList, manifestParser_parseStandardHeaderClause(clauseString)); |
| free(clauseString); |
| } |
| linkedList_destroy(clauseStrings); |
| } |
| } |
| } |
| |
| return completeList; |
| } |
| |
| static linked_list_pt manifestParser_parseImportHeader(char * header) { |
| linked_list_pt clauses; |
| linked_list_pt requirements; |
| |
| int clauseIdx; |
| linked_list_iterator_pt iter; |
| clauses = manifestParser_parseStandardHeader(header); |
| linkedList_create(&requirements); |
| |
| for (clauseIdx = 0; clauseIdx < linkedList_size(clauses); clauseIdx++) { |
| linked_list_pt clause = linkedList_get(clauses, clauseIdx); |
| |
| linked_list_pt paths = linkedList_get(clause, 0); |
| hash_map_pt directives = linkedList_get(clause, 1); |
| hash_map_pt attributes = linkedList_get(clause, 2); |
| |
| int pathIdx; |
| for (pathIdx = 0; pathIdx < linkedList_size(paths); pathIdx++) { |
| attribute_pt name = NULL; |
| requirement_pt req = NULL; |
| char * path = (char *) linkedList_get(paths, pathIdx); |
| if (strlen(path) == 0) { |
| return NULL; |
| } |
| |
| if (attribute_create(strdup("service"), path, &name) == CELIX_SUCCESS) { |
| char *key = NULL; |
| attribute_getKey(name, &key); |
| hashMap_put(attributes, key, name); |
| } |
| |
| requirement_create(directives, attributes, &req); |
| linkedList_addElement(requirements, req); |
| } |
| } |
| |
| iter = linkedListIterator_create(clauses, 0); |
| while(linkedListIterator_hasNext(iter)) { |
| linked_list_pt clause = linkedListIterator_next(iter); |
| |
| linked_list_pt paths = linkedList_get(clause, 0); |
| linkedList_destroy(paths); |
| |
| linkedListIterator_remove(iter); |
| linkedList_destroy(clause); |
| } |
| linkedListIterator_destroy(iter); |
| linkedList_destroy(clauses); |
| |
| return requirements; |
| } |
| |
| static linked_list_pt manifestParser_parseExportHeader(module_pt module, char * header) { |
| linked_list_pt clauses; |
| linked_list_pt capabilities; |
| int clauseIdx; |
| linked_list_iterator_pt iter; |
| clauses = manifestParser_parseStandardHeader(header); |
| linkedList_create(&capabilities); |
| |
| |
| for (clauseIdx = 0; clauseIdx < linkedList_size(clauses); clauseIdx++) { |
| linked_list_pt clause = linkedList_get(clauses, clauseIdx); |
| |
| linked_list_pt paths = linkedList_get(clause, 0); |
| hash_map_pt directives = linkedList_get(clause, 1); |
| hash_map_pt attributes = linkedList_get(clause, 2); |
| |
| int pathIdx; |
| for (pathIdx = 0; pathIdx < linkedList_size(paths); pathIdx++) { |
| char * path = (char *) linkedList_get(paths, pathIdx); |
| attribute_pt name = NULL; |
| capability_pt cap = NULL; |
| if (strlen(path) == 0) { |
| return NULL; |
| } |
| |
| if (attribute_create(strdup("service"), path, &name) == CELIX_SUCCESS) { |
| char *key = NULL; |
| attribute_getKey(name, &key); |
| hashMap_put(attributes, key, name); |
| } |
| |
| capability_create(module, directives, attributes, &cap); |
| linkedList_addElement(capabilities, cap); |
| } |
| } |
| iter = linkedListIterator_create(clauses, 0); |
| while(linkedListIterator_hasNext(iter)) { |
| linked_list_pt clause = linkedListIterator_next(iter); |
| |
| linked_list_pt paths = linkedList_get(clause, 0); |
| linkedList_destroy(paths); |
| |
| linkedListIterator_remove(iter); |
| linkedList_destroy(clause); |
| } |
| linkedListIterator_destroy(iter); |
| linkedList_destroy(clauses); |
| |
| return capabilities; |
| } |
| |
| celix_status_t manifestParser_getSymbolicName(manifest_parser_pt parser, char **symbolicName) { |
| *symbolicName = strdup(parser->bundleSymbolicName); |
| return CELIX_SUCCESS; |
| } |
| |
| celix_status_t manifestParser_getBundleVersion(manifest_parser_pt parser, version_pt *version) { |
| return version_clone(parser->bundleVersion, version); |
| } |
| |
| celix_status_t manifestParser_getCapabilities(manifest_parser_pt parser, linked_list_pt *capabilities) { |
| celix_status_t status; |
| |
| status = linkedList_clone(parser->capabilities, capabilities); |
| |
| return status; |
| } |
| |
| celix_status_t manifestParser_getRequirements(manifest_parser_pt parser, linked_list_pt *requirements) { |
| celix_status_t status; |
| |
| status = linkedList_clone(parser->requirements, requirements); |
| |
| return status; |
| } |