blob: eb5d868bfd66a195b0009505f20ad62955656fa4 [file] [log] [blame]
// 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);
}