Blame apache2/acmp.c

Packit Service 384592
/*
Packit Service 384592
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
Packit Service 384592
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
Packit Service 384592
*
Packit Service 384592
* You may not use this file except in compliance with
Packit Service 384592
* the License.  You may obtain a copy of the License at
Packit Service 384592
*
Packit Service 384592
*     http://www.apache.org/licenses/LICENSE-2.0
Packit Service 384592
*
Packit Service 384592
* If any of the files related to licensing are missing or if you have any
Packit Service 384592
* other questions related to licensing please contact Trustwave Holdings, Inc.
Packit Service 384592
* directly using the email address security@modsecurity.org.
Packit Service 384592
*/
Packit Service 384592
Packit Service 384592
/* Aho-Corasick Matching  */
Packit Service 384592
Packit Service 384592
#include "acmp.h"
Packit Service 384592
Packit Service 384592
#ifdef ACMP_USE_UTF8
Packit Service 384592
/* UTF support */
Packit Service 384592
#include "utf8tables.h"
Packit Service 384592
#else
Packit Service 384592
/* No UTF support */
Packit Service 384592
#define acmp_utf8_char_t long
Packit Service 384592
#include <apr_lib.h>
Packit Service 384592
#define utf8_lcase(a) apr_tolower(a)
Packit Service 384592
#endif
Packit Service 384592
Packit Service 384592
#include <apr_tables.h>
Packit Service 384592
#include <stdio.h>
Packit Service 384592
#include <string.h>
Packit Service 384592
Packit Service 384592
Packit Service 384592
/*
Packit Service 384592
 *******************************************************************************
Packit Service 384592
 *******************************************************************************
Packit Service 384592
 * Data structures for acmp parser
Packit Service 384592
 */
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * One node in trie
Packit Service 384592
 */
Packit Service 384592
typedef struct acmp_node_t acmp_node_t;
Packit Service 384592
typedef struct acmp_btree_node_t acmp_btree_node_t;
Packit Service 384592
struct acmp_node_t {
Packit Service 384592
    acmp_utf8_char_t letter;
Packit Service 384592
    int  is_last;
Packit Service 384592
    acmp_callback_t callback;
Packit Service 384592
    void *callback_data;
Packit Service 384592
    int depth;
Packit Service 384592
Packit Service 384592
    acmp_node_t *child;
Packit Service 384592
    acmp_node_t *sibling;
Packit Service 384592
    acmp_node_t *fail;
Packit Service 384592
    acmp_node_t *parent;
Packit Service 384592
    acmp_node_t *o_match;
Packit Service 384592
Packit Service 384592
    acmp_btree_node_t *btree;
Packit Service 384592
Packit Service 384592
    apr_size_t hit_count;
Packit Service 384592
Packit Service 384592
    char *text;
Packit Service 384592
    char *pattern;
Packit Service 384592
};
Packit Service 384592
Packit Service 384592
struct acmp_btree_node_t {
Packit Service 384592
    acmp_utf8_char_t letter;
Packit Service 384592
    acmp_btree_node_t *left;
Packit Service 384592
    acmp_btree_node_t *right;
Packit Service 384592
    acmp_node_t *node;
Packit Service 384592
};
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Data related to parser, not to individual nodes
Packit Service 384592
 */
Packit Service 384592
struct ACMP {
Packit Service 384592
#ifdef ACMP_USE_UTF8
Packit Service 384592
    int is_utf8;
Packit Service 384592
#endif
Packit Service 384592
    int is_case_sensitive;
Packit Service 384592
    apr_pool_t *parent_pool;
Packit Service 384592
    apr_pool_t *pool;
Packit Service 384592
Packit Service 384592
    int dict_count;
Packit Service 384592
    apr_size_t longest_entry;
Packit Service 384592
Packit Service 384592
    acmp_node_t *root_node;
Packit Service 384592
Packit Service 384592
    const char *data_start;
Packit Service 384592
    const char *data_end;
Packit Service 384592
    const char *data_pos;
Packit Service 384592
    apr_size_t data_len;
Packit Service 384592
Packit Service 384592
    apr_size_t *bp_buffer;
Packit Service 384592
    apr_size_t bp_buff_len;
Packit Service 384592
Packit Service 384592
    acmp_node_t *active_node;
Packit Service 384592
    char u8_buff[6];
Packit Service 384592
    apr_size_t  u8buff_len;
Packit Service 384592
    apr_size_t  hit_count;
Packit Service 384592
    int  is_failtree_done;
Packit Service 384592
    int  is_active;
Packit Service 384592
    apr_size_t  byte_pos;
Packit Service 384592
    apr_size_t  char_pos;
Packit Service 384592
};
Packit Service 384592
Packit Service 384592
/*
Packit Service 384592
 *******************************************************************************
Packit Service 384592
 *******************************************************************************
Packit Service 384592
 * Functions for UTF-8 support
Packit Service 384592
 */
Packit Service 384592
Packit Service 384592
#ifdef ACMP_USE_UTF8
Packit Service 384592
/**
Packit Service 384592
 * Returns length of utf-8 sequence based on its first byte
Packit Service 384592
 */
Packit Service 384592
static int utf8_seq_len(const char *first_byte) {
Packit Service 384592
    return utf8_seq_lengths[(unsigned int)(unsigned char)first_byte[0]];
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Returns length of utf8-encoded text
Packit Service 384592
 */
Packit Service 384592
static size_t utf8_strlen(const char *str) {
Packit Service 384592
    int len = 0;
Packit Service 384592
    const char *c = str;
Packit Service 384592
    while (*c != 0) {
Packit Service 384592
        c += utf8_seq_len(c);
Packit Service 384592
        len++;
Packit Service 384592
    }
Packit Service 384592
    return len;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Returns ucs code for given utf-8 sequence
Packit Service 384592
 */
Packit Service 384592
static acmp_utf8_char_t utf8_decodechar(const char *str) {
Packit Service 384592
    int len = utf8_seq_len(str);
Packit Service 384592
    acmp_utf8_char_t ch = 0;
Packit Service 384592
    switch (len) {
Packit Service 384592
        case 6: ch += (unsigned char)*str++; ch <<= 6;
Packit Service 384592
        case 5: ch += (unsigned char)*str++; ch <<= 6;
Packit Service 384592
        case 4: ch += (unsigned char)*str++; ch <<= 6;
Packit Service 384592
        case 3: ch += (unsigned char)*str++; ch <<= 6;
Packit Service 384592
        case 2: ch += (unsigned char)*str++; ch <<= 6;
Packit Service 384592
        case 1: ch += (unsigned char)*str++;
Packit Service 384592
    }
Packit Service 384592
    ch -= utf8_offsets[len - 1];
Packit Service 384592
    return ch;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Returns lowercase for given unicode character. Searches through
Packit Service 384592
 *   utf8_lcase_map table, if it doesn't find the code assumes
Packit Service 384592
 *   it doesn't have a lowercase variant and returns code itself.
Packit Service 384592
 */
Packit Service 384592
static long utf8_lcase(acmp_utf8_char_t ucs_code) {
Packit Service 384592
    long mid, left, right;
Packit Service 384592
    left = 1;
Packit Service 384592
    right = UTF8_LCASEMAP_LEN * 2 + 1;
Packit Service 384592
Packit Service 384592
    while (left <= right) {
Packit Service 384592
        mid = (left + right) >> 1;
Packit Service 384592
        mid -= (mid % 2); mid++;
Packit Service 384592
        if (ucs_code > utf8_lcase_map[mid])
Packit Service 384592
            left = mid + 2;
Packit Service 384592
        else if (ucs_code < utf8_lcase_map[mid])
Packit Service 384592
            right = mid - 2;
Packit Service 384592
        else if (ucs_code == utf8_lcase_map[mid])
Packit Service 384592
            return utf8_lcase_map[mid - 1];
Packit Service 384592
    }
Packit Service 384592
    return ucs_code;
Packit Service 384592
}
Packit Service 384592
#endif
Packit Service 384592
Packit Service 384592
/*
Packit Service 384592
 *******************************************************************************
Packit Service 384592
 *******************************************************************************
Packit Service 384592
 * Code for local / static utility functions
Packit Service 384592
 */
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Returns length of given string for parser's encoding
Packit Service 384592
 */
Packit Service 384592
static size_t acmp_strlen(ACMP *parser, const char *str) {
Packit Service 384592
#ifdef ACMP_USE_UTF8
Packit Service 384592
    return (parser->is_utf8 == 0) ? strlen(str) : utf8_strlen(str);
Packit Service 384592
#else
Packit Service 384592
    return strlen(str);
Packit Service 384592
#endif
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Turns string to array of ucs values, depending on parser's encoding
Packit Service 384592
 *       str - string to convert, doesn't have to be NULL-terminated
Packit Service 384592
 * ucs_chars - where to write ucs values
Packit Service 384592
 *       len - length of input string
Packit Service 384592
 */
Packit Service 384592
static void acmp_strtoucs(ACMP *parser, const char *str, acmp_utf8_char_t *ucs_chars, int len) {
Packit Service 384592
    int i;
Packit Service 384592
    const char *c = str;
Packit Service 384592
Packit Service 384592
#ifdef ACMP_USE_UTF8
Packit Service 384592
    if (parser->is_utf8) {
Packit Service 384592
        for (i = 0; i < len; i++) {
Packit Service 384592
            *(ucs_chars++) = utf8_decodechar(c);
Packit Service 384592
            c += utf8_seq_len(c);
Packit Service 384592
        }
Packit Service 384592
    } else
Packit Service 384592
#endif
Packit Service 384592
    {
Packit Service 384592
        for (i = 0; i < len; i++) {
Packit Service 384592
            *(ucs_chars++) = *(c++);
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Returns node with given letter, or null if not found
Packit Service 384592
 */
Packit Service 384592
static acmp_node_t *acmp_child_for_code(acmp_node_t *parent_node, acmp_utf8_char_t ucs_code) {
Packit Service 384592
    acmp_node_t *node = parent_node->child;
Packit Service 384592
    if (node == NULL) return NULL;
Packit Service 384592
    for (;;) {
Packit Service 384592
        if (node->letter == ucs_code) return node;
Packit Service 384592
        node = node->sibling;
Packit Service 384592
        if (node == NULL) return NULL;
Packit Service 384592
    }
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Adds node to parent node, if it is not already there
Packit Service 384592
 */
Packit Service 384592
static void acmp_add_node_to_parent(acmp_node_t *parent, acmp_node_t *child) {
Packit Service 384592
    acmp_node_t *node = NULL;
Packit Service 384592
Packit Service 384592
    child->parent = parent;
Packit Service 384592
    if (parent->child == NULL) {
Packit Service 384592
        parent->child = child;
Packit Service 384592
        return;
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    node = parent->child;
Packit Service 384592
    for (;;) {
Packit Service 384592
        if (node == child) return;
Packit Service 384592
        if (node->sibling == NULL) {
Packit Service 384592
            node->sibling = child;
Packit Service 384592
            return;
Packit Service 384592
        }
Packit Service 384592
        node = node->sibling;
Packit Service 384592
    }
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Copies values from one node to another, without child/sibling/fail pointers
Packit Service 384592
 * and without state variables.
Packit Service 384592
 */
Packit Service 384592
static void acmp_clone_node_no_state(acmp_node_t *from, acmp_node_t *to) {
Packit Service 384592
    memcpy(to, from, sizeof(acmp_node_t));
Packit Service 384592
    to->child = NULL;
Packit Service 384592
    to->sibling = NULL;
Packit Service 384592
    to->fail = NULL;
Packit Service 384592
    to->hit_count = 0;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
static inline acmp_node_t *acmp_btree_find(acmp_node_t *node, acmp_utf8_char_t letter) {
Packit Service 384592
    acmp_btree_node_t *bnode = node->btree;
Packit Service 384592
    for (;;) {
Packit Service 384592
        if (bnode == NULL) return NULL;
Packit Service 384592
        if (bnode->letter == letter) return bnode->node;
Packit Service 384592
        if (bnode->letter > letter) {
Packit Service 384592
            bnode = bnode->left;
Packit Service 384592
        } else {
Packit Service 384592
            bnode = bnode->right;
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 *
Packit Service 384592
 */
Packit Service 384592
static inline acmp_node_t *acmp_goto(acmp_node_t *node, acmp_utf8_char_t letter) {
Packit Service 384592
    return acmp_btree_find(node, letter);
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Connects each node with its first fail node that is end of a phrase.
Packit Service 384592
 */
Packit Service 384592
static void acmp_connect_other_matches(ACMP *parser, acmp_node_t *node) {
Packit Service 384592
    acmp_node_t *child, *om;
Packit Service 384592
Packit Service 384592
    for (child = node->child; child != NULL; child = child->sibling) {
Packit Service 384592
        if (child->fail == NULL) continue;
Packit Service 384592
        for (om = child->fail; om != parser->root_node; om = om->fail) {
Packit Service 384592
            if (om->is_last) {
Packit Service 384592
                child->o_match = om;
Packit Service 384592
                break;
Packit Service 384592
            }
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    /* Go recursively through children of this node that have a child node */
Packit Service 384592
    for(child = node->child; child != NULL; child = child->sibling) {
Packit Service 384592
        if (child->child != NULL) acmp_connect_other_matches(parser, child);
Packit Service 384592
    }
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Adds leaves to binary tree, working from sorted array of keyword tree nodes
Packit Service 384592
 */
Packit Service 384592
static void acmp_add_btree_leaves(acmp_btree_node_t *node, acmp_node_t *nodes[],
Packit Service 384592
        int pos, int lb, int rb, apr_pool_t *pool) {
Packit Service 384592
Packit Service 384592
    int left = 0, right = 0;
Packit Service 384592
    if ((pos - lb) > 1) {
Packit Service 384592
        left = lb + (pos - lb) / 2;
Packit Service 384592
        node->left = apr_pcalloc(pool, sizeof(acmp_btree_node_t));
Packit Service 384592
        /* ENH: Check alloc succeded */
Packit Service 384592
        node->left->node = nodes[left];
Packit Service 384592
        node->left->letter = nodes[left]->letter;
Packit Service 384592
#ifdef DEBUG_ACMP
Packit Service 384592
        fprintf(stderr, "%lc ->left %lc\n", (wint_t)node->node->letter, (wint_t)node->left->node->letter);
Packit Service 384592
#endif
Packit Service 384592
    }
Packit Service 384592
    if ((rb - pos) > 1) {
Packit Service 384592
        right = pos + (rb - pos) / 2;
Packit Service 384592
        node->right = apr_pcalloc(pool, sizeof(acmp_btree_node_t));
Packit Service 384592
        /* ENH: Check alloc succeded */
Packit Service 384592
        node->right->node = nodes[right];
Packit Service 384592
        node->right->letter = nodes[right]->letter;
Packit Service 384592
#ifdef DEBUG_ACMP
Packit Service 384592
        fprintf(stderr, "%lc ->right %lc\n", (wint_t)node->node->letter, (wint_t)node->right->node->letter);
Packit Service 384592
#endif
Packit Service 384592
    }
Packit Service 384592
    if (node->right != NULL) {
Packit Service 384592
        acmp_add_btree_leaves(node->right, nodes, right, pos, rb, pool);
Packit Service 384592
    }
Packit Service 384592
    if (node->left != NULL) {
Packit Service 384592
        acmp_add_btree_leaves(node->left, nodes, left, lb, pos, pool);
Packit Service 384592
    }
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Builds balanced binary tree from children nodes of given node.
Packit Service 384592
 */
Packit Service 384592
static void acmp_build_binary_tree(ACMP *parser, acmp_node_t *node) {
Packit Service 384592
    apr_size_t count, i, j;
Packit Service 384592
    acmp_node_t *child = node->child;
Packit Service 384592
    acmp_node_t **nodes;
Packit Service 384592
    apr_size_t pos;
Packit Service 384592
Packit Service 384592
    /* Build an array big enough */
Packit Service 384592
    for (count = 0; child != NULL; child = child->sibling) count++;
Packit Service 384592
    nodes = apr_pcalloc(parser->pool, count * sizeof(acmp_node_t *));
Packit Service 384592
    /* ENH: Check alloc succeded */
Packit Service 384592
Packit Service 384592
    /* ENH: Combine this in the loop below - we do not need two loops */
Packit Service 384592
    child = node->child;
Packit Service 384592
    for (i = 0; i < count; i++) {
Packit Service 384592
        nodes[i] = child;
Packit Service 384592
        child = child->sibling;
Packit Service 384592
    };
Packit Service 384592
Packit Service 384592
    /* We have array with all children of the node and number of those children
Packit Service 384592
     */
Packit Service 384592
    for (i = 0; i < count - 1; i++)
Packit Service 384592
        for (j = i + 1; j < count; j++) {
Packit Service 384592
            acmp_node_t *tmp;
Packit Service 384592
Packit Service 384592
            if (nodes[i]->letter < nodes[j]->letter) continue;
Packit Service 384592
Packit Service 384592
            tmp = nodes[i];
Packit Service 384592
            nodes[i] = nodes[j];
Packit Service 384592
            nodes[j] = tmp;
Packit Service 384592
        }
Packit Service 384592
    node->btree = apr_pcalloc(parser->pool, sizeof(acmp_btree_node_t));
Packit Service 384592
    /* ENH: Check alloc succeded */
Packit Service 384592
    pos = count / 2;
Packit Service 384592
    node->btree->node = nodes[pos];
Packit Service 384592
    node->btree->letter = nodes[pos]->letter;
Packit Service 384592
    acmp_add_btree_leaves(node->btree, nodes, pos, -1, count, parser->pool);
Packit Service 384592
    for (i = 0; i < count; i++) {
Packit Service 384592
        if (nodes[i]->child != NULL) acmp_build_binary_tree(parser, nodes[i]);
Packit Service 384592
    }
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Constructs fail paths on keyword trie
Packit Service 384592
 */
Packit Service 384592
static apr_status_t acmp_connect_fail_branches(ACMP *parser) {
Packit Service 384592
    /* Already connected ? */
Packit Service 384592
    acmp_node_t *child, *node, *goto_node;
Packit Service 384592
    apr_array_header_t *arr, *arr2, *tmp;
Packit Service 384592
Packit Service 384592
    if (parser->is_failtree_done != 0) return APR_SUCCESS;
Packit Service 384592
Packit Service 384592
    parser->root_node->text = "";
Packit Service 384592
    arr  = apr_array_make(parser->pool, 32, sizeof(acmp_node_t *));
Packit Service 384592
    arr2 = apr_array_make(parser->pool, 32, sizeof(acmp_node_t *));
Packit Service 384592
Packit Service 384592
    parser->root_node->fail = parser->root_node;
Packit Service 384592
Packit Service 384592
    /* All first-level children will fail back to root node */
Packit Service 384592
    for (child = parser->root_node->child; child != NULL; child = child->sibling) {
Packit Service 384592
        child->fail = parser->root_node;
Packit Service 384592
        *(acmp_node_t **)apr_array_push(arr) = child;
Packit Service 384592
#ifdef DEBUG_ACMP
Packit Service 384592
        fprintf(stderr, "fail direction: *%s* => *%s*\n", child->text, child->fail->text);
Packit Service 384592
#endif
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    for (;;) {
Packit Service 384592
        while (apr_is_empty_array(arr) == 0) {
Packit Service 384592
            node = *(acmp_node_t **)apr_array_pop(arr);
Packit Service 384592
            node->fail = parser->root_node;
Packit Service 384592
            if (node->parent != parser->root_node) {
Packit Service 384592
                goto_node = acmp_child_for_code(node->parent->fail, node->letter);
Packit Service 384592
                node->fail = (goto_node != NULL) ? goto_node : parser->root_node;
Packit Service 384592
            }
Packit Service 384592
#ifdef DEBUG_ACMP
Packit Service 384592
            fprintf(stderr, "fail direction: *%s* => *%s*\n", node->text, node->fail->text);
Packit Service 384592
#endif
Packit Service 384592
            child = node->child;
Packit Service 384592
            while (child != NULL) {
Packit Service 384592
                *(acmp_node_t **)apr_array_push(arr2) = child;
Packit Service 384592
                child = child->sibling;
Packit Service 384592
            }
Packit Service 384592
        }
Packit Service 384592
        if (apr_is_empty_array(arr2) != 0) break;
Packit Service 384592
Packit Service 384592
        tmp = arr;
Packit Service 384592
        arr = arr2;
Packit Service 384592
        arr2 = tmp;
Packit Service 384592
    }
Packit Service 384592
    acmp_connect_other_matches(parser, parser->root_node);
Packit Service 384592
    if (parser->root_node->child != NULL) acmp_build_binary_tree(parser, parser->root_node);
Packit Service 384592
    parser->is_failtree_done = 1;
Packit Service 384592
    return APR_SUCCESS;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/*
Packit Service 384592
 *******************************************************************************
Packit Service 384592
 *******************************************************************************
Packit Service 384592
 * Code for functions from header file
Packit Service 384592
 */
Packit Service 384592
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * flags - OR-ed values of ACMP_FLAG constants
Packit Service 384592
 * pool  - apr_pool to use as parent pool, can be set to NULL
Packit Service 384592
 */
Packit Service 384592
ACMP *acmp_create(int flags, apr_pool_t *pool) {
Packit Service 384592
    apr_status_t rc;
Packit Service 384592
    apr_pool_t *p;
Packit Service 384592
    ACMP *parser;
Packit Service 384592
Packit Service 384592
    rc = apr_pool_create(&p, pool);
Packit Service 384592
    if (rc != APR_SUCCESS) return NULL;
Packit Service 384592
Packit Service 384592
    parser = apr_pcalloc(p, sizeof(ACMP));
Packit Service 384592
    /* ENH: Check alloc succeded */
Packit Service 384592
    parser->pool = p;
Packit Service 384592
    parser->parent_pool = pool;
Packit Service 384592
#ifdef ACMP_USE_UTF8
Packit Service 384592
    parser->is_utf8 = (flags & ACMP_FLAG_UTF8) == 0 ? 0 : 1;
Packit Service 384592
#endif
Packit Service 384592
    parser->is_case_sensitive = (flags & ACMP_FLAG_CASE_SENSITIVE) == 0 ? 0 : 1;
Packit Service 384592
    parser->root_node = apr_pcalloc(p, sizeof(acmp_node_t));
Packit Service 384592
    /* ENH: Check alloc succeded */
Packit Service 384592
    return parser;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Creates fail tree and initializes buffer
Packit Service 384592
 */
Packit Service 384592
apr_status_t acmp_prepare(ACMP *parser) {
Packit Service 384592
    apr_status_t st;
Packit Service 384592
Packit Service 384592
    if (parser->bp_buff_len < parser->longest_entry) {
Packit Service 384592
        parser->bp_buff_len = parser->longest_entry * 2;
Packit Service 384592
        parser->bp_buffer = apr_pcalloc(parser->pool, sizeof(apr_size_t) * parser->bp_buff_len);
Packit Service 384592
        /* ENH: Check alloc succeded */
Packit Service 384592
    }
Packit Service 384592
Packit Service 384592
    st = acmp_connect_fail_branches(parser);
Packit Service 384592
    parser->active_node = parser->root_node;
Packit Service 384592
    if (st != APR_SUCCESS) return st;
Packit Service 384592
    parser->is_active = 1;
Packit Service 384592
    return APR_SUCCESS;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Adds pattern to parser
Packit Service 384592
 * parser - ACMP parser
Packit Service 384592
 * pattern - string with pattern to match
Packit Service 384592
 * callback - Optional, pointer to an acmp_callback_t function
Packit Service 384592
 * data - pointer to data that will be passed to callback function, only used if callback
Packit Service 384592
 *   is supplied
Packit Service 384592
 * len - Length of pattern in characters, if zero string length is used.
Packit Service 384592
 */
Packit Service 384592
apr_status_t acmp_add_pattern(ACMP *parser, const char *pattern,
Packit Service 384592
        acmp_callback_t callback, void *data, apr_size_t len)
Packit Service 384592
{
Packit Service 384592
    size_t length, i, j;
Packit Service 384592
    acmp_utf8_char_t *ucs_chars;
Packit Service 384592
    acmp_node_t *parent, *child;
Packit Service 384592
Packit Service 384592
    if (parser->is_active != 0) return APR_EGENERAL;
Packit Service 384592
Packit Service 384592
    length = (len == 0) ? acmp_strlen(parser, pattern) : len;
Packit Service 384592
    ucs_chars = apr_pcalloc(parser->pool, length * sizeof(acmp_utf8_char_t));
Packit Service 384592
    /* ENH: Check alloc succeded */
Packit Service 384592
Packit Service 384592
    parent = parser->root_node;
Packit Service 384592
    acmp_strtoucs(parser, pattern, ucs_chars, length);
Packit Service 384592
Packit Service 384592
    for (i = 0; i < length; i++) {
Packit Service 384592
        acmp_utf8_char_t letter = ucs_chars[i];
Packit Service 384592
        if (parser->is_case_sensitive == 0) {
Packit Service 384592
            letter = utf8_lcase(letter);
Packit Service 384592
        }
Packit Service 384592
        child = acmp_child_for_code(parent, letter);
Packit Service 384592
        if (child == NULL) {
Packit Service 384592
            child = apr_pcalloc(parser->pool, sizeof(acmp_node_t));
Packit Service 384592
            /* ENH: Check alloc succeded */
Packit Service 384592
            child->pattern = "";
Packit Service 384592
            child->letter = letter;
Packit Service 384592
            child->depth = i;
Packit Service 384592
            child->text = apr_pcalloc(parser->pool, strlen(pattern) + 2);
Packit Service 384592
            /* ENH: Check alloc succeded */
Packit Service 384592
            for (j = 0; j <= i; j++) child->text[j] = pattern[j];
Packit Service 384592
        }
Packit Service 384592
        if (i == length - 1) {
Packit Service 384592
            if (child->is_last == 0) {
Packit Service 384592
                parser->dict_count++;
Packit Service 384592
                child->is_last = 1;
Packit Service 384592
                child->pattern = apr_pcalloc(parser->pool, strlen(pattern) + 2);
Packit Service 384592
                /* ENH: Check alloc succeded */
Packit Service 384592
                strcpy(child->pattern, pattern);
Packit Service 384592
            }
Packit Service 384592
            child->callback = callback;
Packit Service 384592
            child->callback_data = data;
Packit Service 384592
        }
Packit Service 384592
        acmp_add_node_to_parent(parent, child);
Packit Service 384592
        parent = child;
Packit Service 384592
    }
Packit Service 384592
    if (length > parser->longest_entry) parser->longest_entry = length;
Packit Service 384592
    parser->is_failtree_done = 0;
Packit Service 384592
Packit Service 384592
    return APR_SUCCESS;
Packit Service 384592
}
Packit Service 384592
Packit Service 384592
/**
Packit Service 384592
 * Process the data using ACMPT to keep state, and ACMPT's parser to keep the tree
Packit Service 384592
 */
Packit Service 384592
apr_status_t acmp_process_quick(ACMPT *acmpt, const char **match, const char *data, apr_size_t len) {
Packit Service 384592
    ACMP *parser;
Packit Service 384592
    acmp_node_t *node, *go_to;
Packit Service 384592
    const char *end;
Packit Service 384592
Packit Service 384592
    if (acmpt->parser->is_failtree_done == 0) {
Packit Service 384592
        acmp_prepare(acmpt->parser);
Packit Service 384592
    };
Packit Service 384592
Packit Service 384592
    parser = acmpt->parser;
Packit Service 384592
    if (acmpt->ptr == NULL) acmpt->ptr = parser->root_node;
Packit Service 384592
    node = acmpt->ptr;
Packit Service 384592
    end = data + len;
Packit Service 384592
Packit Service 384592
    while (data < end) {
Packit Service 384592
        acmp_utf8_char_t letter = (unsigned char)*data++;
Packit Service 384592
Packit Service 384592
        if (parser->is_case_sensitive == 0) letter = utf8_lcase(letter);
Packit Service 384592
Packit Service 384592
        go_to = NULL;
Packit Service 384592
        while (go_to == NULL) {
Packit Service 384592
            go_to = acmp_goto(node, letter);
Packit Service 384592
            if (go_to != NULL) {
Packit Service 384592
                if (go_to->is_last) {
Packit Service 384592
                    *match = go_to->text;
Packit Service 384592
                    return 1;
Packit Service 384592
                }
Packit Service 384592
            }
Packit Service 384592
            if (node == parser->root_node) break;
Packit Service 384592
            if (go_to == NULL) node = node->fail;
Packit Service 384592
        }
Packit Service 384592
        if (go_to != NULL) node = go_to;
Packit Service 384592
Packit Service 384592
        /* If node has o_match, then we found a pattern */
Packit Service 384592
        if (node->o_match != NULL) {
Packit Service 384592
            *match = node->text;
Packit Service 384592
            return 1;
Packit Service 384592
        }
Packit Service 384592
    }
Packit Service 384592
    acmpt->ptr = node;
Packit Service 384592
    return 0;
Packit Service 384592
}