static bool test_str_find_substring(const char *key, int expected_pos) { const unsigned char *text = (const unsigned char *)str_find_text; const unsigned int text_len = strlen(str_find_text); struct str_find_context *ctx; unsigned int i, j, pos, max, offset; bool ret; ctx = str_find_init(pool_datastack_create(), key); /* divide text into every possible block combination and test that it matches */ i_assert(text_len > 0); max = 1U << (text_len-1); for (i = 0; i < max; i++) { str_find_reset(ctx); pos = 0; offset = 0; ret = FALSE; for (j = 0; j < text_len; j++) { if ((i & (1 << j)) != 0) { if (str_find_more(ctx, text+pos, j-pos+1)) { ret = TRUE; break; } offset += j-pos + 1; pos = j + 1; } } if (pos != text_len && !ret) { if (str_find_more(ctx, text+pos, j-pos)) ret = TRUE; } if (expected_pos < 0) { if (ret) return FALSE; } else { if (!ret) return FALSE; pos = str_find_get_match_end_pos(ctx) + offset - strlen(key); if ((int)pos != expected_pos) return FALSE; } } return TRUE; }
static int dbox_file_find_next_magic(struct dbox_file *file, uoff_t *offset_r, bool *pre_r) { struct istream *input = file->input; struct str_find_context *pre_ctx, *post_ctx; uoff_t orig_offset, pre_offset, post_offset; const unsigned char *data; size_t size; int ret; *pre_r = FALSE; pre_ctx = str_find_init(default_pool, "\n"DBOX_MAGIC_PRE); post_ctx = str_find_init(default_pool, DBOX_MAGIC_POST); /* \n isn't part of the DBOX_MAGIC_PRE, but it always preceds it. assume that at this point we've already just read the \n. when scanning for it later we'll need to find the \n though. */ str_find_more(pre_ctx, (const unsigned char *)"\n", 1); orig_offset = input->v_offset; while ((ret = i_stream_read_data(input, &data, &size, 0)) > 0) { pre_offset = (uoff_t)-1; if (str_find_more(pre_ctx, data, size)) { pre_offset = input->v_offset + str_find_get_match_end_pos(pre_ctx) - (strlen(DBOX_MAGIC_PRE) + 1); *pre_r = TRUE; } if (str_find_more(post_ctx, data, size)) { post_offset = input->v_offset + str_find_get_match_end_pos(post_ctx) - strlen(DBOX_MAGIC_POST); if (pre_offset == (uoff_t)-1 || post_offset < pre_offset) { pre_offset = post_offset; *pre_r = FALSE; } } if (pre_offset != (uoff_t)-1) { if (*pre_r) { /* LF isn't part of the magic */ pre_offset++; } *offset_r = pre_offset; break; } i_stream_skip(input, size); } if (ret <= 0) { i_assert(ret == -1); if (input->stream_errno != 0) dbox_file_set_syscall_error(file, "read()"); else { ret = 0; *offset_r = input->v_offset; } } i_stream_seek(input, orig_offset); str_find_deinit(&pre_ctx); str_find_deinit(&post_ctx); return ret; }