Пример #1
0
/**
 * Search patterns of the ac_tree matcher in the given buffer using a
 * matching context. The matching context stores offsets used to process
 * a search over multiple data segments. The function has option flags to
 * specify to return where the first pattern is found, or after all the
 * data is consumed, using a user specified callback and/or building a
 * list of patterns matched
 *
 * @param ac_ctx pointer to the matching context
 * @param data pointer to the buffer to search in
 * @param len the length of the data
 * @param flags options to use while matching
 * @param mp memory pool to use
 *
 * @returns Status code
 */
ib_status_t ib_ac_consume(ib_ac_context_t *ac_ctx,
                          const char *data,
                          size_t len,
                          uint8_t flags,
                          ib_mpool_t *mp)
{
    const char *end;

    ib_ac_state_t *state = NULL;
    ib_ac_state_t *fgoto = NULL;

    int flag_match = 0;

    ib_ac_t *ac_tree = ac_ctx->ac_tree;
    ac_ctx->current_offset = 0;

    if ((ac_ctx->ac_tree->flags & IB_AC_FLAG_PARSER_COMPILED) == 0)
    {
        ib_ac_build_links(ac_tree);
    }

    ac_tree = ac_ctx->ac_tree;
    if (ac_ctx->current == NULL) {
        ac_ctx->current = ac_tree->root;
    }

    state = ac_ctx->current;
    end = data + len;

    while (data < end) {
        ib_ac_char_t letter = (unsigned char)*data++;
        ++ac_ctx->processed;
        ++ac_ctx->current_offset;

        if (ac_tree->flags & IB_AC_FLAG_PARSER_NOCASE) {
            letter = tolower(letter);
        }

        fgoto = NULL;
        while (fgoto == NULL) {
            fgoto = ib_ac_bintree_goto(state, letter);

            if (fgoto != NULL) {

                if (fgoto->flags & IB_AC_FLAG_STATE_OUTPUT) {
                    flag_match = 1;

                    ++fgoto->match_cnt;
                    ++ac_ctx->match_cnt;

                    ac_ctx->current = fgoto;
                    state = fgoto;

                    if (flags & IB_AC_FLAG_CONSUME_DOCALLBACK)
                    {
                        ib_ac_do_callback(ac_ctx, state);
                    }

                    if (flags & IB_AC_FLAG_CONSUME_DOLIST)
                    {
                        /* If list is not created yet, create it */
                        if (ac_ctx->match_list == NULL)
                        {
                            ib_status_t rc;
                            rc = ib_list_create(&ac_ctx->match_list, mp);
                            if (rc != IB_OK) {
                                return rc;
                            }
                        }

                        ib_ac_match_t *mt = NULL;
                        mt = (ib_ac_match_t *)ib_mpool_calloc(mp,
                                          1, sizeof(ib_ac_match_t));
                        if (mt == NULL) {
                            return IB_EALLOC;
                        }

                        mt->pattern = state->pattern;
                        mt->data = state->data;
                        mt->pattern_len = state->level + 1;
                        mt->offset = ac_ctx->processed - (fgoto->level + 1);
                        mt->relative_offset = ac_ctx->current_offset -
                                                         (fgoto->level + 1);

                        ib_list_enqueue(ac_ctx->match_list, (void *) mt);
                    }

                    if ( !(flags & IB_AC_FLAG_CONSUME_MATCHALL))
                    {
                        return IB_OK;
                    }

                    ib_ac_state_t *outs = NULL;

                    for (outs = state->outputs;
                         outs != NULL;
                         outs = outs->outputs)
                    {
                        /* This are subpatterns of the current walked branch
                         * that are present as independent patterns as well
                         * in the tree */

                        ++outs->match_cnt;
                        ++ac_ctx->match_cnt;

                        if (flags & IB_AC_FLAG_CONSUME_DOCALLBACK)
                        {
                            ib_ac_do_callback(ac_ctx, outs);
                        }

                        if (flags & IB_AC_FLAG_CONSUME_DOLIST)
                        {
                            /* If list is not created yet, create it */
                            if (ac_ctx->match_list == NULL)
                            {
                                ib_status_t rc;
                                rc = ib_list_create(&ac_ctx->match_list, mp);
                                if (rc != IB_OK) {
                                    return rc;
                                }
                            }

                            ib_ac_match_t *mt = NULL;
                            mt = (ib_ac_match_t *)ib_mpool_calloc(mp,
                                              1, sizeof(ib_ac_match_t));
                            if (mt == NULL) {
                                return IB_EALLOC;
                            }

                            mt->pattern = outs->pattern;
                            mt->data = state->data;
                            mt->pattern_len = outs->level + 1;
                            mt->offset =
                                ac_ctx->processed - (outs->level + 1);
                            mt->relative_offset = ac_ctx->current_offset -
                                                         (outs->level + 1);

                            ib_list_enqueue(ac_ctx->match_list,
                                            (void *) mt);
                        }
                    }
                }
            }
            else {
                /* if goto() failed, look at the fail states */
                if (state != NULL && state->fail != NULL) {
                    if (state == ac_tree->root) {
                        break;
                    }
                    state = state->fail;
                }
                else {
                    state = ac_tree->root;
                }
            }
        }

        if (fgoto != NULL) {
            state = fgoto;
        }

        ac_ctx->current = state;
    }

    ac_ctx->current = state;

    /* If we have a match, return ok. Otherwise return IB_ENOENT */
    if (flag_match == 1) {
        return IB_OK;
    }

    return IB_ENOENT;
}
Пример #2
0
 /**
  * Push @a value to front of list.
  *
  * @param[in] value Value to push to back of list.
  **/
 void push_front(T value) const
 {
     Internal::throw_if_error(
         ib_list_enqueue(m_ib, Internal::value_as_void(value))
     );
 }
Пример #3
0
/**
 * Constructs fail links of branches (the failure transition function)
 *
 * @param ac_tree the ac tree matcher
 *
 * @return ib_status_t status of the operation
 */
static ib_status_t ib_ac_link_fail_states(ib_ac_t *ac_tree)
{
    ib_status_t rc;

    ib_ac_state_t *child = NULL;
    ib_ac_state_t *state = NULL;
    ib_ac_state_t *goto_state = NULL;

    ib_list_t *iter_queue = NULL;

    if (ac_tree->flags & IB_AC_FLAG_PARSER_COMPILED) {
        return IB_OK;
    }

    ac_tree->root->pattern = 0;

    rc = ib_list_create(&iter_queue, ac_tree->mp);
    if (rc != IB_OK) {
        return rc;
    }

    ac_tree->root->fail = ac_tree->root;

    /* All first-level children will fail back to root state */
    for (child = ac_tree->root->child;
         child != NULL;
         child = child->sibling)
    {
        child->fail = ac_tree->root;
        rc = ib_list_enqueue(iter_queue, (void *) child);
        if (rc != IB_OK) {
            return rc;
        }
    }

    while (ib_list_elements(iter_queue) > 0) {
        rc = ib_list_dequeue(iter_queue, (void *) &state);
        if (rc != IB_OK) {
            return rc;
        }

        state->fail = ac_tree->root;

        if (state->parent != ac_tree->root) {
            goto_state = ib_ac_child_for_code(state->parent->fail,
                                             state->letter);
            if (goto_state != NULL) {
                state->fail = goto_state;
            }
        }

        for (child = state->child;
             child != NULL;
             child = child->sibling)
        {
            rc = ib_list_enqueue(iter_queue, (void *) child);
            if (rc != IB_OK) {
                return rc;
            }
        }
    }

    /* Link common outputs of subpatterns present in the branch*/
    ib_ac_link_outputs(ac_tree, ac_tree->root);

    /* Unlink invalid fail transitions. This guarantees that there will
     * be at least one letter with transition in each fail state*/
    ib_ac_unlink_unuseful(ac_tree, ac_tree->root);

    if (ac_tree->root->child != NULL) {
        ib_ac_build_bintree(ac_tree, ac_tree->root);
    }

    ac_tree->flags |= IB_AC_FLAG_PARSER_COMPILED;

    return IB_OK;
}