| // 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. |
| |
| #include "DFPlatform.h" |
| #include "DFNameMap.h" |
| #include "DFDOM.h" |
| #include "DFHashTable.h" |
| #include "DFCommon.h" |
| #include "DFPlatform.h" |
| #include <assert.h> |
| #include <stdlib.h> |
| #include <string.h> |
| |
| static void NameMap_staticInit(); |
| |
| //////////////////////////////////////////////////////////////////////////////////////////////////// |
| // // |
| // DFNameHashTable // |
| // // |
| //////////////////////////////////////////////////////////////////////////////////////////////////// |
| |
| #define HASH_TABLE_SIZE 983 |
| |
| typedef struct DFNameEntry { |
| char *name; |
| char *URI; |
| Tag tag; |
| unsigned int namespaceID; |
| TagDecl tagDecl; |
| struct DFNameEntry *next; |
| } DFNameEntry; |
| |
| typedef struct DFNameHashTable { |
| DFNameEntry *bins[HASH_TABLE_SIZE]; |
| } DFNameHashTable; |
| |
| static uint32_t DFNameHashTableHash(const char *name, const char *URI) |
| { |
| DFHashCode hash; |
| DFHashBegin(hash); |
| for(DFHashCode i = 0; name[i]; ++i) |
| DFHashUpdate(hash,name[i]); |
| for(DFHashCode i = 0; URI[i]; ++i) |
| DFHashUpdate(hash,URI[i]); |
| DFHashEnd(hash); |
| |
| return hash; |
| } |
| |
| static const DFNameEntry *DFNameHashTableGet(DFNameHashTable *table, const char *name, const char *URI) |
| { |
| if (URI == NULL) |
| URI = "";; |
| uint32_t hash = DFNameHashTableHash(name,URI)%HASH_TABLE_SIZE; |
| for (DFNameEntry *entry = table->bins[hash]; entry != NULL; entry = entry->next) { |
| if (!strcmp(name,entry->name) && !strcmp(URI,entry->URI)) |
| return entry; |
| } |
| return 0; |
| } |
| |
| static void DFNameHashTableAdd(DFNameHashTable *table, const char *name, const char *URI, |
| Tag tag, unsigned int namespaceID) |
| { |
| if (URI == NULL) |
| URI = "";; |
| uint32_t hash = DFNameHashTableHash(name,URI)%HASH_TABLE_SIZE; |
| DFNameEntry *entry = (DFNameEntry *)xmalloc(sizeof(DFNameEntry)); |
| entry->name = xstrdup(name); |
| entry->URI = xstrdup(URI); |
| entry->tag = tag; |
| entry->tagDecl.namespaceID = namespaceID; |
| entry->tagDecl.localName = (const char *)entry->name; |
| entry->next = table->bins[hash]; |
| table->bins[hash] = entry; |
| } |
| |
| static DFNameHashTable *DFNameHashTableNew() |
| { |
| return (DFNameHashTable*)xcalloc(1,sizeof(DFNameHashTable)); |
| } |
| |
| static void DFNameHashTableFree(DFNameHashTable *table) |
| { |
| for (uint32_t hash = 0; hash < HASH_TABLE_SIZE; hash++) { |
| DFNameEntry *entry = table->bins[hash]; |
| while (entry != NULL) { |
| DFNameEntry *next = entry->next; |
| free(entry->name); |
| free(entry->URI); |
| free(entry); |
| entry = next; |
| } |
| } |
| free(table); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////////////////////////// |
| // // |
| // DFNamespaceInfo // |
| // // |
| //////////////////////////////////////////////////////////////////////////////////////////////////// |
| |
| typedef struct DFNamespaceInfo DFNamespaceInfo; |
| |
| struct DFNamespaceInfo { |
| NamespaceID nsId; |
| NamespaceDecl *decl; |
| }; |
| |
| DFNamespaceInfo *DFNamespaceInfoNew(NamespaceID nsId, const char *URI, const char *prefix) |
| { |
| DFNamespaceInfo *info = (DFNamespaceInfo *)xcalloc(1,sizeof(DFNamespaceInfo)); |
| info->nsId = nsId; |
| info->decl = (NamespaceDecl *)xmalloc(sizeof(NamespaceDecl)); |
| info->decl->namespaceURI = xstrdup(URI); |
| info->decl->prefix = xstrdup(prefix); |
| return info; |
| } |
| |
| void DFNamespaceInfoFree(DFNamespaceInfo *info) |
| { |
| free((char *)info->decl->namespaceURI); |
| free((char *)info->decl->prefix); |
| free(info->decl); |
| free(info); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////////////////////////// |
| // // |
| // DFTagInfo // |
| // // |
| //////////////////////////////////////////////////////////////////////////////////////////////////// |
| |
| typedef struct DFTagInfo DFTagInfo; |
| |
| struct DFTagInfo { |
| Tag tag; |
| TagDecl *decl; |
| }; |
| |
| DFTagInfo *DFTagInfoNew(Tag tag, NamespaceID nsId, const char *localName) |
| { |
| DFTagInfo *info = (DFTagInfo *)xcalloc(1,sizeof(DFTagInfo)); |
| info->tag = tag; |
| info->decl = (TagDecl *)xmalloc(sizeof(TagDecl)); |
| info->decl->namespaceID = nsId; |
| info->decl->localName = xstrdup(localName); |
| return info; |
| } |
| |
| void DFTagInfoFree(DFTagInfo *info) |
| { |
| free((char *)info->decl->localName); |
| free(info->decl); |
| free(info); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////////////////////////// |
| // // |
| // DFNameMap // |
| // // |
| //////////////////////////////////////////////////////////////////////////////////////////////////// |
| |
| DFHashTable *defaultNamespacesByURI = NULL; |
| DFNameHashTable *defaultTagsByNameURI = NULL; |
| |
| static void DFNameMapAddNamespace(DFNameMap *map, NamespaceID nsId, const char *URI, const char *prefix); |
| |
| |
| struct DFNameMap { |
| DFHashTable *namespacesByID; // NSNumber -> NamespaceInfo |
| DFHashTable *namespacesByURI; // NSString -> NamespaceInfo |
| DFHashTable *tagsByID; // NSNumber -> TagInfo |
| |
| |
| DFNameHashTable *localTagsByNameURI; |
| NamespaceID nextNamespaceId; |
| Tag nextTag; |
| }; |
| |
| DFNameMap *DFNameMapNew(void) |
| { |
| DFNameMap *map = (DFNameMap *)xcalloc(1,sizeof(DFNameMap)); |
| map->namespacesByID = DFHashTableNew2(NULL,NULL,997); |
| map->namespacesByURI = DFHashTableNew2(NULL,(DFFreeFunction)DFNamespaceInfoFree,997); |
| map->tagsByID = DFHashTableNew2(NULL,(DFFreeFunction)DFTagInfoFree,997); |
| map->nextNamespaceId = PREDEFINED_NAMESPACE_COUNT; |
| map->nextTag = PREDEFINED_TAG_COUNT; |
| map->localTagsByNameURI = DFNameHashTableNew(); |
| NameMap_staticInit(); |
| return map; |
| } |
| |
| void DFNameMapFree(DFNameMap *map) |
| { |
| DFHashTableRelease(map->namespacesByID); |
| DFHashTableRelease(map->namespacesByURI); |
| DFHashTableRelease(map->tagsByID); |
| DFNameHashTableFree(map->localTagsByNameURI); |
| free(map); |
| } |
| |
| static NamespaceID NameMap_namespaceIDForURI(DFNameMap *map, const char *URI) |
| { |
| if (URI == NULL) |
| return NAMESPACE_NULL;; |
| DFNamespaceInfo *ns = DFHashTableLookup(map->namespacesByURI,(const char *)URI); |
| if (ns == NULL) { |
| ns = DFHashTableLookup(defaultNamespacesByURI,(const char *)URI); |
| } |
| assert(ns != NULL); |
| return ns->nsId; |
| } |
| |
| static void DFNameMapAddNamespace(DFNameMap *map, NamespaceID nsId, const char *URI, const char *prefix) |
| { |
| assert(DFHashTableLookup(defaultNamespacesByURI,(const char *)URI) == NULL); |
| assert(DFHashTableLookup(map->namespacesByURI,(const char *)URI) == NULL); |
| DFNamespaceInfo *ns = DFNamespaceInfoNew(nsId,URI,prefix); |
| if (nsId >= PREDEFINED_NAMESPACE_COUNT) { |
| DFHashTableAddInt(map->namespacesByID,nsId,ns); |
| } |
| DFHashTableAdd(map->namespacesByURI,(const char *)URI,ns); |
| } |
| |
| NamespaceID DFNameMapFoundNamespace(DFNameMap *map, const char *URI, const char *prefix) |
| { |
| DFNamespaceInfo *existing; |
| existing = DFHashTableLookup(defaultNamespacesByURI,(const char *)URI); |
| if (existing != NULL) |
| return existing->nsId; |
| existing = DFHashTableLookup(map->namespacesByURI,(const char *)URI); |
| if (existing != NULL) |
| return existing->nsId;; |
| NamespaceID nsId = map->nextNamespaceId++; |
| DFNameMapAddNamespace(map,nsId,URI,prefix); |
| return nsId; |
| } |
| |
| const NamespaceDecl *DFNameMapNamespaceForID(DFNameMap *map, NamespaceID nsId) |
| { |
| if (nsId < PREDEFINED_NAMESPACE_COUNT) |
| return &PredefinedNamespaces[nsId];; |
| DFNamespaceInfo *ns = DFHashTableLookupInt(map->namespacesByID,nsId); |
| assert(ns != NULL); |
| return ns->decl; |
| } |
| |
| NamespaceID DFNameMapNamespaceCount(DFNameMap *map) |
| { |
| return map->nextNamespaceId; |
| } |
| |
| const TagDecl *DFNameMapNameForTag(DFNameMap *map, Tag tag) |
| { |
| if (tag < PREDEFINED_TAG_COUNT) |
| return &PredefinedTags[tag];; |
| DFTagInfo *info = DFHashTableLookupInt(map->tagsByID,tag); |
| assert(info != NULL); |
| return info->decl; |
| } |
| |
| Tag DFNameMapTagForName(DFNameMap *map, const char *URI, const char *localName) |
| { |
| const DFNameEntry *entry = DFNameHashTableGet(defaultTagsByNameURI,localName,URI); |
| if (entry == NULL) |
| entry = DFNameHashTableGet(map->localTagsByNameURI,localName,URI); |
| |
| if (entry != NULL) |
| return entry->tag;; |
| |
| // Dynamically allocate new tag |
| NamespaceID nsId = NameMap_namespaceIDForURI(map,URI); |
| Tag tag = map->nextTag++; |
| DFTagInfo *info = DFTagInfoNew(tag,nsId,localName); |
| DFHashTableAddInt(map->tagsByID,tag,info); |
| DFNameHashTableAdd(map->localTagsByNameURI,localName,URI,tag,nsId); |
| return tag; |
| } |
| |
| static void NameMap_staticInit() |
| { |
| if (defaultNamespacesByURI != NULL) |
| return; |
| defaultNamespacesByURI = DFHashTableNew2(NULL,NULL,997); |
| defaultTagsByNameURI = DFNameHashTableNew(); |
| |
| for (NamespaceID nsId = 1; nsId < PREDEFINED_NAMESPACE_COUNT; nsId++) { |
| const NamespaceDecl *decl = &PredefinedNamespaces[nsId]; |
| |
| const char *key = (const char *)decl->namespaceURI; |
| assert(DFHashTableLookup(defaultNamespacesByURI,key) == NULL); |
| DFNamespaceInfo *ns = DFNamespaceInfoNew(nsId,decl->namespaceURI,decl->prefix); |
| DFHashTableAdd(defaultNamespacesByURI,key,ns); |
| } |
| for (Tag tag = MIN_ELEMENT_TAG; tag < PREDEFINED_TAG_COUNT; tag++) { |
| const TagDecl *tagDecl = &PredefinedTags[tag]; |
| const NamespaceDecl *nsDecl = &PredefinedNamespaces[tagDecl->namespaceID]; |
| DFNameHashTableAdd(defaultTagsByNameURI, |
| tagDecl->localName, |
| nsDecl->namespaceURI, |
| tag, |
| tagDecl->namespaceID); |
| } |
| } |
| |
| static DFNameMap *builtinMap = NULL; |
| |
| static void initBuiltinMap(void) |
| { |
| builtinMap = DFNameMapNew(); |
| } |
| |
| static DFNameMap *BuiltinMapGet(void) |
| { |
| static DFOnce once = DF_ONCE_INIT; |
| DFInitOnce(&once,initBuiltinMap); |
| return builtinMap; |
| } |
| |
| const TagDecl *DFBuiltinMapNameForTag(Tag tag) |
| { |
| return DFNameMapNameForTag(BuiltinMapGet(),tag); |
| } |
| |
| Tag DFBuiltinMapTagForName(const char *URI, const char *localName) |
| { |
| return DFNameMapTagForName(BuiltinMapGet(),URI,localName); |
| } |