/** * 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; }
/** * 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)) ); }
/** * 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; }