2013-06-06 16:03:00 -04:00
|
|
|
/*
|
|
|
|
* mod_rayo for FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
2014-05-08 11:10:42 -04:00
|
|
|
* Copyright (C) 2013-2014, Grasshopper
|
2013-06-06 16:03:00 -04:00
|
|
|
*
|
|
|
|
* Version: MPL 1.1
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
|
|
* 1.1 (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.mozilla.org/MPL/
|
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
* License.
|
|
|
|
*
|
|
|
|
* The Original Code is mod_rayo for FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is Grasshopper
|
|
|
|
* Portions created by the Initial Developer are Copyright (C)
|
|
|
|
* the Initial Developer. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s):
|
|
|
|
* Chris Rienzo <chris.rienzo@grasshopper.com>
|
|
|
|
*
|
|
|
|
* nlsml.c -- Parses / creates NLSML results
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
#include <switch.h>
|
|
|
|
#include <iksemel.h>
|
|
|
|
|
|
|
|
#include "nlsml.h"
|
|
|
|
|
|
|
|
struct nlsml_parser;
|
|
|
|
|
|
|
|
/** function to handle tag attributes */
|
|
|
|
typedef int (* tag_attribs_fn)(struct nlsml_parser *, char **);
|
|
|
|
/** function to handle tag CDATA */
|
|
|
|
typedef int (* tag_cdata_fn)(struct nlsml_parser *, char *, size_t);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Tag definition
|
|
|
|
*/
|
|
|
|
struct tag_def {
|
|
|
|
tag_attribs_fn attribs_fn;
|
|
|
|
tag_cdata_fn cdata_fn;
|
|
|
|
switch_bool_t is_root;
|
|
|
|
switch_hash_t *children_tags;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* library configuration
|
|
|
|
*/
|
2014-04-14 12:01:31 -04:00
|
|
|
typedef struct {
|
2013-06-06 16:03:00 -04:00
|
|
|
/** true if initialized */
|
|
|
|
switch_bool_t init;
|
|
|
|
/** Mapping of tag name to definition */
|
|
|
|
switch_hash_t *tag_defs;
|
|
|
|
/** library memory pool */
|
|
|
|
switch_memory_pool_t *pool;
|
2014-04-14 12:01:31 -04:00
|
|
|
} nlsml_globals;
|
|
|
|
static nlsml_globals globals = { 0 };
|
2013-06-06 16:03:00 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* The node in the XML tree
|
|
|
|
*/
|
|
|
|
struct nlsml_node {
|
|
|
|
/** tag name */
|
|
|
|
const char *name;
|
|
|
|
/** tag definition */
|
|
|
|
struct tag_def *tag_def;
|
|
|
|
/** parent to this node */
|
|
|
|
struct nlsml_node *parent;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The SAX parser state
|
|
|
|
*/
|
|
|
|
struct nlsml_parser {
|
|
|
|
/** current node */
|
|
|
|
struct nlsml_node *cur;
|
|
|
|
/** optional UUID for logging */
|
|
|
|
const char *uuid;
|
|
|
|
/** true if a match exists */
|
|
|
|
int match;
|
|
|
|
/** true if noinput */
|
|
|
|
int noinput;
|
|
|
|
/** true if nomatch */
|
|
|
|
int nomatch;
|
|
|
|
};
|
|
|
|
|
2014-04-14 12:01:31 -04:00
|
|
|
/**
|
|
|
|
* Tag def destructor
|
|
|
|
*/
|
|
|
|
static void destroy_tag_def(void *ptr)
|
|
|
|
{
|
|
|
|
struct tag_def *tag = (struct tag_def *) ptr;
|
|
|
|
if (tag->children_tags) {
|
|
|
|
switch_core_hash_destroy(&tag->children_tags);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-06 16:03:00 -04:00
|
|
|
/**
|
|
|
|
* Add a definition for a tag
|
|
|
|
* @param tag the name
|
|
|
|
* @param attribs_fn the function to handle the tag attributes
|
|
|
|
* @param cdata_fn the function to handler the tag CDATA
|
|
|
|
* @param children_tags comma-separated list of valid child tag names
|
|
|
|
* @return the definition
|
|
|
|
*/
|
|
|
|
static struct tag_def *add_tag_def(const char *tag, tag_attribs_fn attribs_fn, tag_cdata_fn cdata_fn, const char *children_tags)
|
|
|
|
{
|
|
|
|
struct tag_def *def = switch_core_alloc(globals.pool, sizeof(*def));
|
2014-03-09 00:37:09 +05:00
|
|
|
switch_core_hash_init(&def->children_tags);
|
2013-06-06 16:03:00 -04:00
|
|
|
if (!zstr(children_tags)) {
|
|
|
|
char *children_tags_dup = switch_core_strdup(globals.pool, children_tags);
|
|
|
|
char *tags[32] = { 0 };
|
|
|
|
int tag_count = switch_separate_string(children_tags_dup, ',', tags, sizeof(tags) / sizeof(tags[0]));
|
|
|
|
if (tag_count) {
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < tag_count; i++) {
|
|
|
|
switch_core_hash_insert(def->children_tags, tags[i], tags[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
def->attribs_fn = attribs_fn;
|
|
|
|
def->cdata_fn = cdata_fn;
|
|
|
|
def->is_root = SWITCH_FALSE;
|
2014-04-14 12:01:31 -04:00
|
|
|
switch_core_hash_insert_destructor(globals.tag_defs, tag, def, destroy_tag_def);
|
2013-06-06 16:03:00 -04:00
|
|
|
return def;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Add a definition for a root tag
|
|
|
|
* @param tag the name
|
|
|
|
* @param attribs_fn the function to handle the tag attributes
|
|
|
|
* @param cdata_fn the function to handler the tag CDATA
|
|
|
|
* @param children_tags comma-separated list of valid child tag names
|
|
|
|
* @return the definition
|
|
|
|
*/
|
|
|
|
static struct tag_def *add_root_tag_def(const char *tag, tag_attribs_fn attribs_fn, tag_cdata_fn cdata_fn, const char *children_tags)
|
|
|
|
{
|
|
|
|
struct tag_def *def = add_tag_def(tag, attribs_fn, cdata_fn, children_tags);
|
|
|
|
def->is_root = SWITCH_TRUE;
|
|
|
|
return def;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handle tag attributes
|
|
|
|
* @param parser the parser
|
|
|
|
* @param name the tag name
|
|
|
|
* @param atts the attributes
|
|
|
|
* @return IKS_OK if OK IKS_BADXML on parse failure
|
|
|
|
*/
|
|
|
|
static int process_tag(struct nlsml_parser *parser, const char *name, char **atts)
|
|
|
|
{
|
|
|
|
struct nlsml_node *cur = parser->cur;
|
|
|
|
if (cur->tag_def->is_root && cur->parent == NULL) {
|
|
|
|
/* no parent for ROOT tags */
|
|
|
|
return cur->tag_def->attribs_fn(parser, atts);
|
|
|
|
} else if (!cur->tag_def->is_root && cur->parent) {
|
|
|
|
/* check if this child is allowed by parent node */
|
|
|
|
struct tag_def *parent_def = cur->parent->tag_def;
|
|
|
|
if (switch_core_hash_find(parent_def->children_tags, "ANY") ||
|
|
|
|
switch_core_hash_find(parent_def->children_tags, name)) {
|
|
|
|
return cur->tag_def->attribs_fn(parser, atts);
|
|
|
|
} else {
|
|
|
|
switch_log_printf(SWITCH_CHANNEL_UUID_LOG(parser->uuid), SWITCH_LOG_INFO, "<%s> cannot be a child of <%s>\n", name, cur->parent->name);
|
|
|
|
}
|
|
|
|
} else if (cur->tag_def->is_root && cur->parent != NULL) {
|
|
|
|
switch_log_printf(SWITCH_CHANNEL_UUID_LOG(parser->uuid), SWITCH_LOG_INFO, "<%s> must be the root element\n", name);
|
|
|
|
} else {
|
|
|
|
switch_log_printf(SWITCH_CHANNEL_UUID_LOG(parser->uuid), SWITCH_LOG_INFO, "<%s> cannot be a root element\n", name);
|
|
|
|
}
|
|
|
|
return IKS_BADXML;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handle tag attributes that are ignored
|
|
|
|
* @param parser the parser
|
|
|
|
* @param atts the attributes
|
|
|
|
* @return IKS_OK
|
|
|
|
*/
|
|
|
|
static int process_attribs_ignore(struct nlsml_parser *parser, char **atts)
|
|
|
|
{
|
|
|
|
return IKS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handle CDATA that is ignored
|
|
|
|
* @param parser the parser
|
|
|
|
* @param data the CDATA
|
|
|
|
* @param len the CDATA length
|
|
|
|
* @return IKS_OK
|
|
|
|
*/
|
|
|
|
static int process_cdata_ignore(struct nlsml_parser *parser, char *data, size_t len)
|
|
|
|
{
|
|
|
|
return IKS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handle CDATA that is not allowed
|
|
|
|
* @param parser the parser
|
|
|
|
* @param data the CDATA
|
|
|
|
* @param len the CDATA length
|
|
|
|
* @return IKS_BADXML if any printable characters
|
|
|
|
*/
|
|
|
|
static int process_cdata_bad(struct nlsml_parser *parser, char *data, size_t len)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < len; i++) {
|
|
|
|
if (isgraph(data[i])) {
|
|
|
|
switch_log_printf(SWITCH_CHANNEL_UUID_LOG(parser->uuid), SWITCH_LOG_INFO, "Unexpected CDATA for <%s>\n", parser->cur->name);
|
|
|
|
return IKS_BADXML;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return IKS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handle CDATA with match text
|
|
|
|
* @param parser the parser
|
|
|
|
* @param data the CDATA
|
|
|
|
* @param len the CDATA length
|
|
|
|
* @return IKS_OK
|
|
|
|
*/
|
|
|
|
static int process_cdata_match(struct nlsml_parser *parser, char *data, size_t len)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < len; i++) {
|
|
|
|
if (isgraph(data[i])) {
|
|
|
|
parser->match++;
|
|
|
|
return IKS_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return IKS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handle nomatch
|
|
|
|
* @param parser the parser
|
|
|
|
* @param atts the attributes
|
|
|
|
* @return IKS_OK
|
|
|
|
*/
|
|
|
|
static int process_nomatch(struct nlsml_parser *parser, char **atts)
|
|
|
|
{
|
|
|
|
parser->nomatch++;
|
|
|
|
return IKS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handle noinput
|
|
|
|
* @param parser the parser
|
|
|
|
* @param atts the attributes
|
|
|
|
* @return IKS_OK
|
|
|
|
*/
|
|
|
|
static int process_noinput(struct nlsml_parser *parser, char **atts)
|
|
|
|
{
|
|
|
|
parser->noinput++;
|
|
|
|
return IKS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Process a tag
|
|
|
|
*/
|
|
|
|
static int tag_hook(void *user_data, char *name, char **atts, int type)
|
|
|
|
{
|
|
|
|
int result = IKS_OK;
|
|
|
|
struct nlsml_parser *parser = (struct nlsml_parser *)user_data;
|
|
|
|
|
|
|
|
if (type == IKS_OPEN || type == IKS_SINGLE) {
|
|
|
|
struct nlsml_node *child_node = malloc(sizeof(*child_node));
|
|
|
|
child_node->name = name;
|
|
|
|
child_node->tag_def = switch_core_hash_find(globals.tag_defs, name);
|
|
|
|
if (!child_node->tag_def) {
|
|
|
|
child_node->tag_def = switch_core_hash_find(globals.tag_defs, "ANY");
|
|
|
|
}
|
|
|
|
child_node->parent = parser->cur;
|
|
|
|
parser->cur = child_node;
|
|
|
|
switch_log_printf(SWITCH_CHANNEL_UUID_LOG(parser->uuid), SWITCH_LOG_DEBUG1, "<%s>\n", name);
|
|
|
|
result = process_tag(parser, name, atts);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (type == IKS_CLOSE || type == IKS_SINGLE) {
|
|
|
|
struct nlsml_node *node = parser->cur;
|
|
|
|
parser->cur = node->parent;
|
|
|
|
free(node);
|
|
|
|
switch_log_printf(SWITCH_CHANNEL_UUID_LOG(parser->uuid), SWITCH_LOG_DEBUG1, "</%s>\n", name);
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Process cdata
|
|
|
|
* @param user_data the parser
|
|
|
|
* @param data the CDATA
|
|
|
|
* @param len the CDATA length
|
|
|
|
* @return IKS_OK
|
|
|
|
*/
|
|
|
|
static int cdata_hook(void *user_data, char *data, size_t len)
|
|
|
|
{
|
|
|
|
struct nlsml_parser *parser = (struct nlsml_parser *)user_data;
|
|
|
|
if (!parser) {
|
|
|
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Missing parser\n");
|
|
|
|
return IKS_BADXML;
|
|
|
|
}
|
|
|
|
if (parser->cur) {
|
|
|
|
struct tag_def *def = parser->cur->tag_def;
|
|
|
|
if (def) {
|
|
|
|
return def->cdata_fn(parser, data, len);
|
|
|
|
}
|
|
|
|
switch_log_printf(SWITCH_CHANNEL_UUID_LOG(parser->uuid), SWITCH_LOG_INFO, "Missing definition for <%s>\n", parser->cur->name);
|
|
|
|
return IKS_BADXML;
|
|
|
|
}
|
|
|
|
return IKS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Parse the result, looking for noinput/nomatch/match
|
2014-05-08 11:10:42 -04:00
|
|
|
* @param nlsml_result the NLSML result to parse
|
2013-06-06 16:03:00 -04:00
|
|
|
* @param uuid optional UUID for logging
|
|
|
|
* @return true if successful
|
|
|
|
*/
|
2014-05-08 11:10:42 -04:00
|
|
|
enum nlsml_match_type nlsml_parse(const char *nlsml_result, const char *uuid)
|
2013-06-06 16:03:00 -04:00
|
|
|
{
|
|
|
|
struct nlsml_parser parser = { 0 };
|
2014-05-07 00:37:32 -07:00
|
|
|
int result = NMT_BAD_XML;
|
|
|
|
iksparser *p = NULL;
|
2013-06-06 16:03:00 -04:00
|
|
|
parser.uuid = uuid;
|
2014-05-07 00:37:32 -07:00
|
|
|
|
2014-05-08 11:10:42 -04:00
|
|
|
if (!zstr(nlsml_result)) {
|
2014-05-07 00:37:32 -07:00
|
|
|
p = iks_sax_new(&parser, tag_hook, cdata_hook);
|
2014-05-08 11:10:42 -04:00
|
|
|
if (iks_parse(p, nlsml_result, 0, 1) == IKS_OK) {
|
2013-06-06 16:03:00 -04:00
|
|
|
/* check result */
|
|
|
|
if (parser.match) {
|
2014-05-07 00:37:32 -07:00
|
|
|
result = NMT_MATCH;
|
|
|
|
goto end;
|
2013-06-06 16:03:00 -04:00
|
|
|
}
|
|
|
|
if (parser.nomatch) {
|
2014-05-07 00:37:32 -07:00
|
|
|
result = NMT_NOMATCH;
|
|
|
|
goto end;
|
2013-06-06 16:03:00 -04:00
|
|
|
}
|
|
|
|
if (parser.noinput) {
|
2014-05-07 00:37:32 -07:00
|
|
|
result = NMT_NOINPUT;
|
|
|
|
goto end;
|
2013-06-06 16:03:00 -04:00
|
|
|
}
|
|
|
|
switch_log_printf(SWITCH_CHANNEL_UUID_LOG(parser.uuid), SWITCH_LOG_INFO, "NLSML result does not have match/noinput/nomatch!\n");
|
|
|
|
} else {
|
|
|
|
switch_log_printf(SWITCH_CHANNEL_UUID_LOG(parser.uuid), SWITCH_LOG_INFO, "Failed to parse NLSML!\n");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
switch_log_printf(SWITCH_CHANNEL_UUID_LOG(parser.uuid), SWITCH_LOG_INFO, "Missing NLSML result\n");
|
|
|
|
}
|
2014-05-07 00:37:32 -07:00
|
|
|
end:
|
2014-05-08 11:10:42 -04:00
|
|
|
|
|
|
|
if ( p ) {
|
2014-05-07 00:37:32 -07:00
|
|
|
iks_parser_delete(p);
|
2014-05-08 11:10:42 -04:00
|
|
|
}
|
2014-05-07 00:37:32 -07:00
|
|
|
return result;
|
2013-06-06 16:03:00 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
#define NLSML_NS "http://www.ietf.org/xml/ns/mrcpv2"
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Makes NLSML result to conform to mrcpv2
|
|
|
|
* @param result the potentially non-conforming result
|
|
|
|
* @return the conforming result
|
|
|
|
*/
|
|
|
|
iks *nlsml_normalize(const char *result)
|
|
|
|
{
|
|
|
|
iks *result_xml = NULL;
|
|
|
|
iksparser *p = iks_dom_new(&result_xml);
|
|
|
|
if (iks_parse(p, result, 0, 1) == IKS_OK && result_xml) {
|
|
|
|
/* for now, all that is needed is to set the proper namespace */
|
|
|
|
iks_insert_attrib(result_xml, "xmlns", NLSML_NS);
|
|
|
|
} else {
|
|
|
|
/* unexpected ... */
|
|
|
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Failed to normalize NLSML result: %s\n", result);
|
|
|
|
if (result_xml) {
|
|
|
|
iks_delete(result_xml);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
iks_parser_delete(p);
|
|
|
|
return result_xml;
|
|
|
|
}
|
|
|
|
|
2013-06-28 11:16:06 -04:00
|
|
|
/**
|
|
|
|
* @return true if digit is a DTMF
|
|
|
|
*/
|
|
|
|
static int isdtmf(const char digit)
|
|
|
|
{
|
|
|
|
switch(digit) {
|
|
|
|
case '0':
|
|
|
|
case '1':
|
|
|
|
case '2':
|
|
|
|
case '3':
|
|
|
|
case '4':
|
|
|
|
case '5':
|
|
|
|
case '6':
|
|
|
|
case '7':
|
|
|
|
case '8':
|
|
|
|
case '9':
|
|
|
|
case '*':
|
|
|
|
case '#':
|
|
|
|
case 'a':
|
|
|
|
case 'A':
|
|
|
|
case 'b':
|
|
|
|
case 'B':
|
|
|
|
case 'c':
|
|
|
|
case 'C':
|
|
|
|
case 'd':
|
|
|
|
case 'D':
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-06-06 16:03:00 -04:00
|
|
|
/**
|
|
|
|
* Construct an NLSML result for digit match
|
|
|
|
* @param digits the matching digits
|
2013-08-30 17:43:10 -04:00
|
|
|
* @param interpretation the optional digit interpretation
|
2013-06-06 16:03:00 -04:00
|
|
|
* @return the NLSML <result>
|
|
|
|
*/
|
2013-08-30 17:43:10 -04:00
|
|
|
iks *nlsml_create_dtmf_match(const char *digits, const char *interpretation)
|
2013-06-06 16:03:00 -04:00
|
|
|
{
|
|
|
|
iks *result = iks_new("result");
|
|
|
|
iks_insert_attrib(result, "xmlns", NLSML_NS);
|
|
|
|
iks_insert_attrib(result, "xmlns:xf", "http://www.w3.org/2000/xforms");
|
|
|
|
if (!zstr(digits)) {
|
|
|
|
int first = 1;
|
|
|
|
int i;
|
|
|
|
int num_digits = strlen(digits);
|
|
|
|
switch_stream_handle_t stream = { 0 };
|
|
|
|
|
2013-08-30 17:43:10 -04:00
|
|
|
iks *interpretation_node = iks_insert(result, "interpretation");
|
|
|
|
iks *input_node = iks_insert(interpretation_node, "input");
|
|
|
|
iks *instance_node = iks_insert(interpretation_node, "instance");
|
|
|
|
iks_insert_attrib(input_node, "mode", "dtmf");
|
|
|
|
iks_insert_attrib(input_node, "confidence", "100");
|
2013-06-06 16:03:00 -04:00
|
|
|
|
|
|
|
SWITCH_STANDARD_STREAM(stream);
|
|
|
|
for (i = 0; i < num_digits; i++) {
|
2013-06-28 11:16:06 -04:00
|
|
|
if (isdtmf(digits[i])) {
|
2013-06-06 16:03:00 -04:00
|
|
|
if (first) {
|
|
|
|
stream.write_function(&stream, "%c", digits[i]);
|
|
|
|
first = 0;
|
|
|
|
} else {
|
|
|
|
stream.write_function(&stream, " %c", digits[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-08-30 17:43:10 -04:00
|
|
|
iks_insert_cdata(input_node, stream.data, strlen(stream.data));
|
|
|
|
|
|
|
|
if (zstr(interpretation)) {
|
|
|
|
iks_insert_cdata(instance_node, stream.data, strlen(stream.data));
|
|
|
|
} else {
|
|
|
|
iks_insert_cdata(instance_node, interpretation, strlen(interpretation));
|
|
|
|
}
|
2013-06-06 16:03:00 -04:00
|
|
|
switch_safe_free(stream.data);
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Initialize NLSML parser. This function is not thread safe.
|
|
|
|
*/
|
|
|
|
int nlsml_init(void)
|
|
|
|
{
|
|
|
|
if (globals.init) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
globals.init = SWITCH_TRUE;
|
|
|
|
switch_core_new_memory_pool(&globals.pool);
|
2014-03-09 00:37:09 +05:00
|
|
|
switch_core_hash_init(&globals.tag_defs);
|
2013-06-06 16:03:00 -04:00
|
|
|
|
|
|
|
add_root_tag_def("result", process_attribs_ignore, process_cdata_ignore, "interpretation");
|
|
|
|
add_tag_def("interpretation", process_attribs_ignore, process_cdata_ignore, "input,model,xf:model,instance,xf:instance");
|
|
|
|
add_tag_def("input", process_attribs_ignore, process_cdata_match, "input,nomatch,noinput");
|
|
|
|
add_tag_def("noinput", process_noinput, process_cdata_bad, "");
|
|
|
|
add_tag_def("nomatch", process_nomatch, process_cdata_ignore, "");
|
|
|
|
add_tag_def("model", process_attribs_ignore, process_cdata_ignore, "ANY");
|
|
|
|
add_tag_def("xf:model", process_attribs_ignore, process_cdata_ignore, "ANY");
|
|
|
|
add_tag_def("instance", process_attribs_ignore, process_cdata_ignore, "ANY");
|
|
|
|
add_tag_def("xf:instance", process_attribs_ignore, process_cdata_ignore, "ANY");
|
|
|
|
add_tag_def("ANY", process_attribs_ignore, process_cdata_ignore, "ANY");
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2014-04-14 12:01:31 -04:00
|
|
|
/**
|
|
|
|
* Destruction of NLSML parser environment
|
|
|
|
*/
|
|
|
|
void nlsml_destroy(void)
|
|
|
|
{
|
|
|
|
if (globals.init) {
|
|
|
|
if (globals.tag_defs) {
|
|
|
|
switch_core_hash_destroy(&globals.tag_defs);
|
|
|
|
globals.tag_defs = NULL;
|
|
|
|
}
|
|
|
|
if (globals.pool) {
|
|
|
|
switch_core_destroy_memory_pool(&globals.pool);
|
|
|
|
globals.pool = NULL;
|
|
|
|
}
|
|
|
|
globals.init = SWITCH_FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-06 16:03:00 -04:00
|
|
|
/* For Emacs:
|
|
|
|
* Local Variables:
|
|
|
|
* mode:c
|
|
|
|
* indent-tabs-mode:t
|
|
|
|
* tab-width:4
|
|
|
|
* c-basic-offset:4
|
|
|
|
* End:
|
|
|
|
* For VIM:
|
2013-06-25 11:50:17 -05:00
|
|
|
* vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet
|
2013-06-06 16:03:00 -04:00
|
|
|
*/
|